在线运行和编辑此教程中的代码
运行代码使用 Python requests 模块发起 GET 和 POST 请求
时间紧?下面是发起简单 GET 和 POST 请求的 Python 语法:
1. GET 请求
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/1"
# A GET request to the API
response = requests.get(url)
# Print the response
print(response.json())
2. POST 请求
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts"
# Data to be sent
data = {
"userID": 1,
"title": "Making a POST request",
"body": "This is the data we created."
}
# A POST request to the API
response = requests.post(url, json=data)
# Print the response
print(response.json())
理解 REST API 及其 HTTP 基础
我们已经知道,API 是软件中介。另一种理解方式是:它是一种软件接口,授予其他应用对特定数据和方法的访问权限。
用于构建 API 的最流行架构之一是表述性状态转移(REST)模式。REST 的架构设计使客户端和服务器可以彼此独立实现,而无需了解对方。这意味着任一端的代码都可以更改,而不必担心更改会如何影响另一端。
因此,REST API 遵循一套旨在简化软件间通信的准则,从而让访问数据的过程更直接、更合乎逻辑。如果您不清楚这些准则也不必担心;入门并不需要掌握它们——您需要了解的是 REST 服务如何暴露数据。
来自 REST Web 服务的数据通过公共 URL 暴露在互联网上,您可以通过发送 HTTP 请求来访问。
HTTP 请求方法概览
让我们回到餐馆的类比:在餐馆点餐时,服务员走到您面前,您说出想要的菜品。服务员随后将您的请求转达给厨师,厨师做好后交给服务员再由其端回给您。换言之,在您发出请求前,厨师不会开始做菜。
REST API 也是如此:它们会在接收到 HTTP 请求方法后再采取行动。HTTP 定义了一组请求方法,用来告诉 API 针对给定资源应执行哪些操作。它还规定了如何与所提供端点上的资源进行交互。
HTTP 方法有多种,但在 REST API 中常用的有五种:
| HTTP 方法 | 说明 |
|---|---|
| GET | 检索数据 |
| POST | 创建数据 |
| PUT | 更新现有数据 |
| PATCH | 部分更新现有数据 |
| DELETE | 删除数据 |
在数据分析和数据科学中,您极有可能最常执行的是 GET 请求。这是因为访问某些数据集必须使用该方法。想了解更多,请参阅 DataCamp 的 Intermediate Importing Data in Python 课程。
当您向 Web 服务器发起请求时,API 会返回一个响应。响应中附带一个 HTTP 状态码。状态码的目的在于为响应提供更多信息,以便客户端了解所收到响应的类型。
什么是 API 端点?
URL 定义了您在 Web 服务器上要交互的数据。就像网页 URL 对应到单个页面一样,端点 URL 关联到 API 内的特定资源。因此,可以把端点描述为 API 在其服务器上接收关于特定资源查询的数字“位置”——把它看作通信通道的另一端。
进一步说,REST API 会暴露一组公共 URL,客户端应用可以通过请求这些 URL 来访问 Web 服务的资源。REST API 暴露的这些公共 URL 就被称为“端点”。
使用 Python 发起 HTTP 请求
Python 的 requests 模块使开发者能够编写代码与 REST API 交互。它允许使用 Python 发送 HTTP 请求,而无需操心通常伴随这些任务的复杂性(例如手动将查询字符串附加到 URL、对 PUT 和 POST 数据进行表单编码等)。
尽管 requests 模块被视为在 Python 中发起 HTTP 请求的事实标准,但它并非 Python 标准库的一部分——需要单独安装。
安装 requests 模块最简单的方法是使用 pip:
python -m pip install requests
始终建议使用虚拟环境来管理不同项目所需的 Python 包;这样一来,各项目的包彼此隔离,而不是全局安装,就不会相互干扰或破坏其他项目中的系统工具。
现在我们已经安装了 requests 模块,接下来看看它如何工作。 在这个 DataLab 工作簿中跟着代码一起实践。
在 Python 中发起 GET 请求
我们已经说明,GET 是您在使用 REST API 时最常见的 HTTP 请求方法之一。它允许您(客户端)从 Web 服务器检索数据。
需要注意的是,GET 是只读操作,这意味着它只适用于访问现有资源,不应被用于修改资源。
为演示 requests 模块如何工作,我们将使用 JSONPlaceholder,这是一个可自由使用的、用于测试和原型设计的假 API。
import requests
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/1"
# A GET request to the API
response = requests.get(url)
# Print the response
response_json = response.json()
print(response_json)
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
"""
在上述代码中,我们进行了以下操作:
-
定义了要从中检索数据的 API 端点。
-
使用
requests.get(url)方法从指定端点检索数据。 -
使用
response.json()方法将响应数据存入字典对象;请注意,这仅在结果为 JSON 格式时有效——否则将会引发错误。 -
最后一步是打印 JSON 响应数据。
我们还可以像下面这样检查 API 返回的状态码:
# Print status code from original response (not JSON)
print(response.status_code)
"""
200
"""
您也可以向 Python 的 GET 请求传递参数。为此,我们需要稍微修改上面的代码。新代码如下:
# The API endpoint
url = "https://jsonplaceholder.typicode.com/posts/"
# Adding a payload
payload = {"id": [1, 2, 3], "userId":1}
# A get request to the API
response = requests.get(url, params=payload)
# Print the response
response_json = response.json()
for i in response_json:
print(i, "\n")
"""
{'userId': 1, 'id': 1, 'title': 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto'}
{'userId': 1, 'id': 2, 'title': 'qui est esse', 'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla'}
{'userId': 1, 'id': 3, 'title': 'ea molestias quasi exercitationem repellat qui ipsa sit aut', 'body': 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut'}
"""
我们做了如下不同之处:
-
修改了 API 端点。请注意末尾不再是
1。 -
在字典中定义了载荷(payload)。
-
将载荷传递给
requests.get()方法的param参数。 -
这次返回的是列表对象,因此我们遍历该列表,并将每个条目单独换行打印。
在 Python 中发起 POST 请求
GET 请求用于检索数据;POST 请求则用于创建新数据。我们来看看如何在 JSONPlaceholder 服务器上创建新数据。
# Define new data to create
new_data = {
"userID": 1,
"id": 1,
"title": "Making a POST request",
"body": "This is the data we created."
}
# The API endpoint to communicate with
url_post = "https://jsonplaceholder.typicode.com/posts"
# A POST request to tthe API
post_response = requests.post(url_post, json=new_data)
# Print the response
post_response_json = post_response.json()
print(post_response_json)
"""
{'userID': 1, 'id': 101, 'title': 'Making a POST request', 'body': 'This is the data we created.'}
"""
在上述代码中,我们执行了以下操作:
-
创建了要添加到 JSONPlaceholder API 的新资源。
-
定义了用于
POST新数据的端点。 -
使用
requests.post()方法发送POST请求。请注意在post()方法中设置了json参数;我们这样做是为了告诉 API,我们明确地向指定的 URL 发送一个 JSON 对象。 -
使用
response.json()方法将响应数据存入字典对象。 -
最后一步是打印 JSON 响应数据。
但是,稍等!
在阅读下一段代码之前,先花 20 秒想一想,API 会返回什么状态码。
请记住:这一次,我们是创建了一个新资源,而不是仅仅检索它。
好了,答案来了……
# Print status code from original response (not JSON)
print(post_response.status_code)
"""
201
"""
Python HTTP 请求进阶主题
用 Python 发起 HTTP 请求通常很直接;不过,有时难免需要更高级的设置或会遇到问题。以下是您可能遇到的一些挑战及其解决方法。
请求认证
到目前为止,我们与 REST API 的交互都相当简单。JSONPlaceholder API 不需要任何认证即可开始使用。然而,在很多情况下,REST API 在授予对特定端点的访问之前会要求认证——尤其是在处理敏感数据时。
例如,如果您想在 GitHub 上创建集成、检索数据并自动化工作流程,您可以使用 GitHub REST API。不过,GitHub REST API 上有许多操作需要认证,例如检索关于已认证用户的公共和私有信息。
下面是一个使用 Python requests 模块的简单实现方式:
from requests.auth import HTTPBasicAuth
private_url = "https://api.github.com/user"
github_username = "username"
token = "token"
private_url_response = requests.get(
url=private_url,
auth=HTTPBasicAuth(github_username, token)
)
private_url_response.status_code
"""
200
"""
在上述代码中,我们:
-
从
requests.auth导入了HTTPBasicAuth对象。该对象会将 HTTP 基本认证附加到给定的请求对象上——本质上与在网站上输入用户名和密码相同。 -
定义了要访问的私有 URL 端点。
-
用一个 GitHub 用户名实例化了变量——出于隐私考虑,我们对用户名做了匿名化处理。
-
用一个 GitHub 个人访问令牌实例化了变量以进行认证。
-
从端点检索数据并存入
private_url_response变量。 -
显示状态码。
处理 HTTP 请求错误
有时对 API 发起的请求并不会如预期那样运行。客户端或服务器端可能存在多种因素。无论原因如何,结果都是一样的:请求失败。
在使用 REST API 时,让代码具备弹性总是个好主意。然而,在编写健壮代码之前,您必须了解当事情不按计划发展时如何管理所报告的错误。
在这个演示中,让我们回到 JSONPlaceholder API。我们先写一段代码,然后解释其运行原理。
# A deliberate typo is made in the endpoint "postz" instead of "posts"
url = "https://jsonplaceholder.typicode.com/postz"
# Attempt to GET data from provided endpoint
try:
response = requests.get(url)
response.raise_for_status()
# If the request fails (404) then print the error.
except requests.exceptions.HTTPError as error:
print(error)
"""
404 Client Error: Not Found for url: https://jsonplaceholder.typicode.com/postz
"""
在上述代码中:
-
我们定义了要检索数据的 JSONPlaceholder 端点,但在构造 URL 时有意拼错——这会引发 404 错误。
-
我们使用 Python 内置的异常处理,通过
try和except(捕获)来处理尝试访问 JSONPlaceholder 端点时出现的任何错误。请注意,raise_for_status()方法用于在过程中发生错误时返回一个HTTPError对象。 -
最后,我们打印了引发的错误。
尽管本例演示了如何处理 404 状态码,但同样的模式也可用于处理任何 HTTP 状态码。
处理过多重定向
以 3xx 开头的 HTTP 状态码表示客户端被重定向,必须执行一些额外操作才能完成请求。然而,这有时会导致无限重定向循环。
Python 的 requests 模块提供了 TooManyRedirects 对象来处理该问题,如下所示:
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
are multiple redirects
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
response.raise_for_status()
except requests.exceptions.TooManyRedirects as error:
print(error)
您也可以在 HTTP 请求方法中通过参数设置最大重定向次数:
# Solution 2
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.max_redirects = 3
response = session.get(url)
另一种选择是完全禁用重定向:
# Solution 3
url = "https://jsonplaceholder.typicode.com/posts"
session = requests.Session()
session.allow_redirects = False
response = session.get(url)
处理 HTTP 请求连接错误
在尝试向服务器发送请求时,您可能还会遇到其他类型的错误。导致服务器无响应的原因有很多(例如 DNS 失败、连接被拒、网络连接问题等),但结果是一致的:会引发连接错误。
您可以使用 requests 模块的 ConnectionError 异常对象来捕获这些问题并进行相应处理。
代码如下所示:
"""
Note: The code here will not raise an error
but the structure is how you would hand a case where there
is a connection error.
"""
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url)
except requests.ConnectionError as error:
print(error)
处理 HTTP 请求超时
当 API 服务器接受了您的连接,但无法在允许时间内完成请求时,您会收到“超时错误”。
我们将通过在 requests.get() 方法中将 timeout 参数设置为一个极小的数来演示如何处理这种情况;这将引发一个错误,我们将使用 requests.Timeout 对象来处理该错误。
url = "https://jsonplaceholder.typicode.com/posts"
try:
response = requests.get(url, timeout=0.0001)
except requests.Timeout as error:
print(error)
处理超时错误最直接的办法是设置更长的超时时间。其他解决方案还包括优化请求、在脚本中加入重试循环,或执行异步 API 调用——这是一种允许您的软件在开始可能耗时较长的活动的同时,仍能对其他事件保持响应,而不是等待该任务完成的技术。
总结
在本教程中,我们介绍了什么是 API,并探讨了一种常见的 API 架构——REST。我们还了解了 HTTP 方法,以及如何使用 Python 的 requests 库与 Web 服务交互。
查看以下课程,提升您的数据科学技能:
FAQs
如何在 Python 的 HTTP 请求中处理自定义请求头?
在 requests 模块中使用会话对象有哪些好处?
在 requests 模块中使用 Session 对象有以下好处:
- 持久连接:在多个请求之间维持连接,提升性能。
- 会话级设置:您可以为通过该会话发起的所有请求统一设置请求头、Cookie 和参数。
- Cookie 持久化:自动处理并在请求之间持久化 Cookie。
示例:
import requests
session = requests.Session()
session.headers.update({"Authorization": "Bearer YOUR_ACCESS_TOKEN"})
response = session.get("https://jsonplaceholder.typicode.com/posts")
print(response.json())
如何在 Python 中使用 POST 请求发送文件?
如何配置 requests 模块以使用代理?

应用程序编程接口(API)是软件“中介”。它们的工作是让应用程序彼此通信。这些不显眼的“中介”在日常生活中无处不在,即使您没有意识到也是如此。例如,如果您今天发过即时消息,您就用到了 API。
更具体地说,API 允许人们用代码发送和检索数据。不过,更常见的用法是通过 API 检索数据。举个例子,您之所以能读到这篇博文,是因为您的浏览器从 DataCamp 服务器检索了构成此页面的数据。
但 Web 服务器不会随机发送数据。那就好比去餐馆,服务员随便给您端上一道菜。服务器在响应数据之前,必须先接收到一个请求。餐馆里的服务员如此,如果您想从 API 检索一些数据,也需要向服务器发出一个 API 请求,服务器才会返回相应的数据。
在本文中,我们将逐步讲解
requests库的一些核心组件,并提供代码示例,帮助您快速上手。这requests库值得学习,因为它是 Python 发送 HTTP 请求的事实行业标准。正如您将看到的,它把发起请求的各种复杂性封装在一个简洁明了的 API 背后,使您可以专注于与服务通信并在应用中消费数据。