频道栏目
首页 > 程序开发 > 软件开发 > 其他 > 正文
49.Python使用requests包进行HTTP交互方法详解
2016-10-01 09:00:48      个评论    来源:Mars Loo的博客  
收藏   我要投稿

简介

Python的HTTP包有urllib、urllib2、httplib等,但是都需要了解较多的HTTP原理才能编码,借助requests包可以在较高的抽象层次上完成HTTP交互过程的开发。安装requests使用pip install requests命令,requests包内嵌了urllib3,自动支持HTTP长连接、连接池等功能。

使用方法

requests支持HTTP的HEAD、GET、POST、PUT、OPTIONS、DELETE、PATCH等请求:

r = requests.options('http://localhost:5000/')
print "Options:", r.headers
r = requests.post('http://localhost:5000/', data={'name': 'mars'})
print "Post:", r.content
r = requests.put('http://localhost:5000/', data={'name': 'loo'})
print "Put:", r.content
r = requests.get('http://localhost:5000/')
print "Get:", r.content
r = requests.delete('http://localhost:5000/')
print "Delete:", r.content
r = requests.get('http://localhost:5000/')
print "Get:", r.content

变量r是一个requests.models.Response类型的响应对象,通过r可以得到HTTP响应的所有信息。

传递QUERY参数

在URI的query部分传递参数,可以直接按照标准放在URL字符串中(允许为同一个key赋值多个value):

r = requests.get('http://localhost:5000/?xx=bb&xx=cc')

也可以放在请求的params参数中:

params = {
    'xx': ['bb', 'cc'],
    'yy': None,
}
r = requests.get('http://localhost:5000/', params=params)
print "Request URL:", r.url

使用字典做参数时,对同一个key的多个value要放在列表中,如果某个key对应的值为None,则其不会放在query中。

定制请求头

为HTTP请求报文的头部添加内容,可以请求时为headers参数赋值:

r = requests.get('http://localhost:5000/', headers={"mars": "loo"})

填写cookie

cookie可以以字典的形式赋值给cookies参数:

cookies = {
    "name": "mars"
}

r = requests.post('http://localhost:5000/', cookies=cookies)

通过RequestsCookieJar对象可以设置cookie的域、path等信息:

jar = requests.cookies.RequestsCookieJar()
jar.set('username', 'mars', domain='httpbin.org', path='/cookies')
jar.set('password', 'loo', domain='httpbin.org', path='/else')
r = requests.get('http://httpbin.org/cookies', cookies=jar)
print r.text

如果是在localhost做实验,domain参数需要赋值为空字符串''。

http://httpbin.org/cookies提供的服务是:如果请求包含cookie的话,会在响应体中回应cookie内容,所以上述代码返回:

import json

d = {
    "mars": "loo"
}
r = requests.post('http://localhost:5000/', data = json.dumps(d),
                  headers={"content-type": "application/json"})

如果需要上传文件,直接将文件以'rb'模式打开放入字典(必须使用'rb'模式,requests才能自动推算出正确的content-length),然后传入files参数,请求类型会自动转换为multipart/form-data:

files = {
    'image': open('sample.jpg', 'rb'),
}

r = requests.post('http://localhost:5000/', files=files)

需要上传的文件大小超过内存时,可以将文件的读取放在上下文管理器中,比如:

with open('verybig.zip', 'rb') as f:
    requests.post('http://localhost:5000/', data=f)

处理响应对象

从为QUERY传递参数的例子中可以看到,使用响应对象的url属性可以访问请求的URL。status_code属性可以获取响应状态码。raise_for_status方法,当状态码为4XX或5XX时,抛出对应的客户端或服务端异常,如果是2XX或3XX错误,返回None。比如:

r = requests.get('http://localhost:5000/')
print r.raise_for_status()

输出可能是None,或者是:

from PIL import Image
from io import BytesIO

r = requests.post('http://localhost:5000/picture')
i = Image.open(BytesIO(r.content))
i.save('sample.jpg', 'jpeg')

如果响应内容的大小超过了机器内存,需要分段读取响应内容,可以在请求时使用stream=True然后调用响应对象的iter_content方法:

r = requests.post('http://localhost:5000/', stream=True)
with open('download.zip', 'wb') as f:
    for chunk in r.iter_content(chunk_size=10*1024*1024):
        if chunk:
            f.write(chunk)

针对application/json格式的响应内容,requests内置了json方法将结果转换为字典后返回:

r = requests.post('http://localhost:5000/', data={'name': 'mars'})
print "JSON:", r.json()

如果响应内容不能转换为字典,抛出异常:ValueError: No JSON object could be decoded。

通过headers属性可以访问响应的头部。

重定向与访问历史

如果请求过程发生了重定向,requests默认返回最后一个成功的响应,如果要获取中间重定向过程的响应,可以访问history属性(按照访问先后顺序的响应对象列表),比如:

r = requests.get("http://localhost:5000")
print r.history
for re in r.history:
    print re.status_code, re.headers

上述代码输出为:

r = requests.get("http://localhost:5000", allow_redirects=False)
print r.status_code, r.headers
for re in r.history:
    print re.status_code, re.headers

