urllib 源码小剖

urllib 是 python 内置的网络爬虫模块,如果熟悉 python 一定能很快上手使用 urllib。

写这篇文章的目的是因为用到了它,但因为用的次数较多,又或者是具体的需求,有必要深入去理解内部的工作方式。

urllib 最简单的使用,我也从下面的语句中开始:

1
2
3
4
import urllib
params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params)
print f.read()

urllib 是模块,urlopen 是模块中的一个方法,它应该属于最高层的封装了,对于传入的任意 url 都能够处理,不管是 http还是https,还是 ftp 还是 file(本地文件).
它返回一个文件对象的包装类,里面除了文件对象,还有 HTTP response 的头和状态码,url 等;根据网络环境或者服务响应速度,会延迟一些时间。

注意,在这个时候,网络上的资源已经读取到了本地,被放在一个文件中。

接下来,f.read 从文件对象中读取数据。

下面是 urlopen 的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def urlopen(url, data=None, proxies=None):
    ......
    global _urlopener
    if proxies is not None:
        opener = FancyURLopener(proxies=proxies)
    elif not _urlopener:
        opener = FancyURLopener()
        _urlopener = opener
    else:
        opener = _urlopener
    if data is None:
        return opener.open(url)
    else:
        return opener.open(url, data)

其中,我们可以得到的讯息是,它创建了类 FancyURLopener 对象,并调用了它的 open方法,而类 FancyURLopener 就是 urllib 的核心。

FancyURLopener 其实是 URLopener 的子类,所以从 URLopener 开始说起。

__tempfiles 是一个 list,用来存储从网络爬取到本地的本地文件名,你可以单独调用这个方法
addheader 添加 HTTP 头,得到了一个 URLopener 对象,就可以使用此函数添加额外的 HTTP 头

open 上面已经提到的,它相当于一个工程老板,会根据不同的 url 来为不同的部门派发不同任务,比如,提供的是 http://baidu.com 就会调用 open_http
open_unknown 无法解析的 url就会调用它,抛出异常
retrieve 爬取网络资源,存储在本地文件,返回一个本地文件的文件名和 HTTP 的response 头
open_http 上面提到过,很综合的处理函数,可以提供 HTTP 基本访问认证,proxy 认证等功能,调用 httplib库的函数。在得到 HTTP response后,会根据 HTTP status 状态码返回爬取的结果或者调用 error 处理函数 http_error

http_error 它其实也是个老板,会根据不同的状态码,为不同的部门分发不同的任务,比如,302 状态码就会调用 http_error_302 方法,302 是资源被临时迁移了,所以会发起再次的请求。
http_error_default 抛出异常,当懒得理那些毛毛小小的错误,就会使用这样的函数

open_https 提供 https 的爬取,和 open_http 差不多
open_file 爬取 ftp 或者直接读取本地文件
open_local_file open_file 当需要直接读取本地文件时候会调用此函数
open_ftp open_file 当 ftp 资源时候会调用此函数
open_data 好似官方没怎么介绍,应该可以忽略它

FancyURLopener 是 urlopener 的子类,主要提供了更详细的错误处理
http_error_302 302 状态码的处理
redirect_internal 302 里边调用这个

http_error_301 直接调用302
http_error_303 直接调用302
http_error_307 当是 POST 的时候,调用直接调用 http_error_default;其他调用 http_error_default

http_error_401 是认证处理
http_error_407 是认证处理,但需要 proxy 代理
retry_proxy_http_basic_auth 代理重新认证 401 的时候会用到
retry_proxy_https_basic_auth 同上
retry_http_basic_auth 访问认证
retry_https_basic_auth 同上
prompt_user_passwd 认证的时候需要账号密码,控制台输入

关于 HTTP 协议的基本认证,推荐阅读:HTTP://www.cnblogs.com/TankXiao/archive/2012/09/26/2695955.html 简单明了

从上面可以看出,无论是 urlopener 还是 FancyURLopener 都没有涉及具体的 ftp 操作,因为在 urllib 中有为 ftp 提供封装:class ftpwrapper 在 open_ftp 中会直接创建 ftpwrapper 对象,然后执行其内部操作。
具体不叙述了。

class addbase 主要包装对文件对象的操作 read close 等
class addinfo addbase 的子类,添加了返回 HTTP response 头方法
class addinfourl addinfo 的子类,添加返回 url 方法

print f.read() 这一句调用其实就是 文件对象的 read,但它是 addinfourl 对象
接下来就是一些实用的工具函数了,主要处理各式各样的 url,譬如提取url里面的 host,port等。源码里有各种实用方法的效果图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Utilities to parse URLs (most of these return None for missing parts):
# unwrap('<URL:type://host/path>') --> 'type://host/path'
# splittype('type:opaquestring') --> 'type', 'opaquestring'
# splithost('//host[:port]/path') --> 'host[:port]', '/path'
# splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'
# splitpasswd('user:passwd') -> 'user', 'passwd'
# splitport('host:port') --> 'host', 'port'
# splitquery('/path?query') --> '/path', 'query'
# splittag('/path#tag') --> '/path', 'tag'
# splitattr('/path;attr1=value1;attr2=value2;...') ->
# '/path', ['attr1=value1', 'attr2=value2', ...]
# splitvalue('attr=value') --> 'attr', 'value'
# unquote('abc%20def') -> 'abc def'
# quote('abc def') -> 'abc%20def')

