python requests高级耍法

昨天,咱们更多的讨论了request的基础API,让咱们对它有了基础的认知。学会上一课程,咱们已经能写点基本的爬虫了。可是还不够,由于,不少站点是须要登陆的,在站点的各个请求之间,是须要保持回话状态的,有的站点还须要证书验证,等等这一系列的问题,咱们将在今天这一环节,加以讨论。html

1.会话对象

会话:session,就是你点进这个站点后,由浏览器与服务器之间保持的一次链接。此次链接里面,你跳转页面,或发起其余请求,服务器要求某些数据验证。服务器不会叫你在每次跳转时候进行验证,而是用已验证的结果进行跳转。这样就节省服务器资源,底层的TCP链接也会被重用。python

跨请求保持数据(客户端存数据):git

s = requests.Session()

s.get('')
r = s.get("")

print(r.text)github

回话提供请求默认数据(数据会被存到服务端):json

s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})

# 'x-test' 和 'x-test2' 一块儿发送给url
s.get('', headers={'x-test2': 'true'})api

注意:即使使用了session,方法级别的参数,仍然不会再跨请求保持。浏览器

如下代码,另个请求分别有本身的cookies安全

s = requests.Session()
r = s.get('')
print(r.text)
# '{"cookies": {}}'

r = s.get('', cookies={'from-my': 'browser'})
print(r.text)
# '{"cookies": {"from-my": "browser"}}'服务器

会话上下文管理器:是指用with 块限定会话对象的使用范围cookie

with requests.Session() as s:
s.get('')

 

2.请求与响应对象

任什么时候候,咱们往服务器发消息,都会返回一个response的响应对象,同时,还能得到咱们本身建立的request对象

r = requests.get('')
print (r.headers)
print (r.request.headers)

在发送请求以前,须要对body获header作一些额外处理,使用以下方法:

from requests import Request, Session


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 证书验证

requests.get('')
requests.get('', verify=True)
requests.get('', verify='/path/to/certfile')
# 将验证路径保持在会话中
s = requests.Session()
s.verify = '/path/to/certfile'
# 忽略对SSL的验证
requests.get('', verify=False)

4.客户端证书

requests.get('', cert=('/path/client.cert', '/path/client.key'))

#证书在会话中

s = requests.Session()
s.cert = '/path/client.cert'

注意:本地证书的私有 key 必须是解密状态。目前,Requests 不支持使用加密的 key。

这里补充一句:当登陆12306时喊你要安装证书。当向有证书验证要求的站点,就使用上面的代码

证书 科普:

Requests 默认附带了一套它信任的根证书,来自于 Mozilla trust store。然而它们在每次 Requests 更新时才会更新。这意味着若是你固定使用某一版本的 Requests,你的证书有可能已经 太旧了。

从 Requests 2.4.0 版以后,若是系统中装了 certifi 包,Requests 会试图使用它里边的 证书。这样用户就能够在不修改代码的状况下更新他们的可信任证书。

6.响应体内容工做流

import requests

# 默认状况下,发起请求会同时下载响应头和响应体(就是响应内容)
tarball_url = ''
# 若是将stream=True 则会推迟响应内容的下载
r = requests.get(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 语句发送请求,这样能够保证请求必定会被关闭
with requests.get('', stream=True) as r:
# 这里处理响应
content = r.content

7.保持活动状态(持久链接)科普

同一会话内的持久链接是彻底自动处理的,同一会话内你发出的任何请求都会自动复用恰当的链接。

注意:只有全部的响应体数据被读取完毕链接才会被释放回链接池;因此确保将 stream 设置为 False 或读取 Response 对象的 content 属性。

8.流式上传

Requests支持流式上传,这容许发送大的数据流或文件,而无需先把它们读入内存。要使用流式上传,需,为请求体,提供一个类文件对象便可:

with open('massive-body') as f:
requests.post('', data=f)

注意的问题:

最好使用二进制模式打开文件。这是由于 requests 有默认设置 header 中的 Content-Length,在这种状况下该值会被设为文件的字节数。若是用文本模式打开文件,就可能碰到错误

9.块编码请求

对于出去和进来的请求,Requests 也支持分块传输编码。要发送一个块编码的请求,仅需为请求体提供一个生成器(或任意没有具体长度的迭代器)

def gen():
yield 'hi'
yield 'there'

requests.post('', data=gen())

注意:

对于分块的编码请求,最好使用 Response.iter_content() 对其数据进行迭代。在理想状况下,request 会设置 stream=True,这样就能够经过调用 iter_content 并将分块大小参数设为 none,从而进行分块的迭代。若是要设置分块的最大致积,能够把分块大小参数设为任意整数。

说白了,就是段点续传

妹的,报了一堆错。先记录在这,后面遇到了再研究

10.POST 多个分块编码的文件

上传图片

import requests

url = ''
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):
print(r.url)


