Bootstrap

【Python】如何编写一个Scrapy扩展(Scrapy Extension)


曾经在幽幽暗暗
反反复复中追问
才知道平平淡淡
从从容容才是真
再回首恍然如梦
再回首我心依旧
只有那无尽的长路伴着我
                     🎵 姜育恒《再回首》


Scrapy是一个强大的爬虫框架,它不仅易于使用,而且具有高度的可扩展性。Scrapy的扩展机制允许开发者在爬虫的不同阶段插入自定义的功能,以实现特定的需求。本文将介绍如何编写一个Scrapy扩展,并展示一个实际的例子。

什么是Scrapy扩展

Scrapy扩展是一些可以插入到Scrapy的执行流程中的插件,用于在特定的时机执行自定义代码。这些时机包括引擎启动和停止、调度器事件、下载器事件以及爬虫的各种信号。

创建Scrapy扩展的步骤

  • 编写扩展类
  • 注册扩展
  • 配置Scrapy使用扩展

步骤1:编写扩展类

首先,我们需要创建一个扩展类,这个类将包含我们希望在特定时机执行的代码。以下是一个简单的扩展示例,它在爬虫开始和结束时打印日志信息。

import logging
from scrapy import signals

class MyCustomExtension:
    def __init__(self, stats):
        self.stats = stats
        self.logger = logging.getLogger(__name__)

    @classmethod
    def from_crawler(cls, crawler):
        ext = cls(crawler.stats)
        crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
        return ext

    def spider_opened(self, spider):
        self.logger.info(f"Spider {spider.name} opened: {spider}")

    def spider_closed(self, spider):
        self.logger.info(f"Spider {spider.name} closed: {spider}")

在这个扩展中,我们定义了两个方法 spider_opened 和 spider_closed,它们分别在爬虫开启和关闭时被调用。通过 signals.connect 方法,我们将这两个方法与 Scrapy 的 spider_opened 和 spider_closed 信号连接起来。

步骤2:注册扩展

接下来,我们需要在 settings.py 文件中注册我们的扩展。

EXTENSIONS = {
    'my_project.extensions.MyCustomExtension': 500,
}

这里的 500 是扩展的优先级,数值越小优先级越高。

步骤3:配置Scrapy使用扩展

在 settings.py 文件中,还需要确保我们的扩展能够被 Scrapy 识别和使用。如果没有特殊需求,已经完成的注册步骤即可使扩展生效。

完整示例

为了更好地理解整个过程,我们将创建一个完整的 Scrapy 项目,并添加我们的自定义扩展。

创建Scrapy项目
scrapy startproject my_project
创建扩展文件

在 my_project/my_project/extensions 目录下创建一个 init.py 文件,并添加以下代码:

# my_project/my_project/extensions/__init__.py

import logging
from scrapy import signals

class MyCustomExtension:
    def __init__(self, stats):
        self.stats = stats
        self.logger = logging.getLogger(__name__)

    @classmethod
    def from_crawler(cls, crawler):
        ext = cls(crawler.stats)
        crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
        return ext

    def spider_opened(self, spider):
        self.logger.info(f"Spider {spider.name} opened: {spider}")

    def spider_closed(self, spider):
        self.logger.info(f"Spider {spider.name} closed: {spider}")
配置settings.py

在 my_project/my_project/settings.py 中添加扩展配置:

EXTENSIONS = {
    'my_project.extensions.MyCustomExtension': 500,
}
编写爬虫

创建一个简单的爬虫,在 my_project/my_project/spiders 目录下创建一个 example.py 文件,并添加以下代码:

import scrapy

class ExampleSpider(scrapy.Spider):
    name = "example"
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
            }
运行爬虫

在终端中运行以下命令,查看扩展的日志输出:

scrapy crawl example

你将看到类似以下的输出:

2024-07-26 12:00:00 [my_project.extensions] INFO: Spider example opened: <ExampleSpider 'example' at 0x10b2c4f70>
2024-07-26 12:00:10 [my_project.extensions] INFO: Spider example closed: <ExampleSpider 'example' at 0x10b2c4f70>

总结

本文介绍了如何编写和使用一个Scrapy扩展。通过扩展机制,我们可以在Scrapy的执行过程中插入自定义的逻辑,满足各种特定需求。希望这个示例能帮助你更好地理解和使用Scrapy扩展。如果你有任何问题或建议,欢迎在评论区留言。

;