python异步requests_pythonrequests⾼级耍法
昨天,我们更多的讨论了request的基础API,让我们对它有了基础的认知。学会上⼀课程,我们已经能写点基本的爬⾍了。但是还不够,因为,很多站点是需要登录的,在站点的各个请求之间,是需要保持回话状态的,有的站点还需要证书验证,等等这⼀系列的问题,我们将在今天这⼀环节,加以讨论。
1.会话对象
会话:session,就是你点进这个站点后,由浏览器与服务器之间保持的⼀次连接。这次连接⾥⾯,你跳转页⾯,或发起其他请求,服务器要求某些数据验证。服务器不会叫你在每次跳转时候进⾏验证,⽽是⽤已验证的结果进⾏跳转。这样就节省服务器资源,底层的TCP连接也会被重⽤。
跨请求保持数据(客户端存数据):
回话提供请求默认数据(数据会被存到服务端):
s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})
# 'x-test' 和 'x-test2' ⼀起发送给url
<('/headers', headers={'x-test2': 'true'})
注意:即便使⽤了session,⽅法级别的参数,仍然不会再跨请求保持。
以下代码,另个请求分别有⾃⼰的cookies
s = requests.Session()
r = s.get('/cookies')
)
# '{"cookies": {}}'
r = s.get('/cookies', cookies={'from-my': 'browser'})
)
# '{"cookies": {"from-my": "browser"}}'
会话上下⽂管理器:是指⽤with 块限定会话对象的使⽤范围
2.请求与响应对象
任何时候,我们往服务器发消息,都会返回⼀个response的响应对象,同时,还能获得我们⾃⼰创建的request对象
r = ('/wiki/Monty_Python')
print (r.headers)
print (r.request.headers)
在发送请求之前,需要对body获header做⼀些额外处理,使⽤如下⽅法:
s = Session()
req = Request('GET', url,
data=data,
headers=header
)
#要想获取有状态的请求,使⽤:
prepped = s.prepare_request(req)
⽽不是使⽤:
prepped = req.prepare()
# do something with prepped.body
# do something with prepped.headers
resp = s.send(prepped,
stream=stream,
verify=verify,
proxies=proxies,
cert=cert,
timeout=timeout
)
print(resp.status_code)
3.SSL 证书验证
<('requestb.in')
<('github', verify=True)
<('github', verify='/path/to/certfile')
# 将验证路径保持在会话中
s = requests.Session()
s.verify = '/path/to/certfile'
# 忽略对SSL的验证
<('', verify=False)
4.客户端证书
<('', cert=('/', '/path/client.key')) #证书在会话中
s = requests.Session()
< = '/'
这⾥补充⼀句:当登录12306时喊你要安装证书。当向有证书验证要求的站点,就使⽤上⾯的代码
Requests 默认附带了⼀套它信任的根证书,来⾃于 Mozilla trust store。然⽽它们在每次 Requests 更新时才会更新。这意味着如果你固定使⽤某⼀版本的 Requests,你的证书有可能已经 太旧了。
从 Requests 2.4.0 版之后,如果系统中装了 certifi 包,Requests 会试图使⽤它⾥边的 证书。这样⽤户就可以在不修改代码的情况下更新他们的可信任证书。
6.响应体内容⼯作流
import requests
# 默认情况下,发起请求会同时下载响应头和响应体(就是响应内容)
tarball_url = 'github/kennethreitz/requests/tarball/master'
# 如果将stream=True 则会推迟响应内容的下载
r = (tarball_url, stream=True)
# 这⾥就是:满⾜某种条件才去下载
if int(r.headers['content-length']) < TOO_LONG:
content = r.content
# 在请求中把 stream 设为 True,Requests ⽆法将连接释放回连接池,
# 除⾮消耗了所有的数据,或者调⽤了 Response.close。
# 这样会带来连接效率低下的问题。如果在使⽤ stream=True 的同时还在部分读取请求的 body(或者完全没有读取 body),
# 那么就应该使⽤ with 语句发送请求,这样可以保证请求⼀定会被关闭
('/get', stream=True) as r:
# 这⾥处理响应
content = r.content
7.保持活动状态(持久连接)科普
同⼀会话内的持久连接是完全⾃动处理的,同⼀会话内你发出的任何请求都会⾃动复⽤恰当的连接。
注意:只有所有的响应体数据被读取完毕连接才会被释放回连接池;所以确保将 stream 设置为 False 或读取 Response 对象的 content 属性。
8.流式上传
Requests⽀持流式上传,这允许发送⼤的数据流或⽂件,⽽⽆需先把它们读⼊内存。要使⽤流式上传,需,为请求体,提供⼀个类⽂件对象即可:
with open('massive-body') as f:
requests.post('some.url/streamed', data=f)
注意的问题:
最好使⽤⼆进制模式打开⽂件。这是因为 requests 有默认设置 header 中的 Content-Length,在这种情况下该值会被设为⽂件的字节数。如果⽤⽂本模式打开⽂件,就可能碰到错误
9.块编码请求
对于出去和进来的请求,Requests 也⽀持分块传输编码。要发送⼀个块编码的请求,仅需为请求体提供⼀个⽣成器(或任意没有具体长度
def gen():
yield 'hi'
yield 'there'
requests.post('some.url/chunked', data=gen())
注意:
对于分块的编码请求,最好使⽤ Response.iter_content() 对其数据进⾏迭代。在理想情况下,request 会设置 stream=True,这样就可以通过调⽤ iter_content 并将分块⼤⼩参数设为 none,从⽽进⾏分块的迭代。如果要设置分块的最⼤体积,可以把分块⼤⼩参数设为任意整数。
说⽩了,就是段点续传
妹的,报了⼀堆错。先记录在这,后⾯遇到了再研究
10.POST 多个分块编码的⽂件
上传图⽚
import requests
url = '/post'
multiple_files = [
('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
r = requests.post(url, files=multiple_files)
print (r.text)
11.事件挂钩
import requests
def print_url(r, *args, **kwargs):
# Requests有⼀个钩⼦系统,你可以⽤来操控部分请求过程,或信号事件处理。
# 在产⽣响应之前调⽤print_url 就是server响应之前的回调
hooks = dict(response=print_url)
r = ('', hooks=dict(response=print_url))
session如何设置和读取print (r.text)
也没看有什么⽤
12.⾃定义⾝份验证
import requests
from requests.auth import AuthBase
class PizzaAuth(AuthBase):
def __init__(self, username):
# setup any auth-related data here
self.username = username
def __call__(self, r):
# modify and return the request
r.headers['X-Pizza'] = self.username
return r
#注意:auth参数必须是⼀个可调⽤对象 实现了 __call__ ⽅法
<('/admin', auth=PizzaAuth('kenneth'))
作⽤就是在请求发出之前,有机会修改请求
13.流式请求
import requests
r = ('/stream/20', stream=True)
for line in r.iter_lines():
# filter out keep-alive new lines
if line:
decoded_line = line.decode('utf-8')
print(json.loads(decoded_line))
就是将请求参数设置stream=True
import requests
r = ('/stream/20', stream=True)
#当使⽤ decode_unicode=True 在 Response.iter_lines() 或 Response.iter_content() 中#时,需要提供⼀个编码⽅式,以防服务器没有提供默认回退编码,从⽽导致错误

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。