the5fire的技术博客

关注python、vim、linux、web开发和互联网--life is short, we need python.


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

作者:the5fire | 标签:   | 发布:2012-11-28 10:54 p.m. | 阅读量: 6257, 6203
对上面的几个对象有个基本概念之后,再来深究下代码,从一个最普通的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的源码不难,难的是以何种方式或者说何种组织结构来写能让人更容易懂。不知道各位有没有什么好的建议或者好的书籍推荐。



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

扫码关注,或者搜索微信公众号:码农悟凡


其他分类: