【问题标题】:Python: requests.exceptions.ConnectionError. Max retries exceeded with urlPython:requests.exceptions.ConnectionError。 url 超出了最大重试次数
【发布时间】:2013-08-30 22:37:54
【问题描述】:

这是脚本:

import requests
import json
import urlparse
from requests.adapters import HTTPAdapter

s = requests.Session()
s.mount('http://', HTTPAdapter(max_retries=1))

with open('proxies.txt') as proxies:
    for line in proxies:
        proxy=json.loads(line)

    with open('urls.txt') as urls:
        for line in urls:

            url=line.rstrip()
            data=requests.get(url, proxies=proxy)
            data1=data.content
            print data1
            print {'http': line}

如您所见,它试图通过代理列表访问 url 列表。这是 urls.txt 文件:

http://api.exip.org/?call=ip

这里是 proxies.txt 文件:

{"http":"http://107.17.92.18:8080"}

我在 www.hidemyass.com 获得了这个代理。它可能是一个糟糕的代理吗?我已经尝试了几个,这就是结果。注意:如果您尝试复制此内容,您可能需要在 hidemyass.com 上将代理更新为最近的代理。他们似乎最终停止工作。 这是完整的错误和回溯:

Traceback (most recent call last):
  File "test.py", line 17, in <module>
    data=requests.get(url, proxies=proxy)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 335, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 454, in send
    history = [resp for resp in gen] if allow_redirects else []
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 144, in resolve_redirects
    allow_redirects=False,
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 438, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 327, in send
    raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPConnectionPool(host=u'219.231.143.96', port=18186): Max retries exceeded with url: http://www.google.com/ (Caused by <class 'httplib.BadStatusLine'>: '')

【问题讨论】:

  • 您的示例中的缩进是否正确?
  • 因为for 循环的主体没有缩进。这似乎会给我一个 IndentationError 。
  • 哦,你的权利。我把代码复制错了。但问题仍然存在。
  • 您的循环仍然不正确。当前代码只会使用 proxies.txt 中列出的最后一个代理。
  • 我的 ISP 代理出现了完全错误。我只使用一个特定的 url(POST 请求)看到了这个问题。我可以通过禁用代理来完成请求:proxies={'https':None}(使用 https)。

标签: python python-requests


【解决方案1】:

查看您提供的堆栈跟踪,您的错误是由httplib.BadStatusLine 异常引起的,根据docs,它是:

如果服务器以我们不理解的 HTTP 状态代码响应,则引发。

换句话说,代理服务器返回的东西(如果返回的话)不能被执行实际请求的 httplib 解析。

根据我在(编写)http 代理方面的经验,我可以说某些实现可能不会太严格地遵循规范(http 上的 rfc 规范实际上并不容易阅读),或者使用 hack 来修复在实现中存在缺陷的旧浏览器。

所以,回答这个问题:

它可能是一个坏代理吗?

...我会说 - 这是可能的。唯一确定的方法是查看代理服务器返回的内容。

尝试使用调试器或抓取数据包嗅探器(例如WiresharkNetwork Monitor)对其进行调试,以分析网络中发生的情况。了解代理服务器返回的确切信息应该可以为您提供解决此问题的关键。

【讨论】:

  • 我没有使用httplib,除非它包含在请求库中?除此之外,您是说我的请求通过代理服务器到达网页,然后返回代理服务器,然后该代理服务器试图中继给我的内容是不可读的?
  • @BigBoy1337 about httplib: 似乎它是间接使用的(无论如何,您在回溯中确实有例外)。关于“您是说我的请求通过代理服务器到达网页,然后返回代理服务器,然后该代理服务器试图中继给我的内容是不可读的?”:这是可能的,但不是必需的。目前我们所知道的是代理的回复无效。 ...
  • ... 代理可能在将请求发送到最终 Web 服务器之前遇到了一些内部错误,因此代理回复无效回复。在 Web 服务器以有效回复对代理进行回复后,此内部错误也可能发生在代理中。最重要的是,Web 服务器可能以无效的依赖回复代理,这反过来又导致来自代理的无效回复。正如我在回答中所说 - 找出根本原因的最直接方法是获取更多关于从代理实际回复的数据。
  • “url 超出的最大重试次数”是否提供了任何可能的线索?那意味着什么?听起来代理试图向网络服务器发出请求,但它一直告诉它再试一次(导致一些错误)。
  • @BigBoy1337 不是真的。您的引用可以解释为:未能执行请求(“Max retries exceeded with url [...]”部分错误消息)由于 httplib.BadStatusLine 之前某处引发异常(“由 [...]” 部分错误消息引起)。请注意,没有关于引发 httplib.BadStatusLine 原因的信息(文档除外)。
【解决方案2】:

也许您在短时间内发送过多请求而使代理服务器超载,您说您从一个流行的免费代理网站获得代理,这意味着您不是唯一使用该服务器的人,而且经常承受重负荷。

如果您像这样在请求之间添加一些延迟:

from time import sleep

[...]

data=requests.get(url, proxies=proxy)
data1=data.content
print data1
print {'http': line}
sleep(1)

(注意sleep(1) 暂停代码执行一秒钟)

有效吗?

【讨论】:

  • 请求总是在末尾添加异常的原始原因。 requests.exceptions.ConnectionError: HTTPConnectionPool(host=u'219.231.143.96', port=18186): Max retries exceeded with url: google.com (Caused by : '') 在这个例子中。 (由 : '' 引起)这意味着按照提供的答案计时更多未处理的 HTTP 不会有问题。
  • @MattPsyK 当我同时发送太多请求时,我在一个流行的网站(运行标准 Apache)上多次遇到此“BadStatusLine”异常(sleep() 技巧对我有用) ,所以这里可能是同样的问题...
  • @BigBoy1337。尝试增加睡眠时间或限制您从服务器请求的文件数量。
【解决方案3】:
def hello(self):
    self.s = requests.Session()
    self.s.headers.update({'User-Agent': self.user_agent})
    return True

试试这个,它对我有用:)

【讨论】:

    【解决方案4】:

    当您向https://anydomainname.example.com/ 的公共 IP 地址发送过多请求时,会发生这种情况。正如您所看到的,由于某些原因不允许/阻止使用https://anydomainname.example.com/ 映射访问公共 IP 地址。一个更好的解决方案是以下 python 脚本,它计算任何域的公共 IP 地址并创建该映射到 /etc/hosts 文件。

    import re
    import socket
    import subprocess
    from typing import Tuple
    
    ENDPOINT = 'https://anydomainname.example.com/'
    
    def get_public_ip() -> Tuple[str, str, str]:
        """
        Command to get public_ip address of host machine and endpoint domain
        Returns
        -------
        my_public_ip : str
            Ip address string of host machine.
        end_point_ip_address : str
            Ip address of endpoint domain host.
        end_point_domain : str
            domain name of endpoint.
    
        """
        # bash_command = """host myip.opendns.com resolver1.opendns.com | \
        #     grep "myip.opendns.com has" | awk '{print $4}'"""
        # bash_command = """curl ifconfig.co"""
        # bash_command = """curl ifconfig.me"""
        bash_command = """ curl icanhazip.com"""
        my_public_ip = subprocess.getoutput(bash_command)
        my_public_ip = re.compile("[0-9.]{4,}").findall(my_public_ip)[0]
        end_point_domain = (
            ENDPOINT.replace("https://", "")
            .replace("http://", "")
            .replace("/", "")
        )
        end_point_ip_address = socket.gethostbyname(end_point_domain)
        return my_public_ip, end_point_ip_address, end_point_domain
    
    
    def set_etc_host(ip_address: str, domain: str) -> str:
        """
        A function to write mapping of ip_address and domain name in /etc/hosts.
        Ref: https://stackoverflow.com/questions/38302867/how-to-update-etc-hosts-file-in-docker-image-during-docker-build
    
        Parameters
        ----------
        ip_address : str
            IP address of the domain.
        domain : str
            domain name of endpoint.
    
        Returns
        -------
        str
            Message to identify success or failure of the operation.
    
        """
        bash_command = """echo "{}    {}" >> /etc/hosts""".format(ip_address, domain)
        output = subprocess.getoutput(bash_command)
        return output
    
    
    if __name__ == "__main__":
        my_public_ip, end_point_ip_address, end_point_domain = get_public_ip()
        output = set_etc_host(ip_address=end_point_ip_address, domain=end_point_domain)
        print("My public IP address:", my_public_ip)
        print("ENDPOINT public IP address:", end_point_ip_address)
        print("ENDPOINT Domain Name:", end_point_domain )
        print("Command output:", output)
    

    你可以在运行你想要的函数之前调用上面的脚本:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-03
      • 1970-01-01
      • 2020-03-16
      • 1970-01-01
      • 2022-08-11
      • 2020-07-11
      • 2018-11-04
      • 2021-04-03
      相关资源
      最近更新 更多