2012年5月25日星期五

IE代理设置会导致Python的urlopen变慢

import sys
import time
try:
    from urllib2 import urlopen
except:
    from urllib.request import urlopen

url = 'http://www.baidu.com'

start = time.time()
res = urlopen(url).read()
elapsed = time.time() - start
print('Elapsed time: {0}'.format(elapsed))

如果你的IE中有设置代理服务器,如上代码跑下来很可能要接近5秒,但取消代理设置之后,1秒都不需要。

pdb跟了半天,过程就不写了,直接说结论吧,问题出在urllib.py(Python 2.7.1,下同)的1534行,proxy_bypass函数:

    def proxy_bypass(host):
        """Return a dictionary of scheme -> proxy server URL mappings.

        Returns settings gathered from the environment, if specified,
        or the registry.

        """
        if getproxies_environment():
            return proxy_bypass_environment(host)
        else:
            return proxy_bypass_registry(host)

getproxies_environment函数用来获取以“_PROXY”结尾的环境变量,如果不存在则返回空的dict。也就是说,有类似的环境变量存在则执行proxy_bypass_environment函数,没有则执行proxy_bypass_registry函数。

而导致urlopen如此之慢的罪魁祸首,就在urllib.py第1511行,proxy_bypass_registry函数中的这一句:

fqdn = socket.getfqdn(rawHost)

执行getfqdn函数,会向rawHost发送三次NetBIOS Name Query请求。也就是这三次压根不会收到返回数据的请求,导致了urlopen会慢成这样。而proxy_bypass的功能,也不过就是确定某个host要不要走代理而已。

Python 2.7.1和3.2均有这个问题,我想保留这个设计总是有一定道理的吧。不过总这么delay也不是事,所以要在IE里设置代理又要用Python写的东西,只有多设置几个环境变量了:

SET HTTP_PROXY="127.0.0.1:8118"
SET HTTPS_PROXY="127.0.0.1:8118"
SET NO_PROXY="localhost,127.0.0.1"

没有评论 :