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

发布于 2021-01-29 17:59:35

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

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

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

关注者
0
被浏览
209
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    这个问题可以有多种可能的解决方案。关于StackOverflow的答案很多,因此,我将尝试将它们全部组合起来,以免您寻找它们的麻烦。

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

    首先,尝试登录

    对于许多问题,激活日志记录可以帮助您发现问题所在(源代码):

    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)
    

    对于连续多个请求,请尝试利用会话

    如果您连续发送多个请求,则可以使用来加快请求的速度requests.Session。这样可以确保与服务器的连接保持打开和配置状态,并且还保留cookie,这是一个不错的好处。试试这个:

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

    要并行处理您的请求(尝试10个以上的请求),请使用requests-futures

    如果您一次发送大量请求,则每个请求都会阻止执行。您可以利用例如request-
    futures
    并行化它:

    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)
    

    服务器限速

    如果有时仅在某些情况下(例如,在几次请求后)出现此问题,则服务器可能会限制您的速率。检查响应,看是否沿这些方向读取某些内容(即“达到速率限制”,“超出工作队列深度”或类似内容;)。

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

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

    您可以通过不阅读从服务器收到的响应来进行检查。如果代码仍然很慢,这不是您的问题,但是如果此问题得以解决,则问题可能出在解析响应上。

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

    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
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看