urllib源码阅读

urllib底层是对httplib的封装,使之更易用
一般用法:

import urllib
res = urllib.urlopen('http://www.baidu.com')
resp.read()

贴下urlopen的代码

def urlopen(url, data=None, proxies=None, context=None):
    ......
    global _urlopener
    if proxies is not None or context is not None:
        opener = FancyURLopener(proxies=proxies, context=context)
    elif not _urlopener:
        opener = FancyURLopener()
        _urlopener = opener
    else:
        opener = _urlopener
    if data is None:
        return opener.open(url)
    else:
        return opener.open(url, data)

可以看出urlopen接收四个参数,url(地址)、data(参数)、proxies(代理,非必填)、context(代理用,非必填)。从代码中可以看出,urlopen实际上都是在调用FancyURLopener的实例,返回该实例中open方法。而FancyURLopener又是URLopener的子类。
URLopener包含的一些属性和方法

__tempfiles 是一个list,用来存储从网络爬取到本地的本地文件
addheader 添加http头
open 用来分发处理各式请求,调用splittype函数对请求地址进行处理,得到url的格式,再调用相应的实例方法

if not hasattr(self, name):   # name是由'open_' 拼上协议名
    if proxy:
        return self.open_unknown_proxy(proxy, fullurl, data)
    else:
        return self.open_unknown(fullurl, data)
try:
    if data is None:
        return getattr(self, name)(url)
    else:
        return getattr(self, name)(url, data)
except socket.error, msg:
    raise IOError, ('socket error', msg), sys.exc_info()[2]

形如上述代码,比如http请求,首先拼出open_http名称,然后通过getattr(self, name)(url)进行调用。
open函数在此处好比一个中转站,对各式请求处理判断后,找到目标函数,进行更准确的操作。
open_http、open_https、open_file、open_local_file、open_ftp、open_data 执行更为精细的请求操作,接收的参数包括url(必填)、data(非必填)
http_error http请求错误,如果open在处理http请求过程中出现错误,将调用该方法
http_error_default http 请求默认错误

FancyURLopener 细分了http请求的返回状态

请求返回数据基本上是在操作addbase或者addbase的子类,它实现了一些操作文件的方法,比如read、readlines等等

源码中有很多的小函数,用来处理url或者参数,注释中写明了这些小函数的作用,如下:

# 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')
posted @ 2017-12-09 15:37  微波~  阅读(360)  评论(0)    收藏  举报