Python 请求很慢并且需要很长时间才能完成 HTTP 或 HTTPS 请求

Posted

技术标签:

【中文标题】Python 请求很慢并且需要很长时间才能完成 HTTP 或 HTTPS 请求【英文标题】:Python requests is slow and takes very long to complete HTTP or HTTPS request 【发布时间】:2020-10-17 07:24:51 【问题描述】:

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

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

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

【问题讨论】:

在您的浏览器中花费的时间是否相似? 还是服务器很慢? 谢谢你们的回复。我已经确定了我的问题,但由于我正在寻找解决方案的 odyssee,我想向 SO 提供我在途中检查过的所有可能的问题。在下面找到我的答案,如果有帮助请告诉我! 【参考方案1】:

这个问题可以有多种可能的解决方案。 *** 上有很多关于这些的答案,所以我会尝试将它们全部组合起来,以免您搜索它们的麻烦。

在我的搜索中,我发现了以下几层:

首先,尝试记录

对于许多问题,激活日志记录可以帮助您发现问题所在 (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")

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

如果只需要检查服务器是否启动,请尝试 HEAD 或流式请求

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

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

有些服务器不支持这个,那么你可以尝试流式响应(source):

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

对于连续的多个请求,尝试使用 Session

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

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

要并行化您的请求(尝试超过 10 个请求),请使用 requests-futures

如果您一次发送大量请求,每个请求都会阻止执行。您可以使用例如requests-futures(来自kederrac 的想法)并行化:

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()

注意不要同时有太多请求使服务器不堪重负。

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

原因可能不在于请求,而在于服务器或您的连接

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

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

如果一切正常,您可以将精力集中在以下可能出现的问题上:

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

服务器可能会专门阻止requests,或者他们可能会利用白名单或其他原因。要发送更好的用户代理字符串,试试这个 (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()

服务器响应格式错误,导致解析问题

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

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

要解决这些问题,请尝试:

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)

如果返回成功响应,则问题应该出在 IPv6 上。原因是requests 首先尝试 IPv6 连接。当超时时,它会尝试通过 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

如果一切正常,您就找到了问题!但是你问怎么解决呢?

    蛮力解决方案是完全disable IPv6。 您也只能disable IPv6 for the current session。 您可能只想force requests to use IPv4。 (在链接的答案中,您必须调整代码以始终为 IPv4 返回 socket.AF_INET。) 如果你想为 SSH 解决这个问题,这里是force IPv4 for SSH 的方法。 (简而言之,将 AddressFamily inet 添加到您的 SSH 配置中。) 您可能还想检查问题是否出在您的DNS or TCP 上。

【讨论】:

对我来说 timeout 修复了它,即使 wgetcurl 使用 IPv6。修改 ***.com/a/46972341/4339170 强制 IPv4 这太邪恶了!你有没有追根究底,你到底有什么问题? 在 micropython 的 urequests 中遇到了这个问题,解决方法是添加 'Connection': 'Close' 的标头。一些服务器不发送 Content-Length 或发送错误的。告诉它关闭连接,确实解决了我的问题(10+秒到1秒)github.com/micropython/micropython-lib/issues/293 好帖子!这对我有用(因为 requests 需要花费大量时间来推断字符集): r = requests.get("example.com") r.raw.chunked = True # Fix issue 1 r.encoding = 'utf-8' # 修复问题 2 我遇到了 IPv6 路由问题timeout 修复了它

以上是关于Python 请求很慢并且需要很长时间才能完成 HTTP 或 HTTPS 请求的主要内容,如果未能解决你的问题,请参考以下文章

Python: Pandas - 嵌套循环需要很长时间才能完成。如何加快速度?

什么是 SNIReadSyncOverAsync,为什么需要很长时间才能完成?

什么是 SNIReadSyncOverAsync,为什么需要很长时间才能完成?

什么是 SNIReadSyncOverAsync,为什么需要很长时间才能完成?

在 Oracle 中处理删除逻辑需要很长时间

谷歌图表需要很长时间才能加载