上述代码输出为:

s = requests.Session()
r = s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
print "1 - Headers:", r.headers
print "1 - Content:", r.content
r = s.get('http://httpbin.org/cookies')
print "2 - Text:", r.text
print "2 - Headers:", r.request.headers

上述代码输出为:

s = requests.Session()
s.headers.update({'1': '2'})
r = s.get('http://localhost:5000/headers', headers={'3': '4', '1': 'mars'})

服务器收到的header中'3'->'4','1'->'mars'。但是对于这种在调用时新增的方法,不会在请求间保持,比如:

s = requests.Session()

r = s.get('http://httpbin.org/cookies', cookies={'mars': 'loo'})
print(r.text)

r = s.get('http://httpbin.org/cookies')
print(r.text)

代码输出为:

with requests.Session() as s:
    r = s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')

根据响应获取请求

使用响应对象的request属性可以访问响应对应的请求对象,比如:

r = requests.get("http://localhost:5000", headers={"Perm": "Authroized"})
print "Request headers:", r.request.headers

上述代码输出可能为:

Request headers: {'Perm': 'Authroized', 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.11.1'}

其实通过响应对象的request属性得到的是一个PreparedRequest对象, 可以修改其某些属性后通过Session对象的send方法重发修改后的请求:

from requests import Session

r = requests.get('http://www.baidu.com')
print r.status_code, r.content

s = Session()
r2 = s.send(r.request)
print r2.status_code, r2.content

也可以先构造Request对象,然后调用其prepare方法返回一个PreparedRequest对象,再将该对象传给Session对象的send方法:

s = requests.Session()
s.cookies.update({'mars': 'loo'})

req = requests.Request('GET', 'http://httpbin.org/cookies')
prepared = req.prepare()

r = s.send(prepared)
print r.text

上述代码的输出为:

s = requests.Session()
s.cookies.update({'mars': 'loo'})

req = requests.Request('GET', 'http://httpbin.org/cookies')
prepared = s.prepare_request(req)

r = s.send(prepared)
print r.text

上述代码的输出为:

r = requests.get('https://xxx.com', verify=False)

依赖requests版本默认的CA的话,只有更新requests包的时候才会更新受信CA。新版本的requests会尝试使用certifi(如果使用了certifi的话,建议经常升级certifi)。

如果服务端的SSL/TLS版本与requests默认的不一致,可以借助HTTPAdapter对象更改Session对象使用的协议版本:

import requests
from requests.auth import HTTPBasicAuth

r = requests.get('http://localhost:5000/', auth=HTTPBasicAuth('mars', 'loo'))
print r.status_code, r.content

摘要认证

from requests.auth import HTTPDigestAuth

r = requests.get('http://localhost:5000/', auth=HTTPDigestAuth('mars', 'loo'))
print "1 - Response Header:", r.headers
print "1 - Request Header:", r.request.headers

上述代码的输出样例为:

1 - Response Header: {'Date': 'Thu, 29 Sep 2016 15:05:08 GMT', 'Content-Length': '12', 'Content-Type': 'text/html; charset=utf-8', 'Server': 'Werkzeug/0.11.10 Python/2.7.10'}
1 - Request Header: {'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.11.1', 'Connection': 'keep-alive', 'Cookie': 'session=.eJyrVkosLcmIz8vPS05VsqpWUkhSslKKrHI18HdJr_B396z0c_fK8atyNAXSWb7hrgZRWckVfu6BQDm37MiQUFulWh2IEfkFiYWlSGaEeBr7hkeaRlbl5PplBWX7GXka-Rn5Gvrm-gLNCMr0dckGyrsaRob4As2oBQDP-yuE.Cs6_JA.kHRL3DmOS5wJavbd34C8cY7Fvl8', 'Authorization': 'Digest username="mars", realm="Authentication Required", nonce="c148818b24be7094bc1a4f714d18ada5", uri="/", response="ed0fd2e1bf8bbe2c3bccc52c60b63a11", opaque="a271f9c9f64d7b67c52c4f4b0971a5a3"'}

代理场景

HTTP/HTTPS代理

请求时可以通过proxies参数设置代理,代理中也可以设置认证方式,比如:

proxies = {
    "https": "https://username:password@proxy.com",
    "http://stackoverflow.com": "http://username:password@proxy.com"
}

r = requests.get('https://www.google.com', proxies=proxies)
print r.status_code
r = requests.get('http://stackoverflow.com', proxies=proxies)
print r.status_code

SOCKS代理

SOCKS代理从传输层转发代理报文,并不关注应用层采用的是什么协议,速度一般比HTTP/HTTPS代理速度快。如果代理使用了SOCKS协议,则需要安装相应的包支持:pip install requests[socks],然后在代理的URL中按照SOCKS协议书写代理的URL即可。

如果觉得我的文章对您有帮助,欢迎关注我或者为这篇文章点赞,谢谢!

点击复制链接 与好友分享!回本站首页
相关TAG标签 Python requests包
上一篇:C语言预处理
下一篇:Struts2框架入门
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站