在我自己的程序中构建scrapy spider,我不想从命令行调用scrapy)

2024-10-06 11:24:12 发布

您现在位置:Python中文网/ 问答频道 /正文

与这个问题类似: stackoverflow: running-multiple-spiders-in-scrapy

我在想,我能从另一个python程序中运行一个完整的垃圾项目吗?假设我想构建一个需要抓取几个不同站点的完整程序,并为每个站点构建完整的scrapy项目。在

我不想从命令行运行,而是运行这些spider并从中获取信息。在

我可以在pythonok中使用mongoDB,我已经可以构建包含spider的垃圾项目,但现在只需将它们合并到一个应用程序中。在

我想运行应用程序一次,并有能力从我自己的程序控制多个蜘蛛

为什么要这样做?这个应用程序也可以使用API连接到其他站点,并且需要实时比较API站点和刮取站点的结果。我不想再从命令行调用scrapy,这一切都是为了自包含的。在

(我最近问了很多关于刮削的问题,因为我正在努力寻找合适的解决方案来构建)

谢谢:)


Tags: 项目命令行in程序api应用程序站点multiple
2条回答

是的,当然可以;)

The idea (inspired from this blog post)将创建一个worker,然后在您自己的Python脚本中使用它:

from scrapy import project, signals
from scrapy.conf import settings
from scrapy.crawler import CrawlerProcess
from scrapy.xlib.pydispatch import dispatcher
from multiprocessing.queues import Queue
import multiprocessing

class CrawlerWorker(multiprocessing.Process):

    def __init__(self, spider, result_queue):
        multiprocessing.Process.__init__(self)
        self.result_queue = result_queue

        self.crawler = CrawlerProcess(settings)
        if not hasattr(project, 'crawler'):
            self.crawler.install()
        self.crawler.configure()

        self.items = []
        self.spider = spider
        dispatcher.connect(self._item_passed, signals.item_passed)

    def _item_passed(self, item):
        self.items.append(item)

    def run(self):
        self.crawler.crawl(self.spider)
        self.crawler.start()
        self.crawler.stop()
        self.result_queue.put(self.items)

使用示例:

^{pr2}$

另一种方法是使用system()执行scrapy crawl命令

马克西姆·罗兰特的回答最终解决了我用自己的脚本构建一个难看的蜘蛛的问题。它解决了我遇到的两个问题:

  1. 它允许连续调用蜘蛛两次(在scrapy教程中的简单示例中,这会导致崩溃,因为您不能两次启动twister reactor)

  2. 它允许将变量从spider返回到脚本中。

只有一件事:这个例子不适用于我现在使用的scrapy版本(scrapy 1.5.2)和python3.7

在玩了一些代码之后,我得到了一个工作示例,我想与大家分享。我还有一个问题,请看下面的脚本。它是一个独立的脚本,所以我也添加了一个spider

import logging
import multiprocessing as mp

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.signals import item_passed
from scrapy.utils.project import get_project_settings
from scrapy.xlib.pydispatch import dispatcher


class CrawlerWorker(mp.Process):
    name = "crawlerworker"

    def __init__(self, spider, result_queue):
        mp.Process.__init__(self)
        self.result_queue = result_queue
        self.items = list()
        self.spider = spider
        self.logger = logging.getLogger(self.name)

        self.settings = get_project_settings()
        self.logger.setLevel(logging.DEBUG)
        self.logger.debug("Create CrawlerProcess with settings {}".format(self.settings))
        self.crawler = CrawlerProcess(self.settings)

        dispatcher.connect(self._item_passed, item_passed)

    def _item_passed(self, item):
        self.logger.debug("Adding Item {} to {}".format(item, self.items))
        self.items.append(item)

    def run(self):
        self.logger.info("Start here with {}".format(self.spider.urls))
        self.crawler.crawl(self.spider, urls=self.spider.urls)
        self.crawler.start()
        self.crawler.stop()
        self.result_queue.put(self.items)


class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def __init__(self, **kw):
        super(QuotesSpider, self).__init__(**kw)

        self.urls = kw.get("urls", [])

    def start_requests(self):
        for url in self.urls:
            yield scrapy.Request(url=url, callback=self.parse)
        else:
            self.log('Nothing to scrape. Please pass the urls')

    def parse(self, response):
        """ Count number of The's on the page """
        the_count = len(response.xpath("//body//text()").re(r"The\s"))
        self.log("found {} time 'The'".format(the_count))
        yield {response.url: the_count}


def report_items(message, item_list):
    print(message)
    if item_list:
        for cnt, item in enumerate(item_list):
            print("item {:2d}: {}".format(cnt, item))
    else:
        print(f"No items found")


url_list = [
    'http://quotes.toscrape.com/page/1/',
    'http://quotes.toscrape.com/page/2/',
    'http://quotes.toscrape.com/page/3/',
    'http://quotes.toscrape.com/page/4/',
]

result_queue1 = mp.Queue()
crawler = CrawlerWorker(QuotesSpider(urls=url_list[:2]), result_queue1)
crawler.start()
# wait until we are done with the crawl
crawler.join()

# crawl again
result_queue2 = mp.Queue()
crawler = CrawlerWorker(QuotesSpider(urls=url_list[2:]), result_queue2)
crawler.start()
crawler.join()
#
report_items("First result", result_queue1.get())
report_items("Second result", result_queue2.get())

如您所见,代码几乎完全相同,只是有些导入由于scrapy API的更改而发生了更改。在

有一件事:我收到一个带有pydistatch导入的不推荐警告:

^{pr2}$

我找到了here如何解决这个问题。但是,我不能让这个工作。有人知道如何应用from\u crawler类方法来消除弃用警告吗?在

相关问题 更多 >