httplib2,一个第三方的开源库,它比http.client更完整的实现了http协议,同时比urllib.request提供了更好的抽象。
#coding=utf8 import httplib2 #获取HTTP对象 h =httplib2.Http() #发出同步请求,并获取内容 resp, content = h.request("http://www.weirdbird.net/") print resp print content
一旦你有了Http对象, 获取数据非常简单,以你要的数据的地址作为参数调用request()方法就可以了。这会对该url执行一个http GET请求
request() 方法返回两个值。第一个是一个httplib2.Response对象,其中包含了服务器返回的所有http头。比如, status为200 表示请求成功。
content 变量包含了http服务器返回的实际数据。数据以bytes对象返回,不是字符串。 如果你需要一个字符串,你需要确定字符编码并自己进行转换
#coding=utf8 import httplib2 #获取HTTP对象 h =httplib2.Http('.cache') #发出同步请求,并获取内容 resp, content = h.request("http://www.weirdbird.net/sitemap.xml") print resp # print content print("......"*3) httplib2.debuglevel = 1 h1 = httplib2.Http('.cache') resp,content = h1.request('http://www.weirdbird.net/sitemap.xml') print(resp) print('debug',resp.fromcache)
此时debug 是true ,说明 是从 本地的.cache 进行读取,没经过原网站,若我不读缓存怎么办? head 上加:
resp,content = h1.request('http://www.weirdbird.net/sitemap.xml',headers={'cache-control':'no-cache' })
httplib2 允许你添加任意的http头部到发出的请求里。为了跳过所有缓存(不仅仅是你本地的磁盘缓存,也包括任何处于你和远程服务器之间的缓存代理服务器), 在headers字典里面加入no-cache头就可以了。
故名思议, 这个是当服务器的资源改变了,若本地的缓存还有,进行更新的
http 为这种目的定义了Last-Modified和Etag头。 这些头被称为验证器(validators)。如果本地缓存已经不是新鲜的,客户端可以在下一个请求的时候发送验证器来检查数据实际上有没有改变。如果数据没有改变,服务器返回304状态码,但不返回数据。 所以虽然还会在网络上有一个来回,但是你最终可以少下载一点字节。
这可能会让人有些困惑。这里实际上有两个 状态码 — 304 (服务器这次返回的, 导致httplib2查看它的缓存), 和 200 (服务器上次返回的, 并和页面数据一起保存在httplib2的缓存里)。response.status返回缓存里的那个
每一次httplib2 发送请求,它包含了Accept-Encoding头来告诉服务器它能够处理deflate 或者 gzip压缩。
当request()方法返回的时候,httplib2就已经解压缩了响应的体(body)并将其放在 content变量里。如果你想知道响应是否压缩过, 你可以检查response['-content-encoding']; 否则,不用担心了.
302临时重定向
调用request()方法返回的response是最终url的响应 ttplib2 会将最终的 url以 content-location加入到 response字典中。这不是服务器返回的头,而是httplib2 特点的特征
response.previous属性持有前一个响应对象的引用,httplib2跟随那个响应获得了当前的响应对象。
response 和 response.previous 都是 httplib2.Response 对象。
这意味着你可以通过response.previous.previous 来反向跟踪重定向链到更前的请求。(场景: 一个url 重定向到第二个url,它又重定向到第三个url。这可能发生!) 在这例子里,我们已经到达了重定向链的开头,所有这个属性是None.
我们再次请求同一个url 发现变回了第一次 那样的返回
301 永久重定向
一旦 httplib2跟随了一个永久重定向, 所有后续的对这个url的请求会被透明的重写到目标url 而不会接触网络来访问原始的url。 记住, 调试还开着, 但没有任何网络活动的输出。
POST 请求同GET 请求不同,因为是要提交到服务器的, 这个api方法必须的参数是status, 并且它应该是url编码过的。 这是一种很简单的序列化格式,将一组键值对(比如字典)转化为一个字符串。
POST 构造数据发送
from urllib.parse import urlencode import httplib2 httplib2.debuglevel = 1 h = httplib2.Http('.cache') data = {'status': 'Test update from Python 3'} h.add_credentials('diveintomark', 'MY_SECRET_PASSWORD', 'identi.ca') resp, content = h.request('https://identi.ca/api/statuses/update.xml', 'POST', urlencode(data), headers={'Content-Type': 'application/x-www-form-urlencoded'})
add_credentials()方法的第三个参数是该证书有效的域名。你应该总是指定这个参数! 如果你省略了这个参数,并且之后重用这个httplib2.Http对象访问另一个需要认证的站点,可能会导致httplib2将一个站点的用户名密码泄漏给其他站点。
记住, httplib2返回的数据总是字节串(bytes), 不是字符串。为了将其转化为字符串,你需要用合适的字符编码进行解码 比如:
print(content.decode('utf-8'))
from xml.etree import ElementTree as etree tree = etree.fromstring(content) status_id = tree.findtext('id') url = 'https://identi.ca/api/statuses/destroy/{0}.xml'.format(status_id) resp, deleted_content = h.request(url, 'DELETE')
httplib2源码
一些httplib2 的demo