Twisted DeferredList仅在一半的时间内运行其回调

时间:2013-04-17 23:41:15

标签: python web-scraping multiprocessing twisted

我正在尝试使用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()

1 个答案:

答案 0 :(得分:1)

看起来你正在使用Twisted混合标准库的多处理库。如果你对此不是很小心,随机的事情就会破裂。例如,也许反应堆在一个过程中满足一些I / O事件,而在另一个过程中满足其余事件。

很难说确定这是问题所在,因为问题中的示例代码不完整(您可能认为该程序的其余部分很无聊,但所有这些都很无聊合在一起定义了程序的行为,所以它们对你的问题非常重要。)