Requests Library 库使用指南

本文翻译于Real Python,翻译以便于查阅。若有不同之处,夹杂作者主观喜好。

开始

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
response = request.get('url')

# 可以向下面这样做
if response.status_code == 200:
    print('Success!')
elif response.status_code == 404:
    print('Not Found.')
# 还可以这样!
if response:
		print('成功')
else:
		print('失败')

get()方法返回的是一个Response 对象的一个实例。(在本例中被存储到response 这个变量里)

**提示:**为什么可以这样做?

是因为__bool__() 是Response对象的一个重载方法

注意:if response 语句,状态码200-400 这个表达式的值均为True

如果你不想在if语句里面检查响应的状态码。

相反,你想在请求不成功的时候引发一个异常。

可以这样做

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import requests
from requests.exceptions import HTTPError

for url in ['https://api.github.com', 'https://api.github.com/invalid']:
    try:
        response = requests.get(url)

        # If the response was successful, no Exception will be raised
        response.raise_for_status()
    except HTTPError as http_err:
        print(f'HTTP error occurred: {http_err}')  # Python 3.6
    except Exception as err:
        print(f'Other error occurred: {err}')  # Python 3.6
    else:
        print('Success!')

如果状态码是成功类状态码,程序继续执行,不引发异常。否则将引发异常。

Response

查看响应的字节内容,可以使用 .content

1
2
response = requests.get('https://api.github.com')
response.content

可以编码→转换为字符串。当你使用.text是默认转为utf-8(requests 会从请求头猜测编码,一般是utf-8)

1
response.text

也可以显式编码。

1
2
response.encoding = 'utf-8' 
response.text

如果你查看响应,它实际上是序列化的json内容。

为了得到Python的数据结构(字典)

要进行反序列化

1
response.json()

Headers

header 返回一个类似字典的对象,允许通过键访问header值。

1
response.header['Content-Type']

header对象有一些特殊之处,HTTP规范将报头定义为不区分大小写。

所以这样写也可以

1
response.header['content-type']

Query String Parameters

自定义请求,常用查询字符串参数传递值。(params)

例如

1
2
3
4
5
6
7
import requests
# 搜索github仓库
response = requests.get('https://api.github.com/search/repositories',params={'q':'requests+language:python'},)
json_response = response.json()
repository = json_response['items'][0]
print(f'Repository name:{repository["name"]}')
print(f'Repository description:{repository["description"]}')

你可以以字典的形式把params 传递给get(),也可以以元祖的形式传递。

1
requests.get('https://api.github.com//search/repositories',params = [('q', 'requests+language:python']),)

甚至可以 以字节的形式传递这些值

1
2
3
4
>>> requests.get(
...     'https://api.github.com/search/repositories',
...     params=b'q=requests+language:python',
... )

Request Headers

自定义header,需要使用headers 参数传递一个HTTP header 字典以获得()

例如

1
2
3
4
5
6
7
8
9
import requests
response = requests.get(
    'https://api.github.com/search/repositories',
    params={'q': 'requests+language:python'},
    headers={'Accept': 'application/vnd.github.v3.text-match+json'}, # 指定了文本匹配类型 text-match+json
)
json_response = response.json()
repository = json_response['items'][0]
print(f'Text matches: {repository["text_matches"]}')

text-match+json 这是一种专有的github Accept 头文件,内容是一种特殊的json格式

Other HTTP Methods

1
2
3
4
5
6
>>> requests.post('https://httpbin.org/post', data={'key':'value'})
>>> requests.put('https://httpbin.org/put', data={'key':'value'})
>>> requests.delete('https://httpbin.org/delete')
>>> requests.head('https://httpbin.org/get')
>>> requests.patch('https://httpbin.org/patch', data={'key':'value'})
>>> requests.options('https://httpbin.org/get')

每个函数调用都使用相应的HTTP方法对httpbin服务发出请求。

1
2
3
4
5
6
7
8
>>> response = requests.head('https://httpbin.org/get')
>>> response.headers['Content-Type']
'application/json'

>>> response = requests.delete('https://httpbin.org/delete')
>>> json_response = response.json()
>>> json_response['args']
{}

The message Body

POST、PUT、和不太常见的PATCH请求通过**消息体(data)**传递数据,而不是通过查询字符串的参数。

data 接受字典、元组列表、字节或者 file-like object。你需要调整正在请求主体中发送的数据,以适应与之交的服务的特定需求。

例如:

1
requests.post('https://httpbin.org/post', data={'key':'value'})

也可以用元组

