IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

urllib2源码解读二(简单的urlopen)

the5fire的技术博客 2012-12-06 13:53:04 累计浏览 2,686 次
本机暂存

对上面的几个对象有个基本概念之后,再来深究下代码,从一个最普通的urllib2.urlopen()开始,先来熟悉下第一个重点对象:build_opener这个函数。

大家最为熟悉的一段代码:

res = urllib2.urlopen('http://python.org')

这端代码的作用就是打开http://python.org这个网站,返回一个response对象。

下面咱们来深入到这个urlopen函数中,来看下代码:

def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):

   """

   对外的访问函数

   """


   global _opener

   if _opener is None:
       _opener = build_opener()
   return _opener.open(url, data, timeout)

在程序第一次执行urlopen操作的时候,其实就是构建了一个全局的_opener对象,然后用这个_opener对象来处理url以及data。这样做的好处就是如果你在程序中要多次调用urlopen,就不会频繁构建opener对象了。当然这个opener也不是一次加载就再也不可变了,urllib2提供了install_opener这个方法,你可以在客户端调用build_opener然后用前面的那个install_opener来加载。

这段代码很简单,起作用就是构建一个opener对象,所以咱来看下它是如何构建这个_opener对象的。

不过在此之前需要先了解下我们一直在说的opener是什么?

这个_opener其实就是OpenerDirector的一个实例,OpenerDirector上篇已经大概说了,目前我们需要了解的就是在这个对象中定义了几个字典属性,这些字典就是用来存放对应的handler的。

      self.handlers = []  

       # manage the individual handlers

       self.handle_open = {}

       self.handle_error = {}

       self.process_response = {}

       self.process_request = {}

最主要的三个字典是process_request、handle_open、process_response,分别存放处理request、打开request、处理response的handler。

所谓的handler是什么呢?顾名思义,就是处理器,目前只需要知道有一群handler,分别用来处理不同的对象,然后对应的处理结果。

有了这样的认识我们先来看下build_opener()函数是如何来构建这个OpenerDirector对象的。

def build_opener(*handlers):

   import types

   def isclass(obj):

       return isinstance(obj, (types.ClassType, type))

   opener = OpenerDirector()

   #这里定义了一系列的handler类

   default_classes = [ProxyHandler, UnknownHandler, HTTPHandler,

                      HTTPDefaultErrorHandler, HTTPRedirectHandler,

                      FTPHandler, FileHandler, HTTPErrorProcessor]

   if hasattr(httplib, 'HTTPS'):#判断是否支持https

       default_classes.append(HTTPSHandler)

   skip = set()

   for klass in default_classes:

       #处理用户函数参数handler中是否有相同的类在默认类中。

       for check in handlers:

           if isclass(check):

               if issubclass(check, klass):

                   skip.add(klass)

           elif isinstance(check, klass):

               skip.add(klass)

   for klass in skip:

       default_classes.remove(klass)

   #这一步,将默认的类实例化之后加入opener中

   for klass in default_classes:

       opener.add_handler(klass())

   #然后把参数中的handler类实例化,加到OpenerDirector中。

   for h in handlers:

       if isclass(h):

           h = h()

       opener.add_handler(h)

   return opener

这个函数的整个过程其实相对简单,只是把系统默认的handler和用户传入的自定义handler参数进行了对比弃重。最后把所有的handler都实例化通过opener.add_handler方法添加给OpenerDirector。最后返回构建好的OpenerDirector实例。

关于这个build_opener就先说到这里,下篇再来说OpenerDirector的add_handler的具体流程。

另外,最近一直在思考一个问题,如何把这些(我学到的东西,比如urllib2)东西能够更好的,更清晰易懂的让读者明白。自己理解urllib2的源码不难,难的是以何种方式或者说何种组织结构来写能让人更容易懂。不知道各位有没有什么好的建议或者好的书籍推荐。

目前我自己的想法就是尽量让每篇文章涉及的未知知识点少,每篇文章也尽量内容单一,这样读起来会不会容易些?

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 用Hyer来进行网站的抓取 (累计阅读 158,253)
  2. 配置Nginx+uwsgi更方便地部署python应用 (累计阅读 107,167)
  3. 程序员技术练级攻略 (累计阅读 35,472)
  4. python实现自动登录discuz论坛 (累计阅读 32,834)
  5. python编程细节──遍历dict的两种方法比较 (累计阅读 20,371)
  6. 每个程序员都应该学习使用Python或Ruby (累计阅读 17,919)
  7. Chrome和goagent的配置方法,你懂的 (累计阅读 16,843)
  8. libcurl的使用总结(二) (累计阅读 15,083)
  9. 30分钟3300%性能提升――python+memcached网页优化小记 (累计阅读 13,742)
  10. 使用python爬虫抓站的一些技巧总结:进阶篇 (累计阅读 13,302)