# Requests有一个钩子系统,你能够用来操控部分请求过程,或信号事件处理。
# 在产生响应以前调用print_url 就是server响应以前的回调
hooks = dict(response=print_url)
r = requests.get('', hooks=dict(response=print_url))
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__ 方法
requests.get('', auth=PizzaAuth('kenneth'))

做用就是在请求发出以前,有机会修改请求

13.流式请求

 

import requests

r = requests.get('', 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 = requests.get('', stream=True)


#当使用 decode_unicode=True 在 Response.iter_lines()Response.iter_content() 中#时,须要提供一个编码方式,以防服务器没有提供默认回退编码,从而致使错误

if r.encoding is None:
r.encoding = 'utf-8'#设置编码方式
for line in r.iter_lines(decode_unicode=True):
if line:
print(json.loads(line))

 

#注意:iter_lines 不保证重进入时的安全性。屡次调用该方法 会致使部分收到的数据丢失。#若是要在多处调用它,就应该使用生成的迭代器对象:

lines = r.iter_lines()
# 保存第一行以供后面使用,或者直接跳过

first_line = next(lines)

for line in lines:
print(line)

 

不晓得各位看懂什么是流式请求没。指的不是请求是流,而是请求返回的数据流。返回一点即取一点。而不是普通的是返回完成后在取内容

14.代理

 

import requests

proxies = {
"http": "",
"https": "",
}

requests.get("http://example.org", proxies=proxies)

代理:就是你访问一个网站,其实并非你直接访问的,而是你发请求给A机器,A机器取请求B机器。B返回给A,A再返回给你。代理就是中间人的意思。为何须要代理?由于:反爬虫网站通常使用IP来识别一个机器。总是一个IP再不停访问网站,该网站就会把这个IP拉入黑名单,不容许访问。这时,就须要不少IP再扰乱反爬虫工具的思惟,避免封IP。

 

15.SOCKS

除了基本的 HTTP 代理,Request 还支持 SOCKS 协议的代理。这是一个可选功能,若要使用, 你须要安装第三方库。

在后面的项目实战中,咱们将会使用

16.HTTP动词

GET、OPTIONS、HEAD、POST、PUT、PATCH、DELETE

GET POST最经常使用

PUT,DELETE在调用rest的接口时,也会用到

17.定制动词

有些服务器不接受GET POST等,要求用自定义的,就使用以下方法

r = requests.request('MKCOL', url, data=data)

r.status_code

18.响应头连接字段

许多 HTTP API 都有响应头连接字段的特性,它们使得 API 可以更好地自我描述和自我显露。

好比在使用分页的状况下最有用

url = ''
r = requests.head(url=url)
print(r.headers['link'])
print(r.links["next"])

19.阻塞和非阻塞

使用默认的传输适配器,Requests 不提供任何形式的非阻塞 IO。 Response.content 属性会阻塞,直到整个响应下载完成。若是你须要更多精细控制,该库的数据流功能(见 流式请求) 容许你每次接受少许的一部分响应,不过这些调用依然是阻塞式的。

若是你对于阻塞式 IO 有所顾虑,还有不少项目能够供你使用,它们结合了 Requests 和 Python 的某个异步框架。典型的优秀例子是 grequestsrequests-futures

20.Header 排序

在某些特殊状况下你也许须要按照次序来提供 header,若是你向 headers 关键字参数传入一个OrderedDict,就能够向提供一个带排序的 header。然而,Requests 使用的默认 header 的次序会被优先选择,这意味着若是你在 headers 关键字参数中覆盖了默认 header,和关键字参数中别的 header 相比,它们也许看上去会是次序错误的。

若是这个对你来讲是个问题,那么用户应该考虑在 Session 对象上面设置默认 header,只要将 Session 设为一个定制的 OrderedDict 便可。这样就会让它成为优选的次序。

以上内容,是request的高级耍法,也不算好高级。接下来的一周,咱们将着重讨论如何解析网页。固然,这一部份内容不会包含JS生成的HTML。这个咱们将会在项目实战环节再讨论。

 

转载:https://zhuanlan.zhihu.com/p/30251855

相关文章
相关标签/搜索