我正在嘗試使用Twisted製作一個相當簡單的網頁抓取工具。我有它的工作,但每當我嘗試颳了幾百個網站,它會無限期地掛起,因爲沒有明顯的原因。一切似乎都行得通,除非它最終停止了一些遺留下來處理的網站。Twisted DeferredList只在其一半的時間運行其回調
我在這裏使用教程: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()
我運行的代碼在一個較大的程序這一部分,因此隊列。
任何關於使DeferredList始終激發的建議?或者關於爲什麼它只發射一半時間的想法,而另一半沒有任何例外的失敗?
這很令人沮喪,尤其是因爲它適用於少量的URL(1-100),但在放大時失敗。我是Twisted的新手,所以我可能只是搞砸了一些錯誤,但我無法弄清楚什麼,或者如何修復它......
另外,在任何人回答'使用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()
看看[Scrapy](http://doc.scrapy.org/en/latest/intro/tutorial.html)。它建立在Twisted之上,可以說是最好的抓取框架之一。 – Blender
我在我的帖子中說過我不能使用Scrapy。這個程序必須可編譯爲一個exe文件,而且我不能使用Scrapy編譯任何東西,因爲它有奇怪的自定義導入模塊。 – oiez
我從來沒有與py2exe和Scrapy的問題。什麼不適合你? – Blender