我正在尝试使用Twisted制作一个相当简单的网络抓取工具。我有它的工作,但每当我试图刮掉超过几百个网站时,它会无限期地挂起,因为没有明显的原因。一切似乎都有效,除非它在最后停止,有几个站点需要处理。
我在这里使用了教程:http://technicae.cogitat.io/2008/06/async-batching-with-twisted-walkthrough.html作为蓝图。
这是我的代码:
class Spider:
"""Twisted-based html retrieval system."""
def __init__(self, queue, url_list):
self.process_queue = queue
self.start_urls = []
for url in url_list:
self.start_urls.append(url)
def crawl(self):
"""Extracts information from each website in start_urls."""
deferreds = []
sem = defer.DeferredSemaphore(30)
for url in self.start_urls:
d = sem.run(self._crawl, url, self.process_queue)
deferreds.append(d)
dl = defer.DeferredList(deferreds, consumeErrors=1)
dl.addCallback(self.finish, self.process_queue)
dl.addCallback(self.shutdown)
reactor.run()
def _crawl(self, url, queue):
d = getPage(url, timeout=10)
d.addCallback(self.parse, url, queue)
d.addErrback(self.parse_error, url, queue)
return d
def parse(self, result, url, queue):
print 'Parsing:', url
data = {'body': result, 'url': url}
response = Response(data['url'], data['body'])
queue.put(response)
return data
def parse_error(self, result, url, queue):
print 'Errback from:', url
data = {'body': 'error', 'url': url}
response = Response(data['url'], data['body'])
queue.put(response)
return data
def finish(self, results, queue):
for (valid, data) in results:
if valid:
print 'Success:', data['url']
else:
print 'Failed:', data['url']
finish_signal = Response('FINISHED', 'DONE')
queue.put(finish_signal)
def shutdown(self, ignore):
reactor.stop()
我在一个更大的程序中运行这部分代码,因此就是Queue。
任何使DeferredList始终触发的建议?或者想法为什么它只发射了一半的时间,并且在另一半没有任何例外的情况下失败了?
这非常令人沮丧,特别是因为它与少量的URL(1-100)完美配合,但在放大时失败。我是Twisted的新手,所以我可能只是搞错了errbacks,但我无法弄清楚是什么,或者如何修复它......
此外,在任何人回答'使用Scrapy!'之前我不能使用Scrapy,因为我不会进入这里。假设这个程序是我最后的希望,必须工作。
编辑:
完整的独立代码,以便人们可以直接运行它:
import sys
from twisted.internet import defer, reactor
from twisted.web.client import getPage
class SeerSpider:
"""Twisted-based html retrieval system."""
def __init__(self, queue, url_list):
self.process_queue = queue
self.start_urls = []
for url in url_list:
self.start_urls.append(url)
def crawl(self):
"""Extracts information from each website in url_list."""
deferreds = []
sem = defer.DeferredSemaphore(30)
for url in self.start_urls:
d = sem.run(self._crawl, url, self.process_queue)
deferreds.append(d)
dl = defer.DeferredList(deferreds, consumeErrors=True)
dl.addCallback(self.finish, self.process_queue)
dl.addCallback(self.shutdown)
reactor.run()
def _crawl(self, url, queue):
d = getPage(url, timeout=10)
d.addCallback(self.parse, url, queue)
d.addErrback(self.parse_error, url, queue)
return d
def parse(self, result, url, queue):
data = {'body': result, 'url': url}
response = Response(data['url'], data['body'])
print response.url
return data
def parse_error(self, result, url, queue):
data = {'body': 'error','url': url}
response = Response(data['url'], data['body'])
print response.url
return data
def finish(self, results, queue):
finish_signal = Response('FINISHED', 'DONE')
print finish_signal.url
def shutdown(self, ignore):
reactor.stop()
class Response:
def __init__(self, url, text):
self.url = url
self.body = text
url_list = ['http://google.com/', 'http://example.com', 'http://facebook.com'] # this will work, make the list bigger to find the bug
spider = SeerSpider(None, url_list)
spider.crawl()
答案 0 :(得分:1)
看起来你正在使用Twisted混合标准库的多处理库。如果你对此不是很小心,随机的事情就会破裂。例如,也许反应堆在一个过程中满足一些I / O事件,而在另一个过程中满足其余事件。
很难说确定这是问题所在,因为问题中的示例代码不完整(您可能认为该程序的其余部分很无聊,但所有这些都很无聊合在一起定义了程序的行为,所以它们对你的问题非常重要。)