urllib 源码小剖
urllib 源码小剖
urllib 是 python 内置的网络爬虫模块,如果熟悉 python 一定能很快上手使用 urllib。
写这篇文章的目的是因为用到了它,但因为用的次数较多,又或者是具体的需求,有必要深入去理解内部的工作方式。
urllib 最简单的使用,我也从下面的语句中开始:
|
1
2
3
4
|
import urllibparams = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})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
urllib 源码小剖的更多相关文章
- urllib2 源码小剖
urllib2 源码小剖 2013-08-25 23:38 by 捣乱小子, 272 阅读, 0 评论, 收藏, 编辑 两篇小剖已经完成: urllib 源码小剖 urllib2 源码小剖 urlli ...
- Django 源码小剖: 响应数据 response 的返回
响应数据的返回 在 WSGIHandler.__call__(self, environ, start_response) 方法调用了 WSGIHandler.get_response() 方法, 由 ...
- Django 源码小剖: 初探 WSGI
Django 源码小剖: 初探 WSGI python 作为一种脚本语言, 已经逐渐大量用于 web 后台开发中, 而基于 python 的 web 应用程序框架也越来越多, Bottle, Djan ...
- Django 源码小剖: 初探中间件(middleware)
因为考虑到文章的长度, 所以 BaseHandler 的展开被推迟了. 在 BaseHandler 中隐藏着中间件的信息, 较常见的 SessionMiddleware 就已经默认安装. BaseH ...
- Django 源码小剖: Django 对象关系映射(ORM)
引 从前面已经知道, 一个 request 的到来和一个对应 response 的返回的流程, 数据处理和数据库离不开. 我们也经常在 views.py 的函数定义中与数据库打交道. django O ...
- Django 源码小剖: Django 中的 WSGI
Django 其内部已经自带了一个方便本地测试的小服务器, 所以在刚开始学习 Django 的时候并不需搭建 apache 或者 nginx 服务器. Django 自带的服务器基于 python w ...
- Django 源码小剖: Django ORM 查询管理器
ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从 ...
- Django 源码小剖: 更高效的 URL 调度器(URL dispatcher)
效率问题 django 内部的 url 调度机制说白了就是给一张有关匹配信息的表, 这张表中有着 url -> action 的映射, 当请求到来的时候, 一个一个(遍历)去匹配. 中, 则调用 ...
- Django 源码小剖: URL 调度器(URL dispatcher)
在刚开始接触 django 的时候, 我们尝试着从各种入门文档中创建一个自己的 django 项目, 需要在 mysite.urls.py 中配置 URL. 这是 django url 匹配处理机制的 ...
随机推荐
- linux 内核睡眠与唤醒
休眠(被阻塞)的进程处于一个特殊的不可执行状态.进程休眠由多种原因,但肯定都是为了等待一些事件.事件可能是一 段时间从文件I/O读取更多数据,或者是某个硬件事件.一个进程还由可能在尝试获取一个已被占用 ...
- 常用批处理命令总结3之Find和FindStr
原文:常用批处理命令总结3之Find和FindStr find 作用:从文件中收索字符串 格式:find 参数 "字符串" 路径\文件名 参数: /V 显示所有未包含指定字符串的行 ...
- SSAS系列——【04】多维数据(物理体系结构)
原文:SSAS系列——[04]多维数据(物理体系结构) 1.本地多维数据集 本地多维数据集和本地挖掘模型允许在客户端工作站与网络的连接断开时对该工作站进行分析.在与本地多维数据集进行交互时,ADMOD ...
- C#中如何获取系统环境变量
原文:C#中如何获取系统环境变量 C#中获取系统环境变量需要用到Environment Class.其中提供了有关当前环境和平台的信息以及操作它们的方法.该类不能被继承. 以下代码得到%systemd ...
- SQL语句分享[不定期更新]
查询临时表 if object_id('')>0 查询表中的数据 select 'insert into ta1(col1,col2,col3) values('''+ltrim(列1)+''' ...
- C# 调用Webservice并传递序列化对象
原文:C# 调用Webservice并传递序列化对象 C#动态调用WebService注意要点 1.动态调用的url后面注意一定要加上?WSDL 例如:string _url = "ht ...
- java基础知识汇总
1. 类的访问控制权限共有两种:public和默认.默认级别的类只能被同一个包中的类看到,包外不可见. 2. 类成员的访问权限共有四种:public,protected,private ...
- UC编程:通过fwrite()和write()比较标准库函数和系统调用的速度
fwrte是C标准库中提供的函数,是对write函数的扩展与封装,write则是Unix系统提供的函数.按照常理来讲,系统调用肯定比使用库快的多,但是事实正好相反 Why?原因就在于缓冲的问题,fwi ...
- __declspec(novtable)keyword
__declspec (novtable )keyword,表示这个类不生成虚函数表.可是继承类不影响(无论基类是否使用了keyword). 不使用此keyword.类在生成对象时构造函数和析构函数多 ...
- Ubuntu下编译程序是出现pthread_create未定义错误
gcc -c node_list.c -o node_list.o gcc -lpthread sim.o cli.o list.o node_list.o -o sim.exe sim.o: In ...