【问题标题】:Downloading HTTPS pages with urllib, error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error使用 urllib 下载 HTTPS 页面,错误:14077438:SSL 例程:SSL23_GET_SERVER_HELLO:tlsv1 警报内部错误
【发布时间】:2015-11-28 14:54:02
【问题描述】:

我正在使用最新的KubuntuPython 2.7.6。我尝试使用以下代码下载https 页面:

import urllib2

hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
       'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
       'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
       'Accept-Encoding': 'none',
       'Accept-Language': 'pl-PL,pl;q=0.8',
       'Connection': 'keep-alive'}

req = urllib2.Request(main_page_url, headers=hdr)

try:
    page = urllib2.urlopen(req)
except urllib2.HTTPError, e:
    print e.fp.read()

content = page.read()
print content

但是,我收到这样的错误:

Traceback (most recent call last):
  File "test.py", line 33, in <module>
    page = urllib2.urlopen(req)
  File "/usr/lib/python2.7/urllib2.py", line 127, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 404, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 422, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 382, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1222, in https_open
    return self.do_open(httplib.HTTPSConnection, req)
  File "/usr/lib/python2.7/urllib2.py", line 1184, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [Errno 1] _ssl.c:510: error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error>

如何解决这个问题?

已解决!

我使用了@SteffenUllrich 提供的网址https://www.ssllabs.com。原来服务器使用的是TLS 1.2,所以我将python更新到2.7.10,并将我的代码修改为:

import ssl
import urllib2

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
       'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
       'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
       'Accept-Encoding': 'none',
       'Accept-Language': 'pl-PL,pl;q=0.8',
       'Connection': 'keep-alive'}

req = urllib2.Request(main_page_url, headers=hdr)

try:
    page = urllib2.urlopen(req,context=context)
except urllib2.HTTPError, e:
    print e.fp.read()

content = page.read()
print content

现在它会下载页面。

【问题讨论】:

  • 您的脚本适用于我的 Python 2.7.10 和 https://facebook.com。你尝试什么网址?一个 URL 或多个 https 会发生这种情况吗?
  • @MartinVseticka:对我来说也适用于 facebook,所以这可能是页面问题。现在呢?
  • 不,不是。但是如果不能重现错误就更难了,所以有人会回答你的问题的机会会更低。无论如何,如果 curl (或任何其他工具)发生同样的情况,请尝试。我的猜测是问题出在 openssl 端而不是 Python 端。

标签: python python-2.7 ssl


【解决方案1】:

我正在使用最新的 Kubuntu 和 Python 2.7.6

据我所知,最新的 Kubuntu (15.10) 使用的是 2.7.10。但假设您使用 14.04 LTS 中包含的 2.7.6:

对我来说也适用于 facebook,所以这可能是页面问题。现在怎么办?

那么这取决于网站。此版本 Python 的典型问题是缺少对仅添加到 Python 2.7.9 的 Server Name Indication (SNI) 的支持。由于现在很多网站都需要 SNI(就像所有使用 Cloudflare Free SSL 的网站一样)我猜这就是问题所在。

但是,还有其他可能性,例如 multiple trust path,它仅在 OpenSSL 1.0.2 中得到修复。或者只是缺少中间证书等。只有提供 URL 或根据此信息和SSLLabs 的分析自行分析情况,才能获得更多信息和解决方法。

【讨论】:

  • 是的,它的 Kubuntu 14.04,我的 OpenSSL 是 OpenSSL 1.0.1f 2014 年 1 月 6 日
  • 非常感谢。我使用了您发布的 SSLLabs 页面,并检查了该页面使用的 TLS 版本。结果是它的 TLS 1.2。我修改了代码,将编辑我的第一篇文章并添加修改后的代码和解释。谢谢!
  • @yak:因为 Python 2.7.6 也支持 TLS 1.2。在 (K)ubuntu 14.04 中,我的猜测是升级到 Python 2.7.10 只是解决了 SNI 问题,这就是它起作用的原因。尽管如此,它仍然有效。
【解决方案2】:

旧版python 2.7.3 使用

requests.get(download_url, headers=headers, timeout=10, stream=True)

得到以下警告和异常:

You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
SSLError(SSLError(1, '_ssl.c:504: error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error')

只要听从建议,访问 Certificate verification in Python 2

运行

pip install urllib3[secure]

问题解决了。

【讨论】:

    【解决方案3】:

    上面的答案只是部分正确,你可以添加一个修复来解决这个问题:

    代码:

    def allow_unverified_content():
        """
        A 'fix' for Python SSL CERTIFICATE_VERIFY_FAILED (mainly python 2.7)
        """
        if (not os.environ.get('PYTHONHTTPSVERIFY', '') and
                getattr(ssl, '_create_unverified_context', None)):
            ssl._create_default_https_context = ssl._create_unverified_context
    

    不带选项地调用它:

    allow_unverified_content()
    

    【讨论】:

      猜你喜欢
      • 2018-02-23
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 2022-08-02
      • 2021-02-18
      • 1970-01-01
      • 2015-12-02
      相关资源
      最近更新 更多