在使用 pip 安装 Python 包时,有时会遇到 SSL 错误,导致无法下载包。
报错如下:
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLZeroReturnError(6, '
TLS/SSL connection has been closed (EOF) (_ssl.c:1149)'))': /simple/...
问题定位
发生这种情况的一个常见原因是:设置了系统代理,且代理不支持 HTTPS,而此时 pip 读取了系统代理后使用了 HTTPS 协议下载。
CFW
等软件一般会通过修改 Windows 注册表的计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings
下的ProxyServer
来配置代理服务器地址端口以及ProxyEnable
而 Python 3.7/3.8 版本的 pip 使用的urllib
标准库,其request.py
默认会读取系统代理配置,自动配置代理,但忽略了代理服务器不支持 HTTPS 的情况。
解决方法
要解决这个问题,有这几种方法:
- 配置代理软件的 HTTPS 代理
- 用TUN模式接管流量,实现隐形代理
- 通过 pip 配置文件设置代理
- 修改Python内置库,修复代理协议问题
前两种方法和使用的不同软件有关。
通过配置文件设置代理是最简单的方法,除了需要将代理地址硬编码到配置文件,屏蔽掉自动检测代理功能外,不会对其他软件产生影响;还可以通过一个小工具修复 Python 内置库的代理协议问题,强制将自动检测的代理协议改为 HTTP,这样能保留自动检测代理的功能。
接下来介绍后两种方法。
1. 设置 pip.ini
通过在用户目录下创建pip.ini
文件,设置代理,即:
对于 Windows,在目录
%APPDATA%\pip
(Windows)下创建pip.ini
文件对于 Linux,在目录
~/.config/pip/
下创建pip.conf
文件
向文件写入或追加内容:
[global]
proxy=http://127.0.0.1:7897
保存文件并重启终端,再次使用pip install
,即可正常下载。
2. 修改内置库
修改 Python 内置库,修复代理协议问题。
我写了一个小工具并上传到了 PYPI,可以自动修改 Python 内置库的一处代理协议问题,经过测试(截止到本文发布时)会发生此问题的 Python 3.7/3.8 版本都可以成功修复。
首先确认当前环境是出现 HTTPS 代理问题的环境,然后在关闭代理的情况下安装此只有8KB
大小的工具:
pip install pytool-proxy-fix
然后运行工具:
pytool-proxy-fix
之后会自动检测当前环境的 HTTPS 协议代理问题,通过强制设置urllib
库自动转换代理时只使用 HTTP 协议,来修复代理协议问题。
结语
相比硬编码代理地址到配置文件,我更喜欢通过此工具进行修复,因为这样可以保留代理自动检测的功能。
文中提到的pytool-proxy-fix
工具由我自己开发,其基于自由度最高的 MIT 协议开源,允许转载或二次开发,但必须注明原作者信息。