Skip to content

Scrapy框架【扩展】

更新: 2025/2/24 字数: 0 字 时长: 0 分钟

另外还有几个实用方法

  • open_spider(self, spider) 其中 spider 即被开启的 Spider 对象,当 Spider 开启的时候会自动调用该方法,这里我们可以做一些初始化操作,如开启数据库连接等。
  • close_spider(spider) 其中 spider 即被关闭的 Spider 对象,当Spider关闭的时候会自动调用该方法,这里我们可以做一些收尾操作,如关闭数据库连接等。
  • from_scrawler(cls, crawler) 是一个类方法,用 @classmethod 标识,其中 cls 就是 Class,crawler 就是 Crawler 对象,通过它我们可以拿到 Scrapy 的所有核心组件,如全局配置的每个信息。方法最后返回一个 Class 实例。

警告

每提取一条数据都会调用一次 process_item() 方法,而 open_spider() 方法和 close_spider() 方法在只会在整个爬虫流程中启动、关闭爬虫时,对项目管道操作调用一次。

前面我们已经了解了 Scrapy 的常用的基本组件,如 SpiderDownloder MiddlewareSpider MiddlewareItem Pipeline 等,其实另外还有一个比较实用的组件 Extension,中文翻译叫作“扩展”。利用它,我们可以完成我们想自定义的功能。

扩展介绍

Scrapy 提供了一个 Extension 机制,可以让我们添加和扩展一些自定义的功能。利用 Extension 我们可以注册一些处理方法并监听 Scrapy 运行过程中的各个信号,做到在发生某个事件时执行我们自定义的方法。

内置扩展

Scrapy 已经内置了一些 Extension,如 LogStats 用于记录一些基本的爬取信息,比如爬取的页面数量、提取的 Item 数量等,Corestates 用于统计爬取过程中的核心统计信息,如开始爬取时间、爬取结束时间等。

定制扩展

我们也可以实现自定义的 Extension,主要分为两步:

  1. 实现一个 Python 类,然后实现对应的处理方法,如实现一个 spider_opened 方法用于处理 Spider 开始爬取时执行的操作,可以接收一个 spider 参数并对其进行操作。
  2. 定义 from_crawler 类方法,其第一个参数是 cls 类对象,第二个参数是 crawler。利用 crawlersignals 对象将 Scrapy 的各个信号和已经定义的处理方法关联起来。

实现方法

我们在项目文件夹下新建一个 extensions.py 文件,添加如下代码:这里我们定义了一个 NotificationExtension 类,实现了 spider_openedspider_closedspider_scraped 方法,分别对应爬取开始、爬取结束、爬取到 Item 的处理。接着调用了 requests 向目标地址发送对应的事件,其中包含两个字段:一个是 event,代表事件的名称;另一个是 data,代表一些附加数据,如 Spider 的名称、Item 的具体内容。

python
import requests

# 接收消息地址
NOTIFICATION_URL = 'http://localhost:5000/notify'

class NotificationExtension(object):
    # 爬取开始
    def spider_opened(self, spider):
        requests.post(NOTIFICATION_URL, json={
            'event': 'SPIDER_OPENED',
            'data': {'spider_name': spider.name}
        })
    # 爬取结束
    def spider_closed(self, spider):
        requests.post(NOTIFICATION_URL, json={
            'event': 'SPIDER_CLOSED',
            'data': {'spider_name': spider.name}
        })
    # 爬取Item
    def spider_scraped(self, spider):
        requests.post(NOTIFICATION_URL, json={
            'event': 'ITEM_SCRAPED',
            'data': {'spider_name': spider.name, 'item': dict(item)}
        })

信号关联

现在启用 NotificationExtension 其实没有任何效果的,我们还需要将这些方法和对应的 Scrapy 信号关联起来,再在 NotificationExtension 类中添加如下类方法:其中 from_crawler 是一个类方法,第一个参数就是 cls 类对象,第二个参数 crawler 代表了 Scrapy 运行过程中全局的 Crawler 对象。在 Crawler 对象里有一个子对象叫作 signals,通过调用 signals 对象的 connect 方法,我们可以将 Scrapy 运行过程中的某个信号和我们自定义的处理方法关联起来。这样在某个事件发生的时候,被关联的处理方法就会被调用。比如这里,connect 方法第一个参数我们传入 ext.spider_opened 这个对象,而 ext 是由 cls 类对象初始化的,所以 ext.spider_opened 就代表我们在 NotificationExtension 类中定义的 spider_opened 方法。connect 方法的第二个参数我们传入了 signals.spider_opened 这个对象,这就指定了 spider_opened 方法可以被 spider_opened 信号触发。这样在 Spider 开始运行的时候,会产生 signals.spider_opened 信号,NotificationExtension 类中定义的 spider_opened 方法就会被调用了。

python
from scrapy import signals

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

启用配置

Downloder MiddlewareSpider Middleware 以及 Item Pipeline 一样, Extension 也是通过 settings.py 中的配置来控制是否被启用,这个配置项就是 EXTENSION 变量。例如:

python
# 开启CoreStats和TelnetConsole这两个EXTENSION
EXTENSIONS = {
    # 启用NotificationExtension定制扩展
    'scrapy.extensions.NotificationExtension': 500,
    # 启用CoreStats内置扩展
    'scrapy.extensions.corestats.CoreStats': 500,
    # 启用TelnetConsole内置扩展
    'scrapy.extensions.telnet.TelnetConsole': 501
}