当前兼容版本:requests (2.24.0) Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12)
使用python requests访问https网站,结果遇到报错sslv3 alert handshake failure。发现就那一个特定网站会,其他都可以正常获取html。
这个问题搞了我整整2天,整整2天,整整2天,真的cao了。
错误是ssl握手失败,一直以为是连这个站点的时ssl协议哪里出了问题,因为浏览器里证书显示无效,不安全的连接。但其实和证书一点关系都没有。
百度搜了一圈,其他人也遇到过这个报错。按他们的方法试,但还是没用,已经绝望了。
不过最后还是幸运地解决了。对我这种新手小白来说,这就是python的坑,巨坑。
报错sslv3 alert handshake failure
完整的错误提示:
Traceback (most recent call last):
File "C:\Python\Python38\lib\site-packages\requests\packages\urllib3\connectio
npool.py", line 542, in urlopen
httplib_response = self._make_request(conn, method, url,
File "C:\Python\Python38\lib\site-packages\requests\packages\urllib3\connectio
npool.py", line 341, in _make_request
self._validate_conn(conn)
File "C:\Python\Python38\lib\site-packages\requests\packages\urllib3\connectio
npool.py", line 761, in _validate_conn
conn.connect()
File "C:\Python\Python38\lib\site-packages\requests\packages\urllib3\connectio
n.py", line 234, in connect
self.sock = ssl_wrap_socket(conn, self.key_file, self.cert_file,
File "C:\Python\Python38\lib\site-packages\requests\packages\urllib3\util\ssl_
.py", line 279, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File "C:\Python\Python38\lib\ssl.py", line 500, in wrap_socket
return self.sslsocket_class._create(
File "C:\Python\Python38\lib\ssl.py", line 1040, in _create
self.do_handshake()
File "C:\Python\Python38\lib\ssl.py", line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure
(_ssl.c:1108)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python\Python38\lib\site-packages\requests\adapters.py", line 360, in
send
resp = conn.urlopen(
File "C:\Python\Python38\lib\site-packages\requests\packages\urllib3\connectio
npool.py", line 574, in urlopen
raise SSLError(e)
requests.packages.urllib3.exceptions.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILU
RE] sslv3 alert handshake failure (_ssl.c:1108)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Python\zhicheng\zc_get.py", line 123, in <module>
response = requests.get(request_url, data = data2, headers = header, verify=
False)
File "C:\Python\Python38\lib\site-packages\requests\api.py", line 69, in get
return request('get', url, params=params, **kwargs)
File "C:\Python\Python38\lib\site-packages\requests\api.py", line 50, in reque
st
response = session.request(method=method, url=url, **kwargs)
File "C:\Python\Python38\lib\site-packages\requests\sessions.py", line 465, in
request
resp = self.send(prep, **send_kwargs)
File "C:\Python\Python38\lib\site-packages\requests\sessions.py", line 573, in
send
r = adapter.send(request, **kwargs)
File "C:\Python\Python38\lib\site-packages\requests\adapters.py", line 431, in
send
raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert h
andshake failure (_ssl.c:1108)
搜到的解决办法:(这其实是正解)
import requests.packages.urllib3.util.ssl_
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL'
网上解决办法参考:
https://www.zhihu.com/question/36044851
https://blog.csdn.net/dmc436/article/details/107174100
https://stackoverflow.com/questions/31730819/python-sslerror-using-requests-for-surveymonkey-com
但我试了,还是报错。
包括openssl、requests的版本升级、重装,试了都还报错。
检测可支持的https协议
检测了那个站https支持的是TLS1.1 TLS1.2,一直以为是sslv3的问题,与目标网站不匹配。
后面找了强制设置tls/ssl连接https的方法,设置SSLv3时,居然报另一个错误“远程主机强迫关闭了一个现有的连接”。
设置TLSv1_2时,就是报之前的sslv3握手失败的错误“sslv3 alert handshake failure”。
报错“远程主机强迫关闭了一个现有的连接”
协议名称从\Lib\site-packages\OpenSSL\SSL.py里找的,都试了一遍。
PROTOCOL_SSLv2(协议不存在)
PROTOCOL_SSLv3(关闭连接)
PROTOCOL_SSLv23(握手失败)
PROTOCOL_TLSv1(关闭连接)
PROTOCOL_TLSv1_1(握手失败)
PROTOCOL_TLSv1_2(握手失败)
PROTOCOL_TLSv1_3(协议不存在)
这里我意识到,不是sslv3的问题。但反正是python的tls/ssl哪里出了什么问题。已经绝望。
测试的代码是上面链接stackoverflow.com里的
import ssl
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager
class Ssl3HttpAdapter(HTTPAdapter):
""""Transport adapter" that allows us to use SSLv3."""
def init_poolmanager(self, connections, maxsize, block=False):
self.poolmanager = PoolManager(num_pools=connections,
maxsize=maxsize,
block=block,
ssl_version=ssl.PROTOCOL_SSLv3)
s = requests.Session()
s.mount('https://', Ssl3HttpAdapter())
url = 'xxx'
print s.get(url)
最后抱着试试的心态,试了一个办法:换一个python版本。网上遇到相同问题的python版本都比较低,有的甚至是python2。
从3.8.2换成了3.6.0,测试,还是报错“sslv3 alert handshake failure”。接着试上面搜到的解决方法:
import requests.packages.urllib3.util.ssl_
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL'
居然好了,没有报错了。我的天,我快要哭了。
python插件包多,功能丰富。版本一多,兼容就出问题。对于新手,好多的坑,而且没有很详细的api介绍。python辣鸡,不过用python、BeautifulSoup,工作上我抓了2w+条有用的数据,还是很香的。
以前弄c#的时候,遇到各种错误,百度一搜,绝对容易找到答案。调试时候,vs里断点一下,什么变量的结构、字节都能看。微软那一套,感觉还是很完善很规范。
总结一下,“sslv3 alert handshake failure”报错,一种解决办法是:
1、更换python版本,3.6没问题
2、加入代码:
import requests.packages.urllib3.util.ssl_
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL'