【问题标题】:Requests, Mechanize, urllib fails but cURL works请求、机械化、urllib 失败但 cURL 有效
【发布时间】:2014-11-24 21:01:21
【问题描述】:

在尝试通过请求访问 this site 时,我收到:

('Connection aborted.', error(54, 'Connection reset by peer'))

我也试过通过mechanize和urllib访问网站,都失败了。但是 cURL 可以正常工作(代码见结尾)。

我尝试了 requests.get() 与参数组合 verify=True,stream=True 并且我还尝试了带有 cURL 标头的请求。

我试图转移到 urllib / Mechanize 作为替代方案,但两者都给出了相同的错误。

我的请求代码如下:

import requests
import cookielib

url = "https://datamuster.marketdatasuite.com/Account/LogOn?ReturnUrl=%2fProfile%2fList"

header = {
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Encoding':'gzip,deflate,sdch',
    'Accept-Language':'en-US,en;q=0.8',
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36'
}

jar = cookielib.CookieJar()
s = requests.Session()
s.headers.update(header)

r = s.get(url, cookies=jar)

带有标题的 cURL 测试:

$ curl -v -I -H "....Testing: Header...." https://datamuster.marketdatasuite.com/Account/LogOn?ReturnUrl=%2fProfile%2fList

* Hostname was NOT found in DNS cache
*   Trying 54.252.86.7...
* Connected to datamuster.marketdatasuite.com (54.252.86.7) port 443 (#0)
* TLS 1.2 connection using TLS_RSA_WITH_AES_128_CBC_SHA256
* Server certificate: datamuster.marketdatasuite.com
* Server certificate: COMODO SSL CA
* Server certificate: AddTrust External CA Root
> HEAD /Account/LogOn?ReturnUrl=%2fProfile%2fList HTTP/1.1
> User-Agent: curl/7.37.1
> Host: datamuster.marketdatasuite.com
> Accept: */*
> ....Testing: Header....
> 
< HTTP/1.1 200 OK

【问题讨论】:

    标签: curl python-requests urllib http-get mechanize-python


    【解决方案1】:

    服务器需要使用SNI,如果没有使用 SNI 则关闭连接。看起来 curl 使用了 SNI,而至少您正在使用的 requests 库的版本不使用 SNI。

    您可以尝试使用 OpenSSL。如果没有 SNI,你会得到一个错误:

    $ openssl s_client -connect datamuster.marketdatasuite.com:443
    CONNECTED(00000003)
    write:errno=104
    

    但如果你使用 SNI (-servername ...) 就可以了:

    CONNECTED(00000003)
    depth=1 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO SSL CA
    ...
    SSL-Session:
        Protocol  : TLSv1.2
        Cipher    : AES128-SHA256
    

    根据FAQ for request SNI 不支持 Python 2,仅支持 Python 3。有关如何使用 Python 2 实现 SNI 的信息,请参阅此资源。

    【讨论】:

      【解决方案2】:

      这个过程并不完全简单,所以我想我会发布一个新答案,以便其他人可以轻松理解。

      Following this thread,我需要安装这些库才能让 SNI 与 Python 2 一起工作:

      但是,pyOpenSSL 在使用pip install pyOpenSSL 安装时可能会导致问题。实际上,我不得不删除我现有的 openssl,因为 pyOpenSSL 0.14 版似乎不起作用:

      pip uninstall pyOpenSSL
      

      以下命令安装了所有必要的依赖项:

      pip install pyOpenSSL==0.13 ndg-httpsclient pyasn1
      

      这应该让请求现在可以在 python 2 上使用 SNI。


      继续阅读有关 pyOpenSSL 版本的问题。 0.14...

      安装版本时。 0.14 我得到以下错误:

      Command /usr/local/opt/python/bin/python2.7 -c "import setuptools, tokenize;__file__='/private/var/folders/04/3f_y5fw166v03k7b51j1tsl80000gn/T/pip_build_alex/cryptography/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /var/folders/04/3f_y5fw166v03k7b51j1tsl80000gn/T/pip-7QR71B-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /private/var/folders/04/3f_y5fw166v03k7b51j1tsl80000gn/T/pip_build_alex/cryptography
      Storing debug log for failure in /Users/alex/.pip/pip.log
      

      并且 pyOpenSSL 安装为版本。 0.14 不完全:

      $ pip show pyOpenSSL
      ---
      Name: pyOpenSSL
      Version: 0.14
      Location: /usr/local/lib/python2.7/site-packages
      Requires: cryptography, six
      

      从requests.get()尝试中可以看出:

      import requests
      response = requests.get("http://datamuster.marketdatasuite.com")
      
      (...lots of errors...)
          raise ConnectionError(err, request=request)
      requests.exceptions.ConnectionError: ('Connection aborted.', error(54, 'Connection reset by peer'))
      

      以下命令恢复为 pyOpenSSL 版本。 0.13 并修正问题

      pip uninstall pyOpenSSL
      pip install pyOpenSSL==0.13
      

      然后在python中:

      import requests
      requests.get("http://datamuster.marketdatasuite.com")
      
      <Response [200]>
      

      【讨论】:

        【解决方案3】:

        我在使用 Python 请求向 WordPress 发送测试请求时遇到了同样的问题(我在专用服务器上安装了 WordPress)。 我尝试更新 SSL- 包但没有成功。

        然后,我意识到发送到服务器的请求在接收响应时出现延迟。长时间的延迟请求总是“启动”并导致('连接中止。',错误(54,'对等连接重置'))。 事实证明,Web 服务器 (apache) 在请求仍在等待响应时重置了连接。

        我将 KeepAliveTimeout 从 5 秒增加到 20 秒(在 Apache Web 服务器中)并且再也不会出现此错误。

        改进异常代码: 增加 KeepAliveTimeout 在大多数测试中都有效。但是,在某些测试中,我仍然遇到相同的错误并且程序停止。我添加了捕获异常的代码并重复它发生的请求。

        import requests
        ...
        while(1):
            requestOK = True
            try:
               r = session.get(requestURL, headers=headers, timeout=None)
            except requests.exceptions.ConnectionError: 
               print ("'Connection aborted.', error(54, 'Connection reset by peer')")
               print ("\tResend request...")
               requestOK = False
            if requestOK:
               break
        

        希望这会有所帮助!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-14
          • 2014-09-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多