使用请求库请求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相关问答推荐

Pyvis和Networkx:如何根据源或目标使 node colored颜色 不同

使用递归将int转换为字符串

从Metacritic上通过网络擦除游戏数据的问题

在循环中使用Print&S结束参数时出现奇怪的问题

visual studio代码窗口中未激活虚拟环境11

检测点坐标 - opencv findContours()

基于其他列的条件向Panda数据框中添加值到新列

如何查找以开头并替换的字符串

将值从函数传递到标签

将逗号分隔的字符串类型系列转换为整数列表 pandas

将元组列表转换为以整个元组为键的字典列表

将字典列表展平为数据框列

无法使用 Python 和 Selenium 检索 href 属性

例外:使用 Pyinstaller 时找不到 PyQt5 插件目录,尽管 PyQt5 甚至没有被使用

python 3中的SQLAlchemy ER图

Tkinter AttributeError:对象没有属性'tk'

Python3 的超级和理解-> TypeError?

Python在OrderedDict中 Select 第i个元素

python判断一个方法是否被调用而不模拟它

如何创建一个永远在其上运行滚动协程的事件循环?