pip:ProxyError(‘Cannot connect to proxy.

目录

  • 1 问题
  • 2 初步尝试
    • 2.1 设置环境变量
    • 2.2 修改注册表(这是一个夺笋的解决方案呀)
    • 2.3 pip的代理设置
  • 3 找问题的根源
    • 3.1 问题的根源
    • 3.2 解决办法
      • 3.2.1 从代理入手
      • 3.2.2 从源入手
      • 3.2.3 从pip入手
  • 4 写在最后
  • 参考文献

1 问题

在打开科学上网软件(后面简称XX)的前提下,pip安装python库失败(此时源为阿里源,XX设置为DIRECT,也就是直连,访问国内网站的),pip报错:

Looking in indexes: https://mirrors.aliyun.com/pypi/simple/
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /pypi/simple/scrapy/
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /pypi/simple/scrapy/
WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /pypi/simple/scrapy/
WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /pypi/simple/scrapy/
WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /pypi/simple/scrapy/
ERROR: Could not find a version that satisfies the requirement scrapy
ERROR: No matching distribution found for scrapy

2 初步尝试

出现了问题之后就试着解决,看错误信息是和代理有关,因此退出XX,再次pip,没有问题。考虑到pip不会经常用,因此这种解决办法似乎完全可以接受,但我有强迫症呀,想找一个让XX始终运行,一劳永逸的解决办法,于是开始在网上搜索,这一搜,啥牛鬼蛇神都出来了(大家能不能好好写博客,不要你抄他抄,搞的信息好混乱,检索效率极低,如果引用,那么需要指出来源),先看看大家伙都怎么办的。

2.1 设置环境变量

设置环境变量如下:

HTTP_PROXY        http://127.0.0.1:7890
HTTPS_PROXY       http://127.0.0.1:7890

确实有效,但很多博客并未给出这么做的原因,而且环境变量影响比较广,我有强迫症啊,只要有一点办法,都要坚决维护环境变量的干净整洁。

2.2 修改注册表(这是一个夺笋的解决方案呀)

修改注册表,将ProxyEnable从1修改为0(图片来自网络,找不到根源在哪了):
pip:ProxyError(‘Cannot connect to proxy._第1张图片
为什么说它损呢,是因为这么一搞代理就被关闭了,XX也就发挥不了作用了,我就为用一次pip,这么干真的合适吗?这样干还不如直接把XX退出呢,右键退出多方便,要用的时候再打开,犯得着修改注册表?最开始这么干的人可能情况比较特殊吧,可能他以后都不在用XX类软件了,并且之前用的XX类软件很拉跨,退出的时候不会关闭系统代理设置,导致奇怪的网络问题,于是他一气之下干脆把代理直接禁了…我编不下去了,确实理解不了为什么有人这么干。

2.3 pip的代理设置

为pip做相应的代理设置,具体做法有以下几种(关于XX的IP和端口号根据个人实际来确定):

  • 使用pip的--proxy选项设置代理:pip install libname --proxy http://127.0.0.1:7890
  • 直接编辑pip的配置文件pip.ini,在其中的[global]下面添上一行proxy = http://127.0.0.1:7890
  • 使用pip的config命令来写配置文件:pip config set global.proxy http://127.0.0.1:7890

按理来说,这和设置环境变量原理应该是一样的,都是把代理的情况告知pip,只是环境变量作用于全局,而这种方式仅仅针对pip。但,诡异的是,上述做法完全没有效果。不用修改环境变量,这本该成为我理想的选择,但它没效。强迫症患者不能忍啊,到底是为什么呢?见下文!

3 找问题的根源

遇到了奇怪的事情,但看源码去解决这个问题对当前的我来说又不现实,只能加大搜索力度了。运气比较好,终于找到了深入剖析这个问题的资料,见参考文献。由于对pip的相关背景不是太了解,且时间有限,所以只看懂了个大概,下面概括一下我的理解(需要深入理解的就去结合参考文献看源码吧)。

3.1 问题的根源

  • 代理服务器只支持HTTP(不确定是XX的锅还是windows的锅),且pip安装库时使用的urllib3在以前也就是低版本的时候是不支持HTTPS的,这样一来,尽管我们的源可能是HTTPS的,比如阿里源https://mirrors.aliyun.com/pypi/simple/,但走的还是HTTP,这正称了代理服务器的心,因此工作起来没有问题。
  • 后来也就是新版本的urllib3支持HTTPS了,但代理服务器不支持,这时候就出问题了:pip通过HTTPS去找代理,但由于代理服务器只支持HTTP,没法处理请求,因此在ssl握手阶段就出错了(连接不上代理)。
  • 关于2.3节的做法为什么没有效,是因为通过--proxy或配置文件所作的代理设置没有被更正到urllib的request。

3.2 解决办法

知道问题的根源就好办了,无非是对症下药。下面分别从代理、源、pip三个方面入手,给出不同的解决办法。

3.2.1 从代理入手

既然事情的是因为代理服务器不支持HTTPS导致的,那么不要用代理就行了,也就是在pip的时候,退出一下XX,后面要用了再启动就是了。2.2的方法之所以生效,也是因为解决了代理,每错,解决的干净彻底。

3.2.2 从源入手

既然XX不支持HTTPS,那我们就不能称一下它脆弱的心?毕竟人家上网的时候帮了咱很多吧。简单的说,咱们不使用带S的源就可以了呀,虽然安全性上有损失,但大公司或知名高校维护的源还是可以信任的。具体做法,通过命令或直接编辑来修改pip的配置文件:

[global]
index-url = http://mirrors.aliyun.com/pypi/simple/

[install]
trusted-host = mirrors.aliyun.com

值得一提的是,不使用安全HTTP协议时,我们要告诉pip我们信任该源(trusted-host),否则pip会撂挑子:

WARNING: The repository located at mirrors.aliyun.com is not a trusted or secure host and is being ignored. If this repository is available via HTTPS we recommend you use HTTPS instead, otherwise you may silence this warning and allow it anyway with '--trusted-host mirrors.aliyun.com'.
ERROR: Could not find a version that satisfies the requirement libname
ERROR: No matching distribution found for libname

这种方法比较适合我这种强迫症患者,因为操作简单,且完全不会影响到pip之外。

3.2.3 从pip入手

pip十分痴迷HTTPS,但XX确实不支持,这时不妨坦诚一些,把XX的情况告诉pip,希望pip能理解和支持。没错,这里要做的就是2.1节2.3节所做的。不过,上文已经说了,2.1节的办法有效,而2.3节的办法无效。因为配置文件也好、--proxy选项也好,咱们对代理的设置都没起效,pip还是从系统获取代理(所以设置系统环境变量有效),这算不算pip的bug呢?具体解决办法,GitHub上有网友提出修改python安装目录/Python37/Lib/site-packages/pip/_internal/network下的session.py(我的是python3.7,具体目录根据个人实际确定)。修改位于419行附近,原先是:

def request(self, method, url, *args, **kwargs):
        # Allow setting a default timeout on a session
        kwargs.setdefault("timeout", self.timeout)
        
        # Dispatch the actual request
        return super().request(method, url, *args, **kwargs)

修改为:

def request(self, method, url, *args, **kwargs):
        # Allow setting a default timeout on a session
        kwargs.setdefault("timeout", self.timeout)
        
        # fix problem with proxies make pip --proxy work
        # this method comes from https://github.com/pypa/pip/issues/9216 (junqfisica's comment)
        kwargs.setdefault("proxies", self.proxies)

        # Dispatch the actual request
        return super().request(method, url, *args, **kwargs)

这样一来,2.3节的办法就可以工作啦。不过修改python自带源码的行为终究让人感觉不太对劲。这个看个人吧,我还是比较推荐3.2.2节的做法,毕竟还讲啥安全呀,各种安全协议倒是层出不穷,与此同时,个人信息都不知道被卖了多少手了。

4 写在最后

到处乱抄博客,污染网络环境的,原地爆炸、螺旋升天!技术社区和氛围需要大家一起来维护,谢谢观看。

参考文献

[1] https://github.com/pypa/pip/issues/9216
[2] https://zhuanlan.zhihu.com/p/350015032

你可能感兴趣的:(开发环境,pip,proxy,ProxyError)