使用请求库请求web资源、网站或web服务时,请求需要很长时间才能完成.代码类似于以下内容:

import requests
requests.get("https://www.example.com/")

此请求需要2分钟(正好2分10秒)才能完成!为什么它这么慢?我该如何修复它?

推荐答案

这个问题有多种可能的解决方案.关于StackOverflow有很多答案,所以我将try 将它们结合起来,以避免您搜索它们的麻烦.

在我的研究中,我发现了以下几层:

First, try logging

对于许多问题,激活日志(log)可以帮助您发现问题所在(source):

import requests
import logging

import http.client
http.client.HTTPConnection.debuglevel = 1

# You must initialize logging, otherwise you'll not see debug output.
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

requests.get("https://www.example.com")

如果调试输出不能帮助您解决问题,请继续阅读.

如果只需要判断服务器是否已启动,请try HEAD或流媒体请求

不请求所有数据,只发送HEAD请求(source)会更快:

requests.head("https://www.example.com")

有些服务器不支持此功能,那么您可以try 流式传输响应(source):

requests.get("https://www.example.com", stream=True)

对于一行中的多个请求,请try 使用一个会话

如果连续发送多个请求,可以使用requests.Session来加快请求速度.这可以确保与服务器的连接保持打开和配置状态,并将Cookie持久化,这是一个很好的好处.试试这个(source):

import requests
session = requests.Session()
for _ in range(10):
    session.get("https://www.example.com")

To parallelize your requests (try for > 10 requests), use requests-futures

如果一次发送大量请求,每个请求都会阻止执行.你可以将其并行化,例如requests-futures(来自kederrac的 idea ):

from concurrent.futures import as_completed
from requests_futures.sessions import FuturesSession

with FuturesSession() as session:
    futures = [session.get("https://www.example.com") for _ in range(10)]
    for future in as_completed(futures):
        response = future.result()

小心不要同时用太多的请求淹没服务器.

如果这也不能解决你的问题,请继续阅读...

The reason might not lie with requests, but the server or your connection

在许多情况下,原因可能在于您请求的服务器.首先,通过以相同方式请求任何其他URL来验证这一点:

requests.get("https://www.google.com")

如果效果良好,您可以将精力集中在以下可能的问题上:

服务器只允许特定的用户代理字符串

服务器可能会专门阻止requests,或者他们可能会利用白名单,或者其他一些原因.要发送更好的用户代理字符串,请try 以下(source):

headers = {"User-Agent": "Mozilla/5.0 (X11; CrOS x86_64 12871.102.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.141 Safari/537.36"}
requests.get("https://www.example.com", headers=headers)

服务器速率限制了你

如果这个问题只是偶尔出现,例如在几个请求之后,服务器可能会限制您的速率.判断响应,看看它是否读到了类似的内容(即"达到速率限制"、"超过工作队列深度"或类似内容;source).

在这里,解决方案只是在请求之间等待更长时间,例如使用time.sleep().

服务器响应的格式不正确,导致解析问题

您可以通过不读取从服务器收到的响应来判断这一点.如果代码仍然很慢,这不是你的问题,但如果这解决了它,问题可能在于解析响应.

  1. 如果某些标题设置不正确,这可能会导致分析错误,从而阻止分块传输(source).
  2. 在其他情况下,手动设置编码可能会解决解析问题(source).

要解决这些问题,请try :

r = requests.get("https://www.example.com")
r.raw.chunked = True # Fix issue 1
r.encoding = 'utf-8' # Fix issue 2
print(response.text)

IPv6不起作用,但IPv4起作用

这可能是最糟糕的问题.一种简单但奇怪的判断方法是添加一个timeout参数,如下所示:

requests.get("https://www.example.com/", timeout=5)

如果返回successful response,问题应该出在IPv6上.原因是requests先try IPv6连接.当超时时,它会try 通过IPv4连接.通过将超时设置为较低,可以强制它在较短的时间内切换到IPv4.

通过使用例如wgetcurl进行验证:

wget --inet6-only https://www.example.com -O - > /dev/null
# or
curl --ipv6 -v https://www.example.com

在这两种情况下,我们都会强制工具通过IPv6连接,以隔离问题.如果超时,请重试强制IPv4:

wget --inet4-only https://www.example.com -O - > /dev/null
# or
curl --ipv4 -v https://www.example.com

如果这一切正常,你已经发现了你的问题!但你会问,如何解决这个问题?

  1. 蛮力解决方案是完全disable IPv6.
  2. 你也可以只买disable IPv6 for the current session件.
  3. 你可能只想要force requests to use IPv4美元.(在链接的答案中,您必须调整代码,使IPv4始终返回socket.AF_INET.)
  4. 如果您想解决SSH的这个问题,下面是如何解决这个问题.(简而言之,将AddressFamily inet添加到SSH配置中.)
  5. 您可能还想判断问题是否出在您的DNS or TCP.

Python-3.x相关问答推荐

使用pythonnet和nicegui时无法pickle December对象

使用pybind11时,在sys.exit(0)处成功完成测试后,Python单元测试冻结

循环遍历数据框以提取特定值

无法使用Python slack 螺栓SDK读取在 slack 通道中收到的消息

按一列分组,如果日期列相同,则在数字列中填写缺少的值

我正在try 从 10*3 矩阵中删除随机值并将其变为 10*2 矩阵

合并两个数据帧并对某些总和进行求和

GUI 仍然有效并且没有错误消息时图形意外冻结 |具有多线程的 Pyside6 和 pyqtgraph (Python 3.11.4)

!date 的命令无法从 jupyter notebook 运行

如何使用 django rest 框架在 self forienkey 中删除多达 n 种类型的数据?

如何通过 GitLab V4 api 列出 gitlab 项目中的所有项目变量

Pandas DataFrame:使用 Pandas 将 NaN 值替换为 3 行以上的平均值

Python 3 `str.__getitem__` 的计算复杂度是多少?

在 Django 中执行 JSONRenderer.render(serialized_student_data.data) 时遇到问题

`pyspark mllib` 与 `pyspark ml` 包

TimescaleDB:是否可以从 Python 调用create_hypertable?

PyQt:退出时没有错误消息(回溯)

在 Python 3 中使用 unittest.mock 修补 input()

如何删除目录? os.removedirs 和 os.rmdir 是否只用于删除空目录?

Python:如何在 Windows 资源管理器中打开文件夹(Python 3.6.2、Windows 10)