Python之美[从菜鸟到高手]--urllib源码分析
urllib提供了较好的封装,可以很方便的读取http,ftp,file等协议数据,本篇只关注http。urllib的底层还是使用httplib模块,相比于httplib,urllib接口更加好用,功能更加强大。支持http代理,可从环境变量中获取代理信息,支持http basic auth,可自动处理302等。但也有不足,如不支持gzip等压缩编码,不支持摘要认证,NTML认证等。
urllib快速使用
urllib的urlopen方法很好用,代理使用如下:
import urllib
opener=urllib.urlopen('http://www.baidu.com/',proxies={'http':'http://root:root2@192.168.1.101:808'})
print opener.code
注意:http://www.baidu.com/需要在域名后加"/",不然会报"IOError: ('http protocol error', 0, 'got a bad status line', None)”,且代理站点需要添加http前缀。
import urllib
def reporthook(bk,bs,total):print bk*bs,'b'
filename,message=urllib.urlretrieve("http://ww.baidu.com/",None,reporthook)
print message.getheader('Content-Length')
返回结果:
8192 b
16384 b
11394
fp = self.open(url, data)
headers = fp.info()
if "content-length" in headers:size = int(headers["Content-Length"])
看的我疑惑了,这headers到底是什么类型啊,怎么那么像字典,还能自动处理大小写?
原来这是rfc822.Message实例,定义了__contains__和__getitem__,果然源码之下,没有秘密可言。
class Message:def __contains__(self, name):"""Determine whether a message contains the named header."""return name.lower() in self.dictdef __getitem__(self, name):"""Get a specific header, as from a dictionary."""return self.dict[name.lower()]
urllib源码分析
1.总体流程
2.http basic auth(基本认证)
GET / HTTP/1.1
Host: 127.0.0.1HTTP/1.1 401 Authorization Required
WWW-Authenticate: Basic realm="my site"----------------------------------------------------------GET / HTTP/1.1
Host: 127.0.0.1
Authorization: Basic cm9vdDpyb290HTTP/1.1 200 OK
我们可以简单配置一下apache,修改httpd.conf,在需要认证的的directory下,添加AllowOverride authconfig,
<Directory "c:/wamp/www/">AllowOverride authconfigOrder Deny,AllowDeny from allAllow from 127.0.0.1
</Directory>
authname "my site"
authtype basic
authuserfile c:/wamp/www/user.txt
require valid-user
其中authname也就是提示信息,会出现在“WWW-Authenticate”头的“realm"(以前一直很奇怪,realm到底是什么?)。authuserfile最好绝对路径。
我们知道了认证方式,那么编码也就简单了。
user_passwd, realhost = splituser(realhost) #realhost类似root:root@www.baiud.com
if user_passwd:import base64auth = base64.b64encode(user_passwd).strip()else:auth = Noneh = httplib.HTTP(host)if auth: h.putheader('Authorization', 'Basic %s' % auth)
当url中没有提供用户名:密码时,但站点的确需要认证时,将返回401状态码,这时将调用http_error_401,如果出现"www-authenticate"响应头,将判断是否是basic认证。如果是将调用retry_http_basic_auth,这个函数从缓存中寻找有无该站点的用户名:密码,如果没有将调用prompt_user_passwd,提示用户输入(如果在GUI环境下需要重写该函数),并将用户名:密码缓存,如下
3.代理
GET / HTTP/1.1
Host: www.baidu.comHTTP/1.0 407 Unauthorized
Server: Proxy
Proxy-Authenticate: Basic realm="CCProxy Authorization"GET / HTTP/1.1
Host: www.baidu.com
Proxy-Authorization: Basic cm9vdDpyb290Mg==HTTP/1.1 200 OK
第一次访问百度,由于设置了代理,所以返回了407状态码,”其中Basic realm“就是网页认证对话标题。如果代理需要”用户名:密码“认证,和http基本认证一样,每次都将”用户名:密码“base64加密作为”Proxy-Authorization“。
def __init__(self, proxies=None, **x509):if proxies is None:proxies = getproxies()assert hasattr(proxies, 'has_key'), "proxies must be a mapping"self.proxies = proxies
我们看到,如果没有设置代理,将调用getproxies()函数获取本地环境变量中的代理。
def getproxies_environment():proxies = {}for name, value in os.environ.items():name = name.lower()if value and name[-6:] == '_proxy':proxies[name[:-6]] = valuereturn proxies
本地环境变量中代理一般设置如下,如在linux中.bashrc设置
export http_proxy="16.111.53.167:808"
export ftp_proxy="16.111.53.167:328"
urllib提供的有用函数
1. quote(s, safe = '/'): url编码,将保留字符编码为%20格式,主要用来编码path前面信息
fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]|")
增补:从python2.6版本才会主动编码,2.5以及低版本不会
2. unquote(s): quote的逆过程。
3. quote_plus(s, safe = ''): query字符串编码,与quote不同点就是将“空格”用“+"表示,主要用于urlencode函数中。
4. unquote_plus(s): quote_plus的逆过程。
5.urlencode(query,doseq=0) : 将2元素的序列或字典编码成查询字符串,doseq允许第二元素也可以为序列,query字符串都是用quote_plus编码。
注意:这里有必要对quote,quote_plus和urlencode做个说明
quote用于url的编码,而quote_plus用于post的data编码,所以而urlencode内部是用quote_plus实现的,所以urlencode一般只用做post data使用,get时不用。
官方文档说明:
urllib.unquote(string)
Replace %xx escapes by their single-character equivalent.
Example: unquote('/%7Econnolly/') yields '/~connolly/'.
urllib.unquote_plus(string)
Like unquote(), but also replaces plus signs by spaces, as required for unquoting HTML form values.
urllib.urlencode(query[, doseq])
Convert a mapping object or a sequence of two-element tuples to a “percent-encoded” string, suitable to pass to urlopen() above as the optional data argument. This is useful to pass a dictionary of form fields to a POST request. The resulting string is a series of key=value pairs separated by '&' characters, where both key and value are quoted using quote_plus() above. When a sequence of two-element tuples is used as the query argument, the first element of each tuple is a key and the second is a value. The value element in itself can be a sequence and in that case, if the optional parameter doseq is evaluates to True, individual key=value pairs separated by '&' are generated for each element of the value sequence for the key. The order of parameters in the encoded string will match the order of parameter tuples in the sequence. The urlparse module provides the functions parse_qs() and parse_qsl() which are used to parse query strings into Python data structures.
6 .url2pathname: 将file协议url转换为本地路径
_typeprog = None
def splittype(url):"""splittype('type:opaquestring') --> 'type', 'opaquestring'."""global _typeprogif _typeprog is None:import re_typeprog = re.compile('^([^/:]+):')match = _typeprog.match(url)if match:scheme = match.group(1)return scheme.lower(), url[len(scheme) + 1:]return None, url
Python之美[从菜鸟到高手]--urllib源码分析相关推荐
- Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)
我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等.强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Pyt ...
- python之美_Python之美[从菜鸟到高手]--生成器之全景分析
yield指令,可以暂停一个函数并返回中间结果.使用该指令的函数将保存执行环境,并且在必要时恢复. 生成器比迭代器更加强大也更加复杂,需要花点功夫好好理解贯通. 看下面一段代码: [python] d ...
- python unit test 访问开发代码_python unittest 源码分析
unittest单元测试框架总结 unittest单元测试框架既可以适用于单元测试,也能够适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否 ...
- Java之美[从菜鸟到高手演变]系列之博文阅读导航
随着博文越来越多,为博客添加一个导航很有必要!本博客将相继开通Java.CloudFoundry.Linux.Ruby等专栏,都会设立目录,希望读者朋友们能更加方便的阅读! 在阅读的过程中有任何问题, ...
- Java之美[从菜鸟到高手演变]之Exception
版权声明:本文为博主原创文章,未经博主允许不得转载. Exception这个东西,程序中必须会有的,尽管我们很不乐意看到它,可是从另一个角度考虑,有异常则说明程序有问题,有助于我们及时改正.有的时候程 ...
- Java之美[从菜鸟到高手演变]之字符串
写程序就像生活,有酸甜苦辣,关键在于过程,任何事情的过程都是美好的,是值得我们回味的!有人说,编程是一种艺术,艺术出于生活却高于生活,每一个细节都值得细细品味...程序员无非就是两件事:学习和分享!独 ...
- Java之美[从菜鸟到高手演变]之集合类【吐血推荐!讲得太好了!!!】
source: http://blog.csdn.net/zhangerqing/article/details/8122075 最近在找工作,目前还没有定下来,拿到了一个公司的offer,不过被当白 ...
- Java之美[从菜鸟到高手演变]之智力题【史上最全】
智力题,每个正式的笔试.面试都会出,而且在面大企业的时候必然会问到,笔者曾在很多面试中,都被问到过,不过答得都不是很好,因为时间很短,加上我们有时候过于紧张,所以做出这类问题,还是有一定的难度,从这篇 ...
- Java之美[从菜鸟到高手演变]之智力题【史上最全】 .
智力题,每个正式的笔试.面试都会出,而且在面大企业的时候必然会问到,笔者曾在很多面试中,都被问到过,不过答得都不是很好,因为时间很短,加上我们有时候过于紧张,所以做出这类问题,还是有一定的难度,从这篇 ...
最新文章
- php之static静态变量详解
- MySQL 报错MySQL server syntax to use near 'OPTION SQL_SELECT_LIMIT=DEFAULT'
- Binder 驱动详解(下)
- js Date对象总结
- php 开源 采集,迅睿CMS 火车头内容采集
- python functools.reduce_Python之functools.reduce使用
- VC 下加载 JPG / JPEG / GIF / PNG 图片最简单的方法
- WAMP安装curl扩展并发起https请求
- orangepi香橙派安装VNC Viewer远程桌面
- python计算正弦值_Python科学计算(二)——正弦信号的时域波形与频谱图
- 采用Zigbee和Raspberry Pi的太阳能/燃气热水器自动控制系统
- p系列服务器产品介绍,常用p系列服务器RS6000服务器产品号码对照表.doc
- sql 行政区划关联查询优化_民政部:四季度继续开展优化行政区划设置研究
- 本地系统盘放到服务器上,怎么把本地盘挂到云服务器
- 私有云搭建使用docker搭建
- word中方框中打钩
- filebeat报错error pipeline/output.go:100 failed to connect to backoff(async(tcp://xx.xx.xx.xx:))...
- 如何寻求知识产权的刑事救济
- coreldraw插件编写
- 师范类专业计算机和数学哪个好,师范类数学与应用数学专业考研考哪个方向好?是本专......