我想用Python语言编写一个脚本,可以从数据库中抓取网址,并下载网页的同时,加快而不是等待每个页面下载一前一后的事情。同时下载多个页面?
根据this thread,Python不允许这样做,因为一些名为Global Interpreter Lock的内容会阻止多次激活相同的脚本。
在投入时间学习Twisted框架之前,我想确保没有更简单的方法来完成我需要做的事情。
谢谢你的任何提示。
我想用Python语言编写一个脚本,可以从数据库中抓取网址,并下载网页的同时,加快而不是等待每个页面下载一前一后的事情。同时下载多个页面?
根据this thread,Python不允许这样做,因为一些名为Global Interpreter Lock的内容会阻止多次激活相同的脚本。
在投入时间学习Twisted框架之前,我想确保没有更简单的方法来完成我需要做的事情。
谢谢你的任何提示。
您可以查看multiprocessing package避免GIL锁定问题。
下载是IO,可以使用非阻塞套接字或扭曲来异步完成。这两种解决方案都比线程或多处理更有效率。
GIL阻止您切实做好处理器负载均衡的线程。由于这不是处理器负载均衡,但防止一个IO等待从停止整个下载后,GIL是不是与此有关。 *)
所以你需要做的就是创建几个同时下载的进程。您可以使用线程模块或多处理模块执行此操作。
*)嗯......除非你有千兆连接,并且你的问题确实是你的处理器在你的网络之前变得超载了。但这显然不是这种情况。
最近,我解决了这个同样的问题。有一点需要考虑的是,有些人不愿意让他们的服务器陷入困境,并会阻止这样做的IP地址。我听到的标准礼貌是在页面请求之间大约3秒钟,但这是灵活的。
如果您从多个网站下载,则可以按域对网址进行分组,并为每个网站创建一个线程。然后,在你的线程,你可以做这样的事情:
for url in urls:
timer = time.time()
# ... get your content ...
# perhaps put content in a queue to be written back to
# your database if it doesn't allow concurrent writes.
while time.time() - timer < 3.0:
time.sleep(0.5)
有时候,只是让你的反应会采取3秒的完整,你不必担心。
当然,如果您只从一个站点下载,这完全不会对您有任何帮助,但它可能会阻止您被阻止。
我的机器在管理它们的开销之前处理了大约200个线程,从而减慢了进程速度。我以每秒40-50页的速度结束。
urllib & threading(或multiprocessing)软件包有所有你需要做的“蜘蛛”你需要。
你必须做的是从数据库获取网址,并为每个网址启动一个线程或进程 抓取网址。
就像例子(错过数据库的URL检索):
#!/usr/bin/env python
import Queue
import threading
import urllib2
import time
hosts = ["http://yahoo.com", "http://google.com", "http://amazon.com",
"http://ibm.com", "http://apple.com"]
queue = Queue.Queue()
class ThreadUrl(threading.Thread):
"""Threaded Url Grab"""
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
#grabs host from queue
host = self.queue.get()
#grabs urls of hosts and prints first 1024 bytes of page
url = urllib2.urlopen(host)
print url.read(1024)
#signals to queue job is done
self.queue.task_done()
start = time.time()
def main():
#spawn a pool of threads, and pass them queue instance
for i in range(5):
t = ThreadUrl(queue)
t.setDaemon(True)
t.start()
#populate queue with data
for host in hosts:
queue.put(host)
#wait on the queue until everything has been processed
queue.join()
main()
print "Elapsed Time: %s" % (time.time() - start)
我得到的帮助来自一些专家,如他发布了python 2.X代码以供参考。 http://paste.ubuntu.com/24529360/
from multiprocessing.dummy import Pool
import urllib
def download(_id):
success = False
fail_count = 0
url = 'fuck_url/%s'%_id
while not success:
if fail_count>10:
print url,'download faild'
return
try:
urllib.urlretrieve(url,'%s.html'%_id)
success = True
except Exception:
fail_count+=1
pass
if __name__ == '__main__':
pool = Pool(processes=100) # 100 thread
pool.map(download,range(30000))
pool.close()
pool.join()
我更喜欢使用requests
因为它有header
,并可以很容易地添加proxy
。
import requests
hdrs = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(url, headers=hdrs, verify=False)#, proxies=proxyDict)
with open(fullFileName, 'wb') as code:
code.write(r.content)
非并发的,但很扎实,细致(老!)工具带有Python安装(或http://svn.python.org/view/python/trunk/Tools/webchecker在线浏览/) - 确保在你的并发实现中,你应用了所有的礼貌和预防措施(robots.txt解析等等;-)。 – 2009-09-29 15:01:12
@Alex,是否有与网络爬行相关的所有礼节和预防措施的集中位置? – tgray 2009-09-29 20:41:11