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

标签 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()

我正在一个更大的程序中运行这部分代码,因此是队列。

对于使 DeferredList 始终触发有什么建议吗?或者关于为什么它只在一半的时候触发,而另一半却毫无异常(exception)地失败的想法?

这非常令人沮丧,特别是因为它可以完美地处理少量 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()

最佳答案

看起来您正在将标准库的多处理库与 Twisted 的使用混合在一起。如果你对此不太小心,随机的东西就会被破坏。例如,也许 react 器在一个进程中满足某些 I/O 事件,而在另一进程中满足其余事件。

但是,很难肯定地说这就是问题所在,因为问题中的示例代码不完整(您可能认为程序的其余部分很无聊,但所有这些无聊的细节综合起来定义了程序的行为,因此它们实际上对您的问题非常重要)。

关于python - Twisted DeferredList 仅在一半的时间内运行其回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16072148/

相关文章:

python - 如何从滚动网络表格中抓取特定单词?

javascript - 在 JavaScript 更改值之前和之后使用 Nokogiri 和 Ruby 进行抓取

python - 如何使用 multiprocessing.Pool 处理无法 pickle 的函数

Python 多处理 - 如何将 kwargs 传递给函数?

python - CoInitialize() 未定义 - Python 错误

python - 如何从 QTableWidget 项目中获取选定的标题标签?

python - 用户输入 "Heads"或 "Tails"的简单 Python 程序

python - 在变量声明中使用冒号

Python与selenium webscraping无法找到元素

c - 拆分不同文件中的进程