2013-04-17 37 views
1

我正在嘗試使用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() 
+0

看看[Scrapy](http://doc.scrapy.org/en/latest/intro/tutorial.html)。它建立在Twisted之上,可以說是最好的抓取框架之一。 – Blender

+0

我在我的帖子中說過我不能使用Scrapy。這個程序必須可編譯爲一個exe文件,而且我不能使用Scrapy編譯任何東西,因爲它有奇怪的自定義導入模塊。 – oiez

+0

我從來沒有與py2exe和Scrapy的問題。什麼不適合你? – Blender

回答

1

它看起來像你在使用雙絞線的混合標準庫的多庫。如果你對此不太在意,隨機的事情就會破裂。例如,反應堆可能在一個過程中滿足一些I/O事件,其餘的則在另一個過程中。

這是很難說的肯定這就是問題所在,不過,因爲在這個問題的示例代碼是不完整的(你可能會認爲該程序的其餘部分是枯燥的,但所有的一起那些枯燥的細節是什麼定義程序的行爲,所以它們對你的問題其實非常重要)。

+0

這不是我認爲它很無聊,我只是不認爲它是相關的。即使在運行完全獨立的代碼版本時,我也可以複製該錯誤,而無需進行任何多處理。 忽略所有隊列,將它們註釋掉並用打印語句運行程序。它與URL的大型列表完全相同。我只用563跑它,它處理562個網站,現在掛在這裏什麼都不做。沒有多處理,沒有隊列,只是打印每個URL,因爲它是由回調處理。 – oiez

+2

太好了。使用完全獨立版本的代碼調試問題應該更簡單。你可以發佈嗎? –

+0

當然,我會用可以直接運行的獨立版本編輯我的帖子。 – oiez

相關問題