1
requests.post('https:://httpbin.org/post',data=('key','value')

但是,如果需要 发送JSON数据,可以使用JSON参数。

requests 将序列化你的数据并为你添加正确的Content-Type

httpbin.org 是个很好的资源,由request作者创建。

1
2
3
4
5
response = requests.post('https://httpbin.org/post', json={'key':'value'})
json_response = response.json()
json_response['data']

json_response['headers']['Content-Type']

requests 以PrepareRequest 的形式向你提供此信息

Inspecting Your Request

在你发送请求之前,请求准备包括 validating headers and serializing JSON content

你可以通过**.request**来访问PrepareRequest

1
2
3
4
5
6
response = requests.post('https://httpbin.org/post', json={'key':'value'})
response.request.headers['Content-Type']

response.request.url

response.request.body

Authentication

截止到目前为止,上面这些所有的请求 都是对公共api的未经身份验证的请求。

接下来谈论一下需要验证身份的请求

所有的请求函数都提供了一个名为auth的参数。它允许你传递凭证 → 元组列表

例如 github的 Authenticated User API

要想它发送请求,该怎么做呢? 如下所示:

1
2
from getpass import getpass
requests.get('https://api.gihu.com/user',auth = ('username',getpass()))

当你的用户名和密码在一个元组中传递给auth参数时,请求将在内部使用HTTP的 **Basic acces authentication schme**

因此你可以这样做

1
2
3
4
5
6
from requests.auth import HTTPBasicAuth
from getpass import getpass
requests.get(
    'https://api.github.com/user',
    auth=HTTPBasicAuth('username', getpass())
)

requests 还提供了其他身份验证方法

  1. HTTPDigestAuth
  2. HTTPProxyAuth

你甚至可以提供自己的身份验证机制。为此必须首先创建AuthBass的子类,然后实现__call__

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import requests
from requests.auth import AuthBase

class TokenAuth(AuthBase):
		""" 实现一个自定义的身份验证机制 """
		def __init__(self, token):
				self.token = token
		def __call__(self, r):
				"""将一个API token 添加到一个自定义的header 中"""
				r.header['X-TokenAuth'] = f'{self.token}'
				return r
requests.get('https://httpbin.org/get', auth=TokenAuth('12345abcde-token'))

上面的代码中,你自定义的TokenAuth 接受一个token,然后j将该token包含你的请求的X-TokenAuth header中

Suggestion:为了安全考虑,建议使用Basic OAuth 这些经过验证的身份验证机制

SSL Certufucate Verfucatuib

证书验证

在requests 中默认会为你执行此操作(通过SSL建立加密链接)

如果你想禁用 — 只需将verify赋值为False

1
requests.get('https://api.github.com', verify=False)

Performance

Timeouts(暂停)

在请求中添加timeout 字段

1
2
3
requests.get('https://api.github.com', timeout=1)

requests.get('https://api.github.com', timeout=3.05)

你也可以给timeout 属性添加一个元组

你也可以传一个元组到超时,第一个元素是连接超时(允许客户端建立到服务器的连接的时间) ,第二个元素是读超时(客户端建立连接后等待响应的时间) :

1
requests.get('https://api.github.com', timeout=(2, 5))

5s之后请求超时,引发一个Timeout 异常

1
2
3
4
5
6
7
8
9
import requests
from requests.exceptions import Timeout

try:
    response = requests.get('https://api.github.com', timeout=1)
except Timeout:
    print('The request timed out')
else:
    print('The request did not time out')

The Session Object

例如get(),post()这些高级别请求的api 是怎么实现的呢?

依靠于 Session 这个类,当你需要微调对发出请求的方式的控制(在高级别的抽象之下的操作)

这时你就需要Session类了

Session 用于请求持久化参数。

例如 多个请求使用相同的身份验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import requests
from getpass import getpass
# 通过使用一个上下文管理器你可以确保
# Session 所使用的资源将在使用后被释放
with requests.Session() as session:
		session.auth = ('username',getpass())

		# Instead of requests.get(), you'll use session.get()
		response = session.get('https://api.github.com/user')

# 你也可以像之前那样检查response
print(response.headers)
print(response.json())

每次使用会话发出请求时,一旦使用身份验证凭据初始化了该凭据,该凭据将被持久化。

会话的主要性能优化以持久连接的形式出现。当您的应用程序使用 Session 连接到服务器时,它将这个连接保存在连接池中。当您的应用程序想要再次连接到同一台服务器时,它将重复使用池中的连接,而不是建立一个新的连接。

Max Retries 最大重试次数

你需要一个自定义的 Transport Adapter 来实现这个功能

Transport Adapter 允许您为与之交互的每个服务定义一组配置。例如,假设您希望所有的请求在最终引发一个 ConnectionError 之前重试3次

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import requests
from requests.adapters import HTTPAdapter
from requests.exceptions import ConnectionError

github_adapter = HTTPAdapter(max_retries=3)

session = requests.Session()

# 将 github_adapter 挂载到 session
# Use `github_adapter` for all requests to endpoints that start with this URL
session.mount('https://api.github.com', github_adapter)

try:
    session.get('https://api.github.com')
except ConnectionError as ce:
    print(ce)

当你把 HTTPAdapter、github_adapter 挂载到session。

session 会将每个配置到https://api.github.com

ConClusion

  • 使用各种不同的 HTTP 方法进行请求,例如GET, PUT

    ,Put

  • 通过修改标头、身份验证、查询字符串和消息正文来自定义请求

  • 检查发送到服务器的数据和服务器发送回来的数据

  • 使用 SSL 证书验证

  • 有效的利用 max_retires、seesion、transport adapter