我有一个获取html页面的Perl脚本。我尝试用Python重写它(Just Coz我正在尝试学习Python),我发现它真的很慢!
这是Perl中的测试脚本
#!/usr/bin/perl
use LWP::Simple;
$url = "http://majorgeeks.com/page.php?id=";
open(WEB,">>"."perldata.txt");
for ($column = 1 ; $column <= 20 ; $column ++)
{
$temp = $url.$column;
print "val = $temp\n\n";
$response=get($temp)or die("[-] Failed!!\n");
print WEB "$response\n\n";
}
这是Python中的等效代码
import urllib2
url = "http://majorgeeks.com/page.php?id="
f = open("pydata.txt", 'w')
for i in range(20):
tempurl = url + str(i+1)
print "Val : " + tempurl + "\n\n"
#req = urllib2.Request(tempurl)
res = urllib2.urlopen(tempurl)
f.write(res.read())
f.close()
我发现的差异很大! Perl脚本在大约30秒内完成。 虽然Python脚本花了大约7分钟。 (420秒)!!
我正在使用Ubuntu 11.10,64bit,Core i7,在12MBPS连接上进行测试。我试了好几次,每次都得到相同的差异。
我在这里做错了吗?或者我需要做点什么?或者差异是否合理? (我希望不会)
非常感谢你的帮助。
更新3: 我刚刚回家并启动了我的笔记本电脑,再次运行代码,它在11秒内完成! :/是因为我“重新启动”我的comp? Here's Profiler输出
注意 - Perl仍然花了31秒同样的事情!! :/
更新2: 正如@Makoto Here's所建议的那样,我所做的分析器数据。这真的很慢!我知道一些python配置与此有关,但不知道是什么。对于一个简单的请求,它不应该花20秒!!!
更新: 固定url到tempurl。按照此处的建议注释掉urllib2.Request。没有多大区别。
答案 0 :(得分:2)
您的代码可以改进,但我不确定它是否会解决所有性能问题:
from urllib2 import urlopen
url = "http://majorgeeks.com/page.php?id={}"
with open("pydata.txt", 'w') as f:
for i in xrange(1, 21):
tempurl = url.format(i)
print "Val : {}\n\n".format(tempurl)
f.write(urlopen(tempurl).read())
我也在逻辑上更改了它 - 它现在请求不同的URL(由tempurl
定义),它用于请求相同的URL 20次(由url
定义)。我也使用了字符串格式,虽然我不确定它如何影响效率。
我在我的系统上测试过它(Windows 7 64位,Python 2.7.2,IDLE内部,中等互联网连接),完成时需要40秒(40.262)。
答案 1 :(得分:1)
我仍然需要抓住我的头脑,弄清楚为什么这段代码对@mayjune和@Tadeck来说都花了这么长时间。我有机会通过分析器正式运行两段代码,结果如下。我强烈建议您在自己的机器上运行这些结果,因为我会产生不同的结果(AMD Athlon II X4 @ 3GHz,8GB RAM,Ubuntu 11.04 x64,7Mbit线)。
运行:
python -m cProfile -o profile.dat <path/to/code.py>; python -m pstats profile.dat
(从探查器内部,您可以检查help
命令。)
Fri Jan 6 17:49:29 2012 profile.dat
20966 function calls (20665 primitive calls) in 13.566 CPU seconds
Ordered by: cumulative time
List reduced from 306 to 15 due to restriction <15>
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.001 0.001 13.567 13.567 websiteretrieval.py:1(<module>)
20 0.000 0.000 7.874 0.394 /usr/lib/python2.7/urllib2.py:122(urlopen)
20 0.000 0.000 7.874 0.394 /usr/lib/python2.7/urllib2.py:373(open)
20 0.000 0.000 7.870 0.394 /usr/lib/python2.7/urllib2.py:401(_open)
40 0.000 0.000 7.870 0.197 /usr/lib/python2.7/urllib2.py:361(_call_chain)
20 0.000 0.000 7.870 0.393 /usr/lib/python2.7/urllib2.py:1184(http_open)
20 0.001 0.000 7.870 0.393 /usr/lib/python2.7/urllib2.py:1112(do_open)
1178 7.596 0.006 7.596 0.006 {method 'recv' of '_socket.socket' objects}
20 0.000 0.000 5.911 0.296 /usr/lib/python2.7/httplib.py:953(request)
20 0.000 0.000 5.911 0.296 /usr/lib/python2.7/httplib.py:974(_send_request)
20 0.000 0.000 5.911 0.296 /usr/lib/python2.7/httplib.py:938(endheaders)
20 0.000 0.000 5.911 0.296 /usr/lib/python2.7/httplib.py:796(_send_output)
20 0.000 0.000 5.910 0.296 /usr/lib/python2.7/httplib.py:769(send)
20 0.000 0.000 5.909 0.295 /usr/lib/python2.7/httplib.py:751(connect)
20 0.001 0.000 5.909 0.295 /usr/lib/python2.7/socket.py:537(create_connection)
......所以从观察来看,唯一可能让你失望的是...... urlopen
和open
。 I / O很慢,所以这是可以理解的。
Fri Jan 6 17:52:36 2012 profileTadeck.dat
21008 function calls (20707 primitive calls) in 13.249 CPU seconds
Ordered by: cumulative time
List reduced from 305 to 15 due to restriction <15>
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.002 0.002 13.249 13.249 websiteretrievalTadeck.py:1(<module>)
20 0.000 0.000 7.706 0.385 /usr/lib/python2.7/urllib2.py:122(urlopen)
20 0.000 0.000 7.706 0.385 /usr/lib/python2.7/urllib2.py:373(open)
20 0.000 0.000 7.702 0.385 /usr/lib/python2.7/urllib2.py:401(_open)
40 0.000 0.000 7.702 0.193 /usr/lib/python2.7/urllib2.py:361(_call_chain)
20 0.000 0.000 7.702 0.385 /usr/lib/python2.7/urllib2.py:1184(http_open)
20 0.001 0.000 7.702 0.385 /usr/lib/python2.7/urllib2.py:1112(do_open)
1178 7.348 0.006 7.348 0.006 {method 'recv' of '_socket.socket' objects}
20 0.000 0.000 5.841 0.292 /usr/lib/python2.7/httplib.py:953(request)
20 0.000 0.000 5.841 0.292 /usr/lib/python2.7/httplib.py:974(_send_request)
20 0.000 0.000 5.840 0.292 /usr/lib/python2.7/httplib.py:938(endheaders)
20 0.000 0.000 5.840 0.292 /usr/lib/python2.7/httplib.py:796(_send_output)
20 0.000 0.000 5.840 0.292 /usr/lib/python2.7/httplib.py:769(send)
20 0.000 0.000 5.839 0.292 /usr/lib/python2.7/httplib.py:751(connect)
20 0.001 0.000 5.839 0.292 /usr/lib/python2.7/socket.py:537(create_connection)
同样,花费时间的最大两个罪魁祸首是urlopen
和open
。这让我相信I / O在破坏代码方面起着重要作用。但是,我测试它的机器上的差异并不大 - Perl的脚本大致在同一时间执行。
real 0m11.129s
user 0m0.230s
sys 0m0.070s
虽然你的机器非常强大,但我不相信你的代码很慢是软件的错。我强烈建议您运行探查器套件(上面包含代码),看看是否能找到我错过的任何瓶颈。
答案 2 :(得分:0)
我真的不知道,你为什么会得到这个奇怪的结果。但是让我建议真正快速的解决方案。使用一些异步库。我喜欢gevent,非常漂亮{{3}}
代码:
from requests import async
import time
begin = time.time()
url = "http://majorgeeks.com/page.php?id=%s"
rs = [async.get(url % i) for i in xrange(1, 21)]
responses = async.map(rs, size=10)
with open("pydata.txt", 'w') as f:
for response in responses:
print response.url
f.write(response.content)
print 'Elapsed:', (time.time()-begin)
只需2.45秒。
修改强>
慢urllib2.urlopen
的可能原因:
http_proxy
网站以某种方式减慢urllib2
代理,限制自动抓取