39

我有一个 Django 站点,当用户请求它时会发生刮擦,我的代码会在一个新进程中启动一个 Scrapy spider 独立脚本。自然,这不适用于用户的增加。

像这样的东西:

class StandAloneSpider(Spider):
    #a regular spider

settings.overrides['LOG_ENABLED'] = True
#more settings can be changed...

crawler = CrawlerProcess( settings )
crawler.install()
crawler.configure()

spider = StandAloneSpider()

crawler.crawl( spider )
crawler.start()

我决定使用 Celery 并使用工作人员来排队抓取请求。

但是,我遇到了 Tornado 反应堆无法重新启动的问题。第一个和第二个蜘蛛运行成功,但是后续的蜘蛛会抛出 ReactorNotRestartable 错误。

任何人都可以分享在 Celery 框架中运行 Spider 的任何技巧吗?

4

2 回答 2

37

好的,这就是我如何让 Scrapy 与我的 Django 项目一起工作,该项目使用 Celery 对要抓取的内容进行排队。实际的解决方法主要来自 joehillen 的代码,位于http://snippets.scrapy.org/snippets/13/

首先是tasks.py文件

from celery import task

@task()
def crawl_domain(domain_pk):
    from crawl import domain_crawl
    return domain_crawl(domain_pk)

然后crawl.py文件

from multiprocessing import Process
from scrapy.crawler import CrawlerProcess
from scrapy.conf import settings
from spider import DomainSpider
from models import Domain

class DomainCrawlerScript():

    def __init__(self):
        self.crawler = CrawlerProcess(settings)
        self.crawler.install()
        self.crawler.configure()

    def _crawl(self, domain_pk):
        domain = Domain.objects.get(
            pk = domain_pk,
        )
        urls = []
        for page in domain.pages.all():
            urls.append(page.url())
        self.crawler.crawl(DomainSpider(urls))
        self.crawler.start()
        self.crawler.stop()

    def crawl(self, domain_pk):
        p = Process(target=self._crawl, args=[domain_pk])
        p.start()
        p.join()

crawler = DomainCrawlerScript()

def domain_crawl(domain_pk):
    crawler.crawl(domain_pk)

这里的技巧是“从多处理导入过程”,它解决了 Twisted 框架中的“ReactorNotRestartable”问题。所以基本上 Celery 任务调用“domain_crawl”函数,它一遍又一遍地重用“DomainCrawlerScript”对象来与你的 Scrapy 蜘蛛交互。(我知道我的示例有点多余,但我在设置多个版本的 python 时这样做是有原因的 [我的 django 网络服务器实际上使用的是 python2.4,而我的工作服务器使用的是 python2.7])

在我的示例中,“DomainSpider”只是一个修改过的 Scrapy Spider,它接受一个 url 列表,然后将它们设置为“start_urls”。

希望这可以帮助!

于 2012-07-25T19:34:37.950 回答
13

我在设置文件中将CELERYD_MAX_TASKS_PER_CHILD设置为 1 并解决了这个问题。工作守护进程在每次蜘蛛运行后启动一个新进程,该进程负责处理反应器。

于 2013-08-12T23:43:37.860 回答