python第三方库—requests详解

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

七、会话保持

请求对象与响应对象:

任何时候进行了类似 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

掏出手机扫一扫:

你可能感兴趣的:(后端,Python,requests,python)