最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【workaround】urllib.urlretrieve下载图片速度很慢 + 【已解决】给urllib.urlretrieve添加user-agent

Python crifan 19121浏览 0评论

【问题】

在折腾,给BlogstoWordpress添加QQ空间搬家到Wordpress的功能。其中用到urllib.urlretrieve下载QQ空间的图片,但是发现下载速度很慢,非常的慢。

此处的慢指的是,原先是几十K的图片,本来正常只需要不到1秒就下载完毕的,结果实际花了几分钟才下载完。

不是一般的慢,是特别的慢。

【解决过程】

1.开始以为是网速有问题,但是后经查证,网络没问题。

并且下载其他博客的图片,比如百度空间的图片,速度都还是很快的。

2.试了试对应的qq空间的图片的地址:

http://s9.photo.store.qq.com/http_imgload.cgi?/rurl4_b=521ecb3f97727a4712812471567bebeeacf8cc423d3a56014196aaf26e799930f0dcea0c85662f530eb17e6ed5f2b0434c7a2543d6e5cfdd63024ac21d06367c454183a134219606a9224fc11e48f8248ec4b1f8

在浏览器中输入,结果同样的几十K的图片,瞬间就显示了,所以,看来至少浏览器中下载图片速度是正常的。

3.猜测是QQ空间对refer值做了判断。

然后看到这里: [CPyUG:60237] Re: urllib获取文件速度很慢的问题,提到了和refer所相关的user-agent:

速度出奇的慢,下载下来要差不多一分钟,但是下载其他网站的图片没有问题。似乎的确是这样,我用{‘User-agent’ :

‘Mozilla/4.0 (compatible; MSIE 6.0; Windows NT)’}就快多了,可能新浪在判断这个东西。

所以,就去试试,给urllib.urlretrieve添加user-agent(如果不行,再试试添加refer为QQ空间的地址)

【给urllib.urlretrieve添加user-agent】

(1)根据上面[CPyUG:60237] Re: urllib获取文件速度很慢的问题中所说,尝试给urllib.urlretrieve添加对应的user-agent。而关于给urllib.urlretrieve添加user-agent的问题,网上找了半天,就看到这里:

Urlretrieve and User-Agent? – Python

中给出的参考代码:

opener = FancyURLopener({})  
opener.verion = 'Mozilla/5.0' 
opener.retrieve('http://example.com', 'index.html') 

然后试了如下代码:

opener = urllib.FancyURLopener({});
opener.verion = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)';
opener.retrieve(fileUrl, fileToSave, reportHook);

结果问题依旧,速度还是很慢。

(2)然后又去找到了python手册中的解释:

urllib._urlopener

The public functions urlopen() and urlretrieve() create an instance of the FancyURLopener class and use it to perform their requested actions. To override this functionality, programmers can create a subclass of URLopener or FancyURLopener, then assign an instance of that class to the urllib._urlopener variable before calling the desired function. For example, applications may want to specify a different User-Agent header than URLopener defines. This can be accomplished with the following code:

import urllib

class AppURLopener(urllib.FancyURLopener):
    version = "App/1.7"

urllib._urlopener = AppURLopener()

然后写了对应的代码:

class AppURLopener(urllib.FancyURLopener):
    version = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT)";

def downloadFile():
    urllib._urlopener = AppURLopener();
    
    urllib.urlretrieve(fileUrl, fileToSave);

结果是,至少看起来,的确是可以给urllib.urlretrieve添加对应的User-Agent了,但是却对此处的问题,下载图片速度慢的问题,没任何影响。

貌似看起来,好像问题不在这个User-Agent。

所以只能继续折腾。

4.发现上面原先要现在的QQ空间的图片地址,有时候是需要跳转redirect的,所以又去先获得对应当前真实的图片地址:

resp = urllib2.urlopen(fileUrl);
realUrl = resp.geturl();

然后再去下载对应的realUrl,结果问题依旧。

5.添加对应的cookie支持:

# add cookie to test whether can speedup pic download
gVal['cj'] = cookielib.CookieJar();
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(gVal['cj']));
urllib2.install_opener(opener);

问题依旧,下载还是很慢。

6.后来逼急了,手动去调用urllib2.urlopen去打开对应的url,获得对应的response,然后read出对应的图片二进制数据,然后保存图片为对应的本地文件:

resp = urllib2.urlopen(fileUrl); # note: Python 2.6 has added timeout support.
realUrl = resp.geturl();

url = str(realUrl);
req = urllib2.Request(url);
#req.add_header('Refer', "http://user.qzone.qq.com/622007179/blog/");
#req.add_header('User-Agent', gConst['userAgentIE9']);
#req.add_header('Cache-Control', 'no-cache');
#req.add_header('Accept', '*/*');
#req.add_header('Accept-Encoding', 'gzip, deflate');
#req.add_header('Connection', 'Keep-Alive');
resp = urllib2.urlopen(req);

respHtml = resp.read();

binfile = open(fileToSave, "wb");
binfile.write(respHtml);

binfile.close();

print "save pic OK";

上述代码中,有几点需要注意的是:

(1)经过测试,发现原以为的Refer,User-Agent,甚至Cache-control等,全部都对图片下载的速度没影响。

所以,暂时此处的结果就是,通过urllib.urlretrieve下载图片,不知何种原因,速度狂慢,而自己手动去通过urllib2.urlopen打开图片地址,获得图片数据的话,却都是很正常的。

【总结】

下面分析一下,用urllib.urlretrieve下载QQ空间的图片速度慢,这一问题的可能的原因:

Chrome中抓出的来的Http的GET请求信息:

GET /http_imgload.cgi?/rurl4_b=521ecb3f97727a4712812471567bebee7a4969da4a435c2afc49a751497b7d1b011ffa9ba753345b408a05762102c98074de25ae01872185682efd4b863d99e123e4109ea6725c199673f178dc530410eaee9b79 HTTP/1.1

和IE9中F12抓出来的:

键	值
请求	GET /http_imgload.cgi?/rurl4_b=521ecb3f97727a4712812471567bebeed32313b0721c3dd95eae6e8bf135143d68875a3b78a06b0c840db8d7eae6f59d05be2f71aa1b610c0e41aa934aab83fb003600cd6b42237fd24ed784c918f4311076a93f HTTP/1.1

可以看出,HTTP协议的版本,都是是1.1的,而对于urllib.urlretrieve,其Python 2.7手册中的解释是:

20.5.4. urllib Restrictions

  • Currently, only the following protocols are supported: HTTP, (versions 0.9 and 1.0), FTP, and local files.

即HTTP是0.9和1.0版本的。

所以,也不知道是不是这个HTTP版本的原因导致此问题的,即不知道是不是:

对于QQ空间的图片,即放在各个QQ自己的服务器上面的那些QQ空间的图片:

如果是普通浏览器中用HTTP 1.1下载图片是正常的,速度很快的;

而Python中的urllib.urlretrieve去用HTTP 0.9和1.0,去下载图片速度就很慢了。

目前仅是猜测,根本原因还是未知。

转载请注明:在路上 » 【workaround】urllib.urlretrieve下载图片速度很慢 + 【已解决】给urllib.urlretrieve添加user-agent

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (2)

  1. 记录折腾的过程是个好习惯啊~,赞! 你是做完才记录的吗?还是变做边记? 每次做完我总是记不太清楚细节了,而且代码也变了,记起来很麻烦啊
    KING11年前 (2013-09-14)回复
    • 大多数时候都是边做边记录。 当然,这种方式,会很耗时间。
      crifan11年前 (2013-09-14)回复
87 queries in 0.212 seconds, using 22.16MB memory