scrapy 在长时间运行的进程中多次执行临时爬网

rur96b6h  于 2022-11-09  发布在  其他
关注(0)|答案(2)|浏览(129)

所以,我创建了这个类,这样我就可以使用Scrapy按需爬行:

from scrapy import signals
from scrapy.crawler import CrawlerProcess, Crawler
from scrapy.settings import Settings

class NewsCrawler(object):

    def __init__(self, spiders=[]):
        self.spiders = spiders
        self.settings = Settings()

    def crawl(self, start_date, end_date):
        crawled_items = []

        def add_item(item):
            crawled_items.append(item)

        process = CrawlerProcess(self.settings)

        for spider in self.spiders:
            crawler = Crawler(spider, self.settings)
            crawler.signals.connect(add_item, signals.item_scraped)
            process.crawl(crawler, start_date=start_date, end_date=end_date)

        process.start()

        return crawled_items

基本上,我有一个长时间运行的进程,我将多次调用上述类的crawl方法,如下所示:

import time

crawler = NewsCrawler(spiders=[Spider1, Spider2])

while True:
    items = crawler.crawl(start_date, end_date)
    # do something with crawled items ...
    time.sleep(3600)

问题是,第二次调用crawl时,将出现以下错误:twisted.internet.error.ReactorNotRestartable .
据我所知,这是因为React堆在停止运行后无法运行。有什么解决办法吗?
谢谢你!

inkz8wg9

inkz8wg91#

这是目前Scrapy(扭曲)的一个限制,使它很难使用Scrapy作为一个lib。
你可以做的是派生一个新的进程,它运行爬行器,并在爬行完成后停止React器。然后你可以等待加入,并在爬行完成后产生一个新的进程。如果你想在主线程中处理项目,你可以将结果发布到队列中。我建议你为项目使用自定义的管道。
看一下下面由我回答:https://stackoverflow.com/a/22202877/2208253
你应该能够应用同样的原理。但是你宁愿使用多处理而不是台球。

5ssjco0h

5ssjco0h2#

根据@bj-blazkowicz的回答,我找到了一个解决方案,它是运行多个蜘蛛时推荐使用的爬虫,如文档www.example.com中所述https://docs.scrapy.org/en/latest/topics/practices.html#run-scrapy-from-a-script
还有另一个Scrapy实用程序,它提供了对爬行过程的更多控制:scrapy.crawler.CrawlerRunner.这个类是一个简单的 Package 器,它封装了一些简单的帮助器来运行多个爬虫程序,但是它不会以任何方式启动或干扰现有的React器。
使用这个类,React器应该在调度蜘蛛后显式运行。如果你的应用程序已经在使用Twisted,并且你想在同一个React器中运行Scrapy,建议你使用CrawlerRunner而不是CrawlerProcess。
主文件中的代码:

from multiprocessing import Process, Queue

from scrapy.crawler import CrawlerRunner
from scrapy.utils.project import get_project_settings
from scrapy.utils.log import configure_logging
from twisted.internet import reactor

# Enable logging for CrawlerRunner

configure_logging()

class CrawlerRunnerProcess(Process):
    def __init__(self, spider, q, *args):
        Process.__init__(self)
        self.runner = CrawlerRunner(get_project_settings())
        self.spider = spider
        self.q = q
        self.args = args

    def run(self):
        deferred = self.runner.crawl(self.spider, self.q, self.args)
        deferred.addBoth(lambda _: reactor.stop())
        reactor.run(installSignalHandlers=False)

# The wrapper to make it run multiple spiders, multiple times

def run_spider(spider, *args):  # optional arguments
    q = Queue()  # optional queue to return spider results
    runner = CrawlerRunnerProcess(spider, q, *args)
    runner.start()
    runner.join()
    return q.get()

您的spider文件中的代码:

class MySpider(Spider):
    name = 'my_spider'

    def __init__(self, q, *args,**kwargs):
        super(MySpider, self).__init__(*args,**kwargs)
        self.q = q  # optional queue
        self.args = args  # optional args

    def parse(self, response):
        my_item = MyItem()

        self.q.put(my_item)
        yield my_item

相关问题