最后总结,urlopen 是最高层的封装,简单的一句话就可以爬取 WWW 很简单;其内部是通由 FancyURLopener 实现,FancyURLopener 是 URLopener 的父类:URLopener 实现了爬取方法,但未定义对应具体状态码的 error handlers,这些由 FancyURLopener 定义。

捣乱  2013-08-25

http://daoluan.net

 
 
分类: 网络

urllib 源码小剖的更多相关文章

  1. urllib2 源码小剖

    urllib2 源码小剖 2013-08-25 23:38 by 捣乱小子, 272 阅读, 0 评论, 收藏, 编辑 两篇小剖已经完成: urllib 源码小剖 urllib2 源码小剖 urlli ...

  2. Django 源码小剖: 响应数据 response 的返回

    响应数据的返回 在 WSGIHandler.__call__(self, environ, start_response) 方法调用了 WSGIHandler.get_response() 方法, 由 ...

  3. Django 源码小剖: 初探 WSGI

    Django 源码小剖: 初探 WSGI python 作为一种脚本语言, 已经逐渐大量用于 web 后台开发中, 而基于 python 的 web 应用程序框架也越来越多, Bottle, Djan ...

  4. Django 源码小剖: 初探中间件(middleware)

    因为考虑到文章的长度, 所以 BaseHandler 的展开被推迟了. 在 BaseHandler 中隐藏着中间件的信息, 较常见的 SessionMiddleware 就已经默认安装.  BaseH ...

  5. Django 源码小剖: Django 对象关系映射(ORM)

    引 从前面已经知道, 一个 request 的到来和一个对应 response 的返回的流程, 数据处理和数据库离不开. 我们也经常在 views.py 的函数定义中与数据库打交道. django O ...

  6. Django 源码小剖: Django 中的 WSGI

    Django 其内部已经自带了一个方便本地测试的小服务器, 所以在刚开始学习 Django 的时候并不需搭建 apache 或者 nginx 服务器. Django 自带的服务器基于 python w ...

  7. Django 源码小剖: Django ORM 查询管理器

    ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从 ...

  8. Django 源码小剖: 更高效的 URL 调度器(URL dispatcher)

    效率问题 django 内部的 url 调度机制说白了就是给一张有关匹配信息的表, 这张表中有着 url -> action 的映射, 当请求到来的时候, 一个一个(遍历)去匹配. 中, 则调用 ...

  9. Django 源码小剖: URL 调度器(URL dispatcher)

    在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 URL. 这是 django url 匹配处理机制的 ...

随机推荐

  1. UVA 10139 Factovisors(数论)

    Factovisors The factorial function, n! is defined thus for n a non-negative integer: 0! = 1 n! = n * ...

  2. Unity3D音频播放器 动态装载组件

    大多数在线Unity有关如何只教程Unity在播放音乐.之后如何通过拖动它们无法继续添加音频文件 但有时在游戏中的对象要玩几个声音.这时候我们就需要使用代码控制,拖动推教程AudioClip颂值的方法 ...

  3. 【Espruino】NO.15 nRF24L01+无线收发器

    http://blog.csdn.net/qwert1213131/article/details/35853747 本文属于个人理解,能力有限,纰漏在所难免,还望指正! [小鱼有点电] [Espru ...

  4. [CLR via C#]5.3 值类型的装箱和拆箱

    原文:[CLR via C#]5.3 值类型的装箱和拆箱 在CLR中为了将一个值类型转换成一个引用类型,要使用一个名为装箱的机制. 下面总结了对值类型的一个实例进行装箱操作时内部发生的事: 1)在托管 ...

  5. Excel 删除所有错误公式

    当前工作表的话可以F5-定位-公式-错误值 来选中所有含错误值的单元格,然后按delete删除. 多表的话没办法了,因为不能跨工作表多重选中,只能一页页的删,或者用vba编个宏来解决

  6. javascritpt 原型链

    // 基类 var BaseCalculator = function(){ this.decimalDigits = 2; }; // public BaseCalculator.prototype ...

  7. MVC应用程序使用Web Services(asmx)

    原文:MVC应用程序使用Web Services(asmx) 这次,我们练习MVC应用程序中,应用web service.先在MVC应用程序中创建一个目录Services,将用来存储Service.a ...

  8. IS2009制作Oracle 静默安装包(二) 感谢空白先生特许授权

    原文:IS2009制作Oracle 静默安装包(二) 感谢空白先生特许授权 上一篇: IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权本文经原作者特许授权于海洋女神发布,转载请务必注 ...

  9. mysql utf8mb4与emoji表情

    一 什么是Emoji emoji就是表情符号:词义来自日语(えもじ,e-moji,moji在日语中的含义是字符) 表情符号现已普遍应用于手机短信和网络聊天软件. emoji表情符号,在外国的手机短信里 ...

  10. YII相关资料(干货)

    Sites 网站 yiifeed:Yii 最新动态都在这里 yiigist:Yii 专用的 Packages my-yii:Yii 学习资料和新闻 Docs 文档 Yii Framework 2.0 ...