Windows下pip中的Urllib2错误
我在Windows上用ActiveState Python 2.7.2运行pip时遇到了一些问题。我们使用了一个代理,这可能是问题的一部分。这个代理是不需要认证的。系统的代理设置在Firefox里手动配置或者用一些简单的Python代码都能正常工作:
这个操作是正常的:
urllib.urlopen('http://www.google.com', proxies={'http': 'http://proxy:port'})
它返回了来自google.com的带有头信息的响应:
<addinfourl at 61539976L whose fp = <socket._fileobject object at 0x00000000042924F8>>
在设置了http_proxy
环境变量后,我运行了:
pip install loremipsum
结果是:
Downloading/unpacking loremipsum
Could not fetch URL http://pypi.python.org/simple/loremipsum: <urlopen error [Errno 11004] getaddrinfo
failed>
Will skip URL http://pypi.python.org/simple/loremipsum when looking for download links for loremipsum
Could not fetch URL http://pypi.python.org/simple/: <urlopen error [Errno 11004] getaddrinfo failed>
Will skip URL http://pypi.python.org/simple/ when looking for download links for loremipsum
Cannot fetch index base URL http://pypi.python.org/simple/
Could not fetch URL http://pypi.python.org/simple/loremipsum/: <urlopen error [Errno 11004] getaddrinfo failed>
Will skip URL http://pypi.python.org/simple/loremipsum/ when looking for download links for loremipsum
Could not find any downloads that satisfy the requirement loremipsum
No distributions at all found for loremipsum
Exception information:
Traceback (most recent call last):
File "C:\ActiveState\ActivePython\lib\site-packages\pip\basecommand.py", line 126, in main
self.run(options, args)
File "C:\ActiveState\ActivePython\lib\site-packages\pip\commands\install.py", line 222, in run
requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle)
File "C:\ActiveState\ActivePython\lib\site-packages\pip\req.py", line 954, in prepare_files
url = finder.find_requirement(req_to_install, upgrade=self.upgrade)
File "C:\ActiveState\ActivePython\lib\site-packages\pip\index.py", line 152, in find_requirement
raise DistributionNotFound('No distributions at all found for %s' % req)
DistributionNotFound: No distributions at all found for loremipsum
错误11004似乎表示有名称解析的问题,这在使用代理时应该是与代理访问(或无视)有关的问题。
我可以在Linux上测试一个类似的设置(http_proxy变量、相同的代理、不同的Python)。运行上面的命令效果很好。还有,在Windows机器上的浏览器中访问这个网址也能正常工作(显示一堆egg和zip文件)。
我查看了pip
的代码,想找出它出错的地方,并在交互式会话中运行了代码。我发现所有下载的准备和操作基本上都在C:\ActiveState\ActivePython\lib\site-packages\pip\downloads.py
中进行。在setup()
(第125行)中,准备了ProxyHandler
并构建了opener
,这个opener
被存储在urllib2
中,以便后续调用使用。当我在交互式环境中运行时,我发现需要为https
代理添加一个条目。我还添加了调试信息的打印。这让我在iPython的交互式运行中得到了:
In [1]: import urllib2
In [2]: proxy='proxy:port'
In [3]: proxy_support = urllib2.ProxyHandler({"http": proxy, "ftp": proxy, "https": proxy})
In [4]: opener = urllib2.build_opener(proxy_support, urllib2.CacheFTPHandler, urllib2.HTTPHandler(debugle
vel=1), urllib2.HTTPSHandler(debuglevel=1))
In [5]: urllib2.install_opener(opener)
对于ftp
、http
和https
,代理确实是相同的。我还通过一些打印检查了所有处理命令行参数的代码,确保它们没有干扰代理。代理在downloads.py
中的存储方式与上面简化的方式相同(从http_proxy变量读取)。
在弄清楚从pip获取包的URL后,它会进入第74行的__call__()
。
首先构造一个请求,使用:
In [6]: url = urllib2.Request('http://pypi.python.org/simple/loremipsum', headers={'Accept-encoding': 'identity'})
然后这个请求会与urllib2.urlopen(url)
一起使用:
In [7]: response = urllib2.urlopen(url)
send: 'GET http://pypi.python.org/simple/loremipsum HTTP/1.1\r\nHost: pypi.python.org\r\nUser-Agent: Pyth
on-urllib/2.7\r\nConnection: close\r\nAccept-Encoding: identity\r\n\r\n'
reply: 'HTTP/1.1 301 Moved Permanently\r\n'
header: Server: Varnish
header: Retry-After: 0
header: Location: https://pypi.python.org/simple/loremipsum
header: Content-Length: 0
header: Accept-Ranges: bytes
header: Date: Tue, 12 Aug 2014 16:41:39 GMT
header: Via: 1.1 varnish
header: X-Served-By: cache-fra1234-FRA
header: X-Cache: MISS
header: X-Cache-Hits: 0
header: X-Timer: S1407861699.491394,VS0,VE0
header: Connection: close
header: Age: 0
send: 'CONNECT pypi.python.org:443 HTTP/1.0\r\n'
send: '\r\n'
send: 'GET /simple/loremipsum HTTP/1.1\r\nHost: pypi.python.org\r\nUser-Agent: Python-urllib/2.7\r\nConne
ction: close\r\nAccept-Encoding: identity\r\n\r\n'
reply: 'HTTP/1.1 301 Moved Permanently\r\n'
header: Date: Tue, 12 Aug 2014 16:41:40 GMT
header: Server: nginx/1.6.0
header: Location: /simple/loremipsum/
header: Cache-Control: max-age=600, public
header: Strict-Transport-Security: max-age=31536000; includeSubDomains
header: Via: 1.1 varnish
header: Content-Length: 0
header: Accept-Ranges: bytes
header: Via: 1.1 varnish
header: Age: 44282
header: X-Served-By: cache-iad2135-IAD, cache-fra1231-FRA
header: X-Cache: MISS, HIT
header: X-Cache-Hits: 0, 1
header: X-Timer: S1407861700.831757,VS0,VE0
header: Connection: close
send: 'CONNECT pypi.python.org:443 HTTP/1.0\r\n'
send: '\r\n'
send: 'GET /simple/loremipsum/ HTTP/1.1\r\nHost: pypi.python.org\r\nUser-Agent: Python-urllib/2.7\r\nConn
ection: close\r\nAccept-Encoding: identity\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Date: Tue, 12 Aug 2014 16:41:41 GMT
header: Server: nginx/1.6.0
header: Content-Type: text/html; charset=utf-8
header: X-PYPI-LAST-SERIAL: 794358
header: Cache-Control: max-age=600, public
header: Strict-Transport-Security: max-age=31536000; includeSubDomains
header: Via: 1.1 varnish
header: Content-Length: 913
header: Accept-Ranges: bytes
header: Via: 1.1 varnish
header: Age: 67708
header: X-Served-By: cache-iad2121-IAD, cache-fra1231-FRA
header: X-Cache: HIT, HIT
header: X-Cache-Hits: 1, 1
header: X-Timer: S1407861701.174694,VS0,VE0
header: Vary: Accept-Encoding
header: Connection: close
这似乎是一个可以接受的答案。我在pip中有完全相同的代码,但它却失败了。
我漏掉了什么?为什么我的交互式会话可以工作,而pip却不行?
1 个回答
你没有给pip指定代理吗?
补充说明:评论的总结是:代理是通过环境变量 HTTP_PROXY
指定的,但一开始没用,现在可以用了。
我稍微研究了一下urllib,发现它默认会处理Windows注册表的设置。它有一个 getproxies()
函数,这个函数会返回 getproxies_environment() 或 getproxies_registry()
,所以你其实在没有修改环境变量或命令行的情况下就应该能正常使用。