本内容复制知乎的一个贴子,在此只做下记录及参考和学习,原链接地址:
最近遇到的一个问题,在搞清楚之后才发现这么多年的 HTTPS_PROXY 都配置错了!
起因
想用 Python 在网上下载一些图片素材,结果 requests 报 requests.exceptions.ProxyError,具体的错误信息见下面。当然第一时间是把系统代理关了,结果访问就正常了。
如果只是这样,可能我就觉得是代理有问题,然后关了用就行了,但是偏偏想要下载的资源里是必须要走代理的,所以只能想办法解决。
下面先介绍一下具体的情况:
解决过程
操作系统:Windows 10
Python: 3.8(有虚拟环境)
requests 通过代理访问外网时报错如下:
Traceback (most recent call last):File "E:\code\Python\.venv\smalltools\lib\site-packages\urllib3\connectionpool.py", line 696, in urlopenself._prepare_proxy(conn)File "E:\code\Python\.venv\smalltools\lib\site-packages\urllib3\connectionpool.py", line 964, in _prepare_proxyconn.connect()File "E:\code\Python\.venv\smalltools\lib\site-packages\urllib3\connection.py", line 359, in connectconn = self._connect_tls_proxy(hostname, conn)File "E:\code\Python\.venv\smalltools\lib\site-packages\urllib3\connection.py", line 496, in _connect_tls_proxyreturn ssl_wrap_socket(File "E:\code\Python\.venv\smalltools\lib\site-packages\urllib3\util\ssl_.py", line 432, in ssl_wrap_socketssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls)File "E:\code\Python\.venv\smalltools\lib\site-packages\urllib3\util\ssl_.py", line 474, in _ssl_wrap_socket_implreturn ssl_context.wrap_socket(sock)File "C:\Users\Davy\AppData\Local\Programs\Python\Python38\lib\ssl.py", line 500, in wrap_socketreturn self.sslsocket_class._create(File "C:\Users\Davy\AppData\Local\Programs\Python\Python38\lib\ssl.py", line 1041, in _createself.do_handshake()File "C:\Users\Davy\AppData\Local\Programs\Python\Python38\lib\ssl.py", line 1310, in do_handshakeself._sslobj.do_handshake()
OSError: [Errno 0] Error
因为浏览器访问是没有问题的,代理本身应该没有问题。
按照这个错误信息在网上搜了一下,比较接近的帖子给的解决方案有安装 ssl 模块之类,都照着检查了一遍,问题还是没有解决。
因为网上的内容有些年头了,并且我觉得使用代理是非常常见的场景,既然没多少人报这个问题,那么很可能只是偶然的 bug,于是想着把版本再升级试试。
升级到 python 3.9 ,错误仍然存在,提示略有变化:
Traceback (most recent call last):File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\site-packages\urllib3\connectionpool.py", line 696, in urlopenself._prepare_proxy(conn)File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\site-packages\urllib3\connectionpool.py", line 964, in _prepare_proxyconn.connect()File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\site-packages\urllib3\connection.py", line 359, in connectconn = self._connect_tls_proxy(hostname, conn)File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\site-packages\urllib3\connection.py", line 496, in _connect_tls_proxyreturn ssl_wrap_socket(File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\site-packages\urllib3\util\ssl_.py", line 432, in ssl_wrap_socketssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls)File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\site-packages\urllib3\util\ssl_.py", line 474, in _ssl_wrap_socket_implreturn ssl_context.wrap_socket(sock)File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 500, in wrap_socketreturn self.sslsocket_class._create(File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1040, in _createself.do_handshake()File "C:\Users\Davy\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1309, in do_handshakeself._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:1122)
好歹错误信息有点变化,于是按照最下面 ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:1122) 去谷歌,并没有找到解决办法,但是发现有人在不久前遇到了相同的问题,并且通过降级 Python 3.7 解决了。
参见:
先重新安装 Python 3.7 试了一下果然可行,并且意外地发现在 Python 3.8 环境下也是可行的,也就是可以排除 Python 版本的问题,那么自然就怀疑是某个包引发的。
通过简单地对比和排除,很快就发现了问题所在:
模块 urllib3 的版本,报错的是 1.26.3,没报错的是 1.25.11
在原报错环境中使用下面命令重装低版本 urllib3:
pip install urllib3==1.25.11
然后测试果然就没问题了。
问题根源
先查了一下 urllib3 的更新日志,应该是 1.26.0 的修改导致的:
按照这个更新日志,明明应该是增加了 HTTPS 的支持,怎么反而让它失效了呢?
我一时搞不明白这个问题,但是想起了我最近遭遇到了另一个问题,然后意外地找到了真相: