发出 HTTP 请求对于应用程序与网络交互的方式至关重要。如果您正在使用 Python,无论是构建网络爬虫、使用 RESTful API,还是需要以其他方式与网络交互,Python 的第三方 Requests 模块都是最流行、最易用的选择。

在本篇文章中,我们将使用 Requests 模块探索三个层次的 HTTP 请求,从基础知识开始,逐步深入到高级技术。最后,您就可以在生产中使用 Requests 了!

第 1 层:基本 HTTP 请求

在基础层,我们有基本的 HTTP 请求。这些请求是需要与网络服务交互的 Python 开发人员的基本需求。Requests 模块让执行 GET 和 POST 请求变得异常简单,让您可以毫不费力地检索网页或向服务器发送数据。

首先,将 Requests 安装到你选择的虚拟环境中:

python3 -m venv venv-requests-vonage

../venv-requests-vonage/bin/activate

pip install -U pip requests

激活虚拟环境并安装 Requests 后,就可以立即开始使用了。下面是一个获取网页内容的 GET 请求示例:

import requests

response = requests.get('https://example.com')

print(response.text)

运行上述代码后,您将看到 https://example.com 页面的全部 HTML 代码。但我们能做的不仅仅是通过请求获取网页!

下面是一个 POST 请求,我们将数据发送到一个 URL:

import requests

data = {'vonage': 'loves', 'python': '!'}
response = requests.post('https://httpbin.org/post', json=data)

print(response.json()

我们可以在下面看到序列化为 Python 字典的响应。请注意,其中包含了我们发布的数据:

{
    'args': {},
    'data': '{"vonage": "loves", "python": "!"}',
    'files': {},
    'form': {},
    'headers': {
        'Accept': '*/*',
        'Accept-Encoding': 'gzip, deflate',
        'Content-Length': '34',
        'Content-Type': 'application/json',
        'Host': 'httpbin.org',
        'User-Agent': 'python-requests/2.31.0',
        'X-Amzn-Trace-Id': 'Root=1-65012480-007aeecf146f5ff007c7678d'
    },
    'json': {
        'python': '!',
        'vonage': 'loves'
    },
    'origin': '82.30.197.62',
    'url': 'https://httpbin.org/post'
}

有了这些简单的示例,您就可以开始用 Python 创建 HTTP 请求了。但如果您需要在多个请求中持续设置或共享资源,该怎么办呢?这就是第 2 级的用武之地!

第 2 层:使用会话进行持久化

HTTP 会话是一种在对同一服务器的多个请求中持久设置的方法。会话使用连接池,这意味着如果你向同一主机发出多个 HTTP 调用,你将使用相同的资源,并能显著提高性能!

如果上述两种情况都适用于你,你可能会想使用会话:

  • 你需要维护有状态的连接,比如在使用经过验证的 API 或网络应用程序时。
  • 你向同一个 API/主机发出了许多请求,而且不想浪费时间和资源。

Requests 模块提供了一个 Session 对象,让你可以做到这一点。下面是一个示例:

import requests

# 创建会话
session = requests.Session()
# 设置每次请求都要发送的头信息
session.headers.update({'Accepts': 'application/json'})
# 在同一会话中执行多个请求
response1 = session.get('https://example.com/some-page')
response2 = session.get('https://example.com/some-other-page')

这样使用会话意味着我们设置的任何 cookie 都将被持久化。我们还可以通过将默认值添加到会话对象来为会话设置默认值,就像上面我们发送的头那样。

下面是一个使用 HTTP 会话的性能优势示例。下面的代码没有使用会话,而是对 Vonage 的 Number Insight API 进行了 100 次单独的 API 调用,以查找 100 个不同电话号码的信息,并将其转换为国际 E.164 格式:

import requests
import time

start_time = time.perf_counter()
number_conversions = {}
params = {'api_key': 'MY_API_KEY', 'api_secret': 'MY_API_SECRET', 'country': 'GB'}

for i in range(100):
    phone_number = str(1614960100 + i)
    params['number'] = phone_number
    
    with requests.get(
        'https://api.nexmo.com/ni/basic/json',
        params=params,
    ) as response:
        number_conversions[phone_number] = response.json()[
            'international_format_number'
        ]
elasped_time = time.perf_counter() - start_time

print(f'Time elapsed is: {elasped_time} seconds.')

输出结果如下所用时间为:11.103735665994463 秒。因此,运行 100 次 API 调用耗时超过 11 秒,这并不可怕,但可以做得更好。

如果我们在调用 Number Insight API 时使用会话对象,就会发现其中的差别:

with requests.Session() as session:
    for i in range(100):
        phone_number = str(441614960100 + i)
        params['number'] = phone_number
    
        with session.get(
            'https://api.nexmo.com/ni/basic/json',
            params=params,
        ) as response:
            number_conversions[phone_number] = response.json()[
                'international_format_number'
            ]

这一次,我们得到了这样的输出结果:所用时间为:4.058261167003366 秒,几乎快了三倍!从这个程序的冰柱图中我们可以看到,我们的系统在连接池上花费的时间按比例来说更少了,而且所用时间的使用效率要比我们像上面那样发出 100 个单独请求时高得多。

通过使用会话,你可以自动处理 cookie 和头等事项,使代码更简洁、更高效。但如果你需要对 HTTP 请求进行更多控制,或者想对连接进行微调,该怎么办呢?这就是第三级了。

第三层:利用 HTTP 适配器进行高级设置

现在,我们已经准备好进入最高级别,即在最底层自定义 HTTP 请求的行为,包括连接池和重试等设置。通过使用 HTTP 适配器,Requests 允许我们设置这些底层属性。您可以将 HTTP 适配器挂载到会话对象上,以便在整个会话中使用自定义设置。在 Requests 中,我们使用一个名为 HTTPAdapter 的对象来实现这一功能。

下面介绍如何使用 HTTPAdapter 对象配置自定义设置:

import requests
from requests.adapters import HTTPAdapter

session = requests.Session()
# 创建 HTTPAdapter 对象并配置连接池和重试
adapter = HTTPAdapter(pool_connections=20, pool_maxsize=5, max_retries=3)
# 将 HTTPAdpater 对象挂载到会话中
session.mount('https://', adapter)
response = session.get('https://example.com')

这也可以与超时(例如 session.get('https://example.com',timeout=10))等特定请求值相结合,对每个请求进行细粒度控制。使用 HTTP 适配器可以控制 HTTP 请求的发出方式,从而可以对应用程序的行为进行微调,以满足特定需求。

在这篇博文中,我们使用 Python 的 Requests 模块探索了 HTTP 请求的三个层次,从基本请求到使用会话和 HTTP 适配器的高级定制。掌握了这三个层次,您就可以在 Python 项目中处理各种与 Web 相关的任务了。

请记住,每个级别都建立在前一个级别的基础上,因此请从基础开始,并随着项目需求的发展逐步提高级别。HTTP 请求是网络开发的基本要素,有了 Requests 模块,您就拥有了有效处理 HTTP 请求的强大工具。

最后修改:2024 年 03 月 24 日
本站福利|微信扫描二维码,永久享受 96 折充话费电费