Skip to content

Requests - 使用 Requests

Requests 库的主要目的是简化向 Web 服务器发送 HTTP 请求以及处理其响应的过程。本章介绍基础知识:发送基本的 GET 请求、传递 URL 参数以及检查响应的不同部分。

GET 方法是最常见的 HTTP 方法,用于从指定的资源中检索数据。要发送 GET 请求,首先导入 requests 模块:

import requests

然后,使用 requests.get() 函数,提供您要访问的资源的 URL。此函数返回一个 Response 对象,其中包含服务器对您的请求的响应。

import requests
# A common public API for examples
# 一个常用的公共 API 作为示例
url = 'https://jsonplaceholder.typicode.com/todos/1'
try:
response = requests.get(url)
# The 'response' object itself gives some info when printed
# 'response' 对象本身在打印时提供一些信息
print(f'Response Object: {response}')
except requests.exceptions.RequestException as e:
print(f'Request failed: {e}')
print(f'请求失败: {e}')
Response Object: <Response [200]>
响应对象: <Response [200]>

输出 <Response [200]> 表示请求成功,服务器返回的 HTTP 状态码是 200 (OK)。

Response 对象包含关于服务器回复的丰富信息。主要的属性和方法包括:

  • Status Code: response.status_code(整数)提供 HTTP 状态码。response.ok 布尔属性在 status_code 小于 400 时为 True(即不是错误)。
  • Headers: response.headers 是一个不区分大小写的类似字典的对象,包含响应头(例如,Content-Type、Date、Server)。
  • Text Content: response.text 将响应体作为字符串返回。Requests 会尝试使用适当的编码对其进行解码(通常在头部中找到,或默认为 UTF-8)。您可以使用 response.encoding 检查或覆盖编码。
  • Byte Content: response.content 将响应体作为原始字节返回。这适用于非文本内容,如图像、音频或其他二进制文件。
  • JSON Content: 如果响应内容类型是 JSON(例如,application/json),response.json() 将其解析为 Python 字典或列表。如果内容不是有效的 JSON,它会引发 requests.exceptions.JSONDecodeError。

处理潜在的错误至关重要。response.raise_for_status() 方法是一种便捷的方式,可以在请求导致不成功的状态码(4xx 客户端错误或 5xx 服务器错误)时引发 requests.exceptions.HTTPError。

import requests
url = 'https://jsonplaceholder.typicode.com/todos/1'
try:
response = requests.get(url, timeout=5) # Added a timeout
# 添加了超时设置
response.raise_for_status() # Check for HTTP errors (4xx or 5xx)
# 检查 HTTP 错误(4xx 或 5xx)
print(f'Status Code: {response.status_code}')
print(f'Is response OK? {response.ok}')
print(f'Content-Type Header: {response.headers.get("Content-Type")}')
print(f'状态码: {response.status_code}')
print(f'响应是否成功 (OK)? {response.ok}')
print(f'Content-Type 头部: {response.headers.get("Content-Type")}')
# Get JSON data since this API returns JSON
# 获取 JSON 数据,因为此 API 返回 JSON
todo_item = response.json()
print('\nParsed JSON Data:')
print('\n解析后的 JSON 数据:')
print(todo_item)
print(f"Item Title: {todo_item.get('title')}")
print(f"项目标题: {todo_item.get('title')}")
# Example of accessing raw text (though json() is better for JSON data)
# 访问原始文本的示例(尽管对于 JSON 数据来说 json() 更好)
# print('\nRaw Text Data (first 100 chars):')
# print('\n原始文本数据(前 100 个字符):')
# print(response.text[:100] + '...' if len(response.text) > 100 else response.text)
except requests.exceptions.HTTPError as http_err:
print(f'HTTP error occurred: {http_err} - Status Code: {http_err.response.status_code}')
print(f'发生 HTTP 错误: {http_err} - 状态码: {http_err.response.status_code}')
except requests.exceptions.JSONDecodeError as json_err:
print(f'JSON decode error: {json_err}')
print(f'JSON 解码错误: {json_err}')
except requests.exceptions.RequestException as e:
print(f'An error occurred: {e}')
print(f'发生错误: {e}')
Status Code: 200
Is response OK? True
Content-Type Header: application/json; charset=utf-8
Parsed JSON Data:
{
'userId': 1,
'id': 1,
'title': 'delectus aut autem',
'completed': False
}
Item Title: delectus aut autem
状态码: 200
响应是否成功 (OK)? True
Content-Type 头部: application/json; charset=utf-8
解析后的 JSON 数据:
{
'userId': 1,
'id': 1,
'title': 'delectus aut autem',
'completed': False
}
项目标题: delectus aut autem

通常,您需要将数据作为 URL 查询字符串的一部分发送到服务器(例如,example.com/search?query=python&page=1)。Requests 通过允许您将参数字典传递给 requests.get() 方法的 params 参数来简化此操作。

import requests
# Using httpbin.org/get, which reflects the request's arguments
# 使用 httpbin.org/get,它会反映请求的参数
base_url = 'https://httpbin.org/get'
query_parameters = {'name': 'Alice', 'age': 30, 'city': 'Wonderland'}
try:
response = requests.get(base_url, params=query_parameters, timeout=5)
response.raise_for_status()
print(f'Constructed Request URL: {response.url}')
print('\nServer saw these arguments (from response JSON):')
print(f'构造的请求 URL: {response.url}')
print('\n服务器看到的参数(来自响应 JSON):')
# httpbin.org/get returns a JSON where 'args' contains the query parameters
# httpbin.org/get 返回一个 JSON,其中 'args' 包含查询参数
print(response.json().get('args'))
except requests.exceptions.RequestException as e:
print(f'An error occurred: {e}')
print(f'发生错误: {e}')
Constructed Request URL: https://httpbin.org/get?name=Alice&age=30&city=Wonderland
Server saw these arguments (from response JSON):
{'name': 'Alice', 'age': '30', 'city': 'Wonderland'}
(Note: Values in 'args' are strings as they are parsed from the URL)
构造的请求 URL: https://httpbin.org/get?name=Alice&age=30&city=Wonderland
服务器看到的参数(来自响应 JSON):
{'name': 'Alice', 'age': '30', 'city': 'Wonderland'}
(注意:'args' 中的值是字符串,因为它们是从 URL 中解析的)

Requests 会自动对参数进行 URL 编码并构建完整的查询字符串。

除了 GET:其他 HTTP 方法(例如 POST)

Section titled “除了 GET:其他 HTTP 方法(例如 POST)”

Requests 完全支持其他 HTTP 方法,如 POST、PUT、DELETE、HEAD 和 OPTIONS。例如,POST 请求通常用于向服务器发送数据以创建或更新资源。

您可以在请求体中发送数据。对于表单编码的数据,使用 data 参数并传递字典。对于 JSON 数据,使用 json 参数更简单:

import requests
# httpbin.org/post reflects the POSTed data
# httpbin.org/post 会反映 POST 的数据
url_post = 'https://httpbin.org/post'
# Sending JSON data
# 发送 JSON 数据
json_payload = {'username': 'testuser', 'email': 'test@example.com', 'active': True}
try:
response = requests.post(url_post, json=json_payload, timeout=5)
response.raise_for_status()
print('JSON POST Response Details:')
print('JSON POST 响应详情:')
print(f'Status Code: {response.status_code}')
print(f'状态码: {response.status_code}')
# httpbin.org/post returns a JSON that includes the parsed JSON payload under 'json'
# httpbin.org/post 返回一个 JSON,其中包含解析后的 JSON 数据,位于 'json' 键下
returned_data = response.json()
print(f'Sent JSON payload as received by server: {returned_data.get("json")}')
print(f'Request Content-Type header: {returned_data.get("headers", {}).get("Content-Type")}')
print(f'服务器接收到的发送的 JSON 数据: {returned_data.get("json")}')
print(f'请求 Content-Type 头部: {returned_data.get("headers", {}).get("Content-Type")}')
except requests.exceptions.RequestException as e:
print(f'An error occurred during POST: {e}')
print(f'POST 过程中发生错误: {e}')
JSON POST Response Details:
Status Code: 200
Sent JSON payload as received by server: {'username': 'testuser', 'email': 'test@example.com', 'active': True}
Request Content-Type header: application/json
JSON POST 响应详情:
状态码: 200
服务器接收到的发送的 JSON 数据: {'username': 'testuser', 'email': 'test@example.com', 'active': True}
请求 Content-Type 头部: application/json

当您使用 json 参数时,Requests 会自动将您的 Python 字典序列化为 JSON 字符串,并将 Content-Type 头部设置为 application/json。

网络操作有时会很慢或无限期地挂起。为了防止程序永远等待,始终为您的请求指定一个超时时间。Requests 中的 timeout 参数可以是单个浮点数(表示连接和读取超时时间的总和),也可以是一个元组 (connect_timeout, read_timeout)。

import requests
# httpbin.org/delay/N endpoint delays the response by N seconds
# httpbin.org/delay/N 端点会将响应延迟 N 秒
url_delayed = 'https://httpbin.org/delay/3'
try:
# Timeout set to 2 seconds, which is less than the server's 3-second delay
# 超时设置为 2 秒,少于服务器的 3 秒延迟
print('Attempting request with 2s timeout (expected to time out)...')
print('尝试发送 2 秒超时请求(预期会超时)...')
response = requests.get(url_delayed, timeout=2)
print('Request successful (this should not be reached).')
print('请求成功(不应该执行到这里)。')
except requests.exceptions.Timeout:
print('The request timed out as expected after 2 seconds.')
print('请求在 2 秒后按预期超时。')
except requests.exceptions.RequestException as e:
print(f'An unexpected error occurred: {e}')
print(f'发生意外错误: {e}')
try:
# Timeout set to 5 seconds, which is more than the server's 3-second delay
# 超时设置为 5 秒,多于服务器的 3 秒延迟
print('\nAttempting request with 5s timeout (expected to succeed)...')
print('\n尝试发送 5 秒超时请求(预期会成功)...')
response = requests.get(url_delayed, timeout=5)
response.raise_for_status()
print(f'Request successful within 5 seconds. Status: {response.status_code}')
print(f'请求在 5 秒内成功。状态码: {response.status_code}')
except requests.exceptions.Timeout:
print('The request timed out (this should not happen with a 5s timeout for a 3s delay).')
print('请求超时(对于 3 秒延迟,设置为 5 秒超时不应该发生)。')
except requests.exceptions.RequestException as e:
print(f'An error occurred: {e}')
print(f'发生错误: {e}')
Attempting request with 2s timeout (expected to time out)...
The request timed out as expected after 2 seconds.
Attempting request with 5s timeout (expected to succeed)...
Request successful within 5 seconds. Status: 200
尝试发送 2 秒超时请求(预期会超时)...
请求在 2 秒后按预期超时。
尝试发送 5 秒超时请求(预期会成功)...
请求在 5 秒内成功。状态码: 200

设置适当的超时时间是编写健壮的网络应用程序的最佳实践。