请求,Mechanize,urllib失败,但cURL工作

时间:2014-11-24 21:01:21

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

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

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

我还尝试通过mechanize和urllib访问该网站,两者都失败了。但是cURL工作正常(请参阅end代码)。

我尝试了requests.get()参数verify=Truestream=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

3 个答案:

答案 0 :(得分:3)

服务器需要使用SNI,如果没有使用SNI,则只关闭连接。看起来像curl使用SNI,而至少你使用的请求库的版本不使用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成为可能的信息,请参阅此资源。

答案 1 :(得分:2)

这个过程并不是那么简单,所以我想我会发布一个新的答案,让其他人更容易理解。

Following this thread,我需要安装这些库,让SNI与Python 2一起使用:

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

pip uninstall pyOpenSSL

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

pip install pyOpenSSL==0.13 ndg-httpsclient pyasn1

这应该可以获得在python 2上使用SNI的请求。


继续阅读pyOpenSSL ver的问题。 0.14 ...

安装ver时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安装为ver。 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 ver。 0.13并更正问题

pip uninstall pyOpenSSL
pip install pyOpenSSL==0.13

然后在python:

import requests
requests.get("http://datamuster.marketdatasuite.com")

<Response [200]>

答案 2 :(得分:1)

使用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

希望这会有所帮助!