Requests 是用语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。
一、安装
request 通过pip安装:
#windows:
pip install requests
#Linux:
sudo pip install requests
安装后再终端下运行Python,查看request的版本信息,检测是否安装成功:
>>>import requests
>>>requests.__version__
'2.21.0'
二、请求方式
HTTP常见的请求是GET和POST,详细介绍请看两种HTTP请求方法:GET对比POST对比
(1)requests实现get请求:
GET请求有种形式(以百度为例):
#不带参数
https://www.baidu.com/s
#带参数
https://www.baidu.com/s?wd=python
判断URL是否带有参数,可以对符号‘’?‘’判断。一般网址末端带有‘’?‘’就说明该URL带有参数。如果一个URL有多个参数,则用‘’&‘’连接。
requests实现get请求,对于带有参数的有两种方式:
import requests
#第一种:
response = requests.get("https://www.baidu.com/s?wd=python")
#第二种:
response = requests.get("https://www.baidu.com/s",params={"wd":"python")
实际开发中建议使用第一种,因为不仅代码简单,而且如果参数动态变化,那么可以使用字符串格式对URL动态设置,比如:”https://www.baidu.com/s?wd=%s” % ('python')
(2)requests实现post请求:
POST请求就是提交表单,表单的数据内容就是POST的请求参数,Requests实现POST请求需设置请求参数data,数据格式可以是字典,元组,列表,JSON格式。
不同的数据格式如下:
#字典
data = {
'key1': 'value1',
'key2': 'value2',
}
#元组或者列表
data = (('key1', 'value1'), ('key2', 'value2'), ('key3', 'value3'))
#JSON
#JSON(一种轻量级的数据交换格式)
import json
data = {
'key1': 'value1',
'key2': 'value2',
}
data = json.dumps(data)
requests实现post请求:
import requests
response = requests.post('https://www.baidu.com/', data=data)
值得注意的是,requests的GET和POST方法的请求参数分别是params和data。
(3)响应对象(Response)
发送请求时,服务器会返回相应的响应对象。requests提供以下方法获取响应内容:
response.status_code: 响应状态码
response.raw: 原始响应体,使用r.raw.read()读取
response.content: 字节方式的响应体,需要进行解码。
response.text: 字符串方式的响应体。
response.headers: 以字典对象存储服务器响应头。
response.json: requests内置的JSON解码器。
response.raise_for_status(): 请求失败(非200响应),抛出异常。
response.url: 获取请求链接。
response.cookies: 获取请求后的cookies。
response.encoding: 获取编码格式。
三、复杂的请求方式
1. 添加请求头(headers):
import requests
headers = {
'content-type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6756.400 QQBrowser/10.3.2473.400',
'cookies':' ',
'referer':' ',
}
requests.get('http://www.baidu.com/', headers=headers)
2.使用代理IP(proxies):
import requests
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'https://10.10.1.10:1080'
}
requests.get('http://www.baidu.com/', proxies=proxies)
3. 证书验证(verify):
通常设置请求参数verify=False时关闭验证即可,默认为True。如需设置证书文件,则verify = 证书路径。
import requests
url = 'https://kyfw.12306.cn/otn/leftTicket/init'
# 关闭证书验证
# 不过下面的请求会有如下警告,建议指定证书
'''InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-
usage.html#ssl-warningsInsecureRequestWarning)'''
response = requests.get(url, verify=False)
print(response.status_code)
# 默认是开启证书验证
# response = requests.get(url, verify=True)
# 设置证书路径
# response = requests.get(url, verify='/path/to/certfile')
对于上述警告解决方法:
-
方法一:设置忽略警告的方式屏蔽这个警告
import requests from requests.packages import urllib3 urllib3.disable_warnings() response = requests.get('https://www.12306.cn', verify=False) print(response.status_code)
-
方法二:使用 logging模块 捕获警告到日志的方式忽略警告
import logging import requests logging.captureWarnings(True) response = requests.get('https://www.12306.cn', verify=False) print(response.status_code)
-
方法三:指定本地证书用作客户端证书,而且本地私有证书的 key 必须是解密状态,加密状态的key是不支持的
import requests response = requests.get('https://www.12306.cn', cert=('/path/server.crt', '/path/key')) print(response.status_code)
4. 设置超时时间(timeout):
如果服务器在设置的请求参数timeout的timeout秒内没有应答,将引发一个异常。
import requests
# GET请求
requests.get('http://www.baidu.com/', timeout=2)
# POST请求
requests.post('http://www.baidu.com/', timeout=2)
5. 标识识别身份(Cookies):
设置参数cookies即可,在requests中可以以字典或者RequestsCookieJar对象作为cookies参数。
当客户端发送请求时,自动会生成一个RequestsCookieJar对象,用于存放Cookies(服务器发送给客户端的,以保持服务器与客户端之间的状态)。
#cookies字符串转化为字典的方法:
temp_cookies = '_zap=e6bcb677-f710-4bf1-8ceb-de51e97415c9; _xsrf=685f3baf-45be-43b4-8f32-02de3367b5e5;\
d_c0="AEDkwu2GVA6PThq56D3xIo2-6W-daZoS90s=|1538970683";\
q_c1=185fcb11f0f7429eaba419368a2f4b7e|1538970685000|1538970685000;\
l_n_c=1; n_c=1;\
l_cap_id="Y2E3MGY5ZTdhZWFiNDE0ZjkzMmQ0MTQzOGM1YWExM2Y=|1539332192|46faa5b9406b718f99e6c369465bccbde3cc5ba9"; \
r_cap_id="ZWEwODQwMTkyMGM0NDE1N2E3YWFhNDI5ZTZmOTE5NmU=|1539332192|405231c0a71396732f27d6a4368c78c0f7bb86cb"; \
cap_id="YjAxNGUzN2M1MzFjNDhjNWE4M2UyZjg3MDBkNWJiNWY=|1539332192|4758bc5f5a4678861d6990b9dd2dc86bb2812364";\
tgw_l7_route=5bcc9ffea0388b69e77c21c0b42555fe'
cookies_dict = {}
for i in temp_cookies.split(';'):
value = i.split('=')
cookies_dict[value[0]] = value[1]
或者
cookie_dict = {i.split("=")[0]:i.split("=")[-1] for i in cookie.split("; ")}
代码中temp_cookies 是cookies信息,可以在chrome开发者工具的Network中的某请求的Headers的Request Headers中找到,它是一个字符串。上面的代码通过两次spilt分割:temp_cookies.split(';')得到列表,i.split('=')得到键值对构成列表。最终得到的cookies_dict为一个字典。
requests的响应(response)对象的cookies属性,即 respons.cookies 是RequestsCookieJar对象。requests提供RequestsCookieJar对象与字典对象之间相互转化的方法,如下:
import requests
#RequestsCookieJar对象转化为字典:
requests.utils.dict_from_cookiesjar()
#字典转化为RequestsCookieJar对象
requests.utils.cookiesjar_from_dict()
#在RequestsCookieJar中添加字典
requests.utils.add_dict_to_cookiesjar()
requests的response对象的cookies属性是RequestsCookieJar对象。
四、下载与上传
(1)下载
下载即从服务器获取内容,然后保存在本地,方法如下:
import requests
response = requsets.get('https://cc.stream.qqmusic.qq.com/C100001Yy1a31Dr60y.m4a?fromtag=52')
with open('mymusic.m4a','wb') as f:
f.write(r.content)
该代码中的url是一个音频,请求后得到的内容以字节流的形式写入文件。
(2)上传
post上传文件(可以是图片,音频,视频等)时,使用files参数,作为请求参数。files参数以字典形式传递。
如下:
import requests
#一个字段单个文件上传
files = {
"field1" : open('report.xls', 'rb')
}
或者
#一个字段多个文件上传(推荐使用元组列表,其中列表中元组的结果为(form_field_name,file_info))
files = [
("field1" , ("filename1", open("filePath1", "rb"))),
("field1" , ("filename2", open("filePath2", "rb"), "image/png")),
("field1" , open("filePath3", "rb")),
("field1" , open("filePath4", "rb").read())
]
response = requests.post(url,files = files)
五、错误与异常
- 遇到网络问题(如:DNS 查询失败、拒绝连接等)时,requests 会抛出一个
ConnectionError
异常。 - 如果 HTTP 请求返回了不成功的状态码,response_raise_for_status ()会抛出一个
HTTPError
异常。 - 若请求超时,则抛出一个
Timeout
异常。 - 若请求超过了设定的最大重定向次数,则会抛出一个
TooManyRedirects
异常。
所有requests显式抛出的异常都继承自 requests.exceptions.RequestException
六、事件挂钩
requests有一个钩子系统(事件完成后,执行的回调函数),你可以用来操控部分请求过程,或信号事件处理。
通过设置hooks参数实现。可用的钩子—response,
从一个请求产生的响应对象。
通过传递一个 { response : callback_function}
字典给 hooks
请求参数为每个请求分配一个钩子(回调)函数。
response响应对象会作为第一个参数传入回调函数,若执行回调函数期间发生错误,系统会给出一个警告。若回调函数返回一个值,默认以该值替换向函数传进来的数据。若函数未返回任何东西,也没有什么其他的影响。
举个例子如下,在运行期间打印get请求方法的参数:
#回调函数
def print_url(r, *args, **kwargs):
print(r.url)
>>> requests.get('http://httpbin.org', hooks=dict(response=print_url))
http://httpbin.org
<Response [200]>
七、会话保持
请求对象与响应对象:
任何时候进行了类似 requests.get() 的调用,你都在做两件主要的事情。其一,你在构建一个 Request 对象, 该对象将被发送到某个服务器请求或查询一些资源。其二,一旦
requests
得到一个从服务器返回的响应就会产生一个Response
对象。该响应对象包含服务器返回的所有信息,也包含你原来创建的Request
对象。
requests中的会话对象(Session)让你能够跨请求保持某些参数。它也会在同一个 Session 实例发出的所有请求之间保持 cookie, 期间使用 urllib3
的 connection pooling (连接池)功能。所以如果你向同一主机发送多个请求,底层的 TCP 连接将会被重用,从而带来显著的性能提升。会话对象具有主要的 requests API 的所有方法。
1. 会话对象可以用来跨请求保持一些 cookie:
from requests import Session
#会话对象实例化
s = Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
# 跨请求
r = s.get("http://httpbin.org/cookies")
print(r.text)
# '{"cookies": {"sessioncookie": "123456789"}}'
2. 会话对象也可用来为请求方法提供缺省数据:
from requests import Session
#通过为会话对象的属性提供数据实现为请求方法提供缺省数据。
s = Session()
#会话对象的属性初始化
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})
# 'x-test' 和 'x-test2'会一起随请求发送,传递给请求方法的字典都会与已设置会话层数据合并。
s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
3. 值得注意的是,就算使用了会话对象,方法级别的参数也不会被跨请求保持,举个栗子如下:
from requests import Session
s = Session()
response = s.get('http://httpbin.org/cookies', cookies={'from-my': 'browser'})
print(response.text)
# '{"cookies": {"from-my": "browser"}}'
response = s.get('http://httpbin.org/cookies')
print(response.text)
# '{"cookies": {}}'
4. 手动为会话添加 cookie,就使用 Cookie utility 函数 来操纵 Session.cookies。
5. 会话还可以用作前后文管理器:
from requests import Session
s = Session()
# 确保 with 区块退出后会话能被关闭,即使发生了异常也一样。
with requests.Session() as s:
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
从字典参数中移除一个值:
因为方法层的参数覆盖会话的相同参数。在方法层参数中将那个键的值设置为
None
,就可以省略会话层字典参数中该键包含在一个会话中的所有数据你都可以直接使用。
当从 API 或者会话调用中收到一个 response 对象时,request
属性其实是使用了 PreparedRequest(准备的请求)
。有时在发送请求之前,你需要对 body 或者 headers (或者别的什么东西)做一些额外处理,
下面演示了一个简单的做法:
from requests import Request, Session
s = Session()
#实例化请求对象
req = Request('GET', url,
data=data,
headers=header
)
#准备好请求对象
prepped = req.prepare()
#发送请求,返回响应对象resp
resp = s.send(prepped,
stream=stream,
verify=verify,
proxies=proxies,
cert=cert,
timeout=timeout
)
print(resp.status_code)
然而,上述代码会失去 Requests Session 对象的一些优势, 尤其 Session 级别的状态,例如 cookie 就不会被应用到你的请求上去。要获取一个带有状态的 PreparedRequest (准备好的请求), 请用 Session.prepare_request() 取代 Request.prepare()的调用,如下所示:
from requests import Request, Session
s = Session()
req = Request('GET', url,
data=data
headers=headers
)
prepped = s.prepare_request(req)
resp = s.send(prepped,
stream=stream,
verify=verify,
proxies=proxies,
cert=cert,
timeout=timeout
)
print(resp.status_code)
写在最后,欢迎关注一个一起学python的微信公众号:大众学python
掏出手机扫一扫: