Lzh on GitHub

Scrapy 的插件系统是一个框架,它统一了对扩展 Scrapy 核心功能的组件(如中间件、扩展或管道)的管理和配置。它为用户提供了 Scrapy 扩展管理的即插即用体验,并赋予开发人员广泛的配置控制权。

Activating and configuring add-ons (激活和配置插件)

Crawler 初始化期间,会从您的 ADDONS 设置中读取已启用的插件列表。

ADDONS 设置是一个字典,其中每个键是插件类或其导入路径,值是其优先级。

这是一个在项目的 settings.py 中启用两个插件的示例:

ADDONS = {
    'path.to.someaddon': 0,
    SomeAddonClass: 1,
}

Writing your own add-ons (编写您自己的插件)

插件是组件,包含以下一个或两个方法:

update_settings(settings)

此方法在 Crawler 初始化期间被调用。在此处,您应该执行依赖项检查(例如,针对外部 Python 库),并根据需要更新 Settings 对象,例如为该插件启用组件或设置其他扩展所需的配置。

参数

  • settings (Settings) – 存储 Scrapy/组件配置的设置对象。

classmethod update_pre_crawler_settings(cls, settings)

使用此类方法代替 update_settings() 方法来更新预爬虫设置,其值在创建 Crawler 对象之前使用。

参数

  • settings (BaseSettings) – 存储 Scrapy/组件配置的设置对象。

插件设置的设置应使用 addon 优先级(参见填充设置scrapy.settings.BaseSettings.set()):

class MyAddon:
    def update_settings(self, settings):
        settings.set("DNSCACHE_ENABLED", True, "addon")

这允许用户在项目或爬虫配置中覆盖这些设置。

在编辑设置的值而不是完全覆盖它时,通常最好保持其优先级不变。例如,在编辑组件优先级字典时。

如果 update_settings 方法引发 scrapy.exceptions.NotConfigured,则该插件将被跳过。这使得在满足某些条件时才启用插件变得容易。

Fallbacks (回退)

某些插件提供的组件需要回退到“默认”实现,例如,自定义下载处理程序需要通过默认下载处理程序发送它不处理的请求,或者包含一些额外处理但否则使用默认统计信息收集器的统计信息收集器。而且,一个项目可能需要使用几种相同类型的自定义组件,例如两个支持不同类型的自定义请求的自定义下载处理程序,并且仍然需要对其他请求使用默认下载处理程序。为了使此类用例更易于配置,我们建议以以下方式编写此类自定义组件:

  • 自定义组件(例如 MyDownloadHandler)不应继承自默认的 Scrapy 组件(例如 scrapy.core.downloader.handlers.http.HTTPDownloadHandler),而应该能够从特殊设置(例如 MY_FALLBACK_DOWNLOAD_HANDLER)加载回退组件的类,创建它的实例并使用它。
  • 包含这些组件的插件应在其 update_settings() 方法中读取默认设置的当前值(例如 DOWNLOAD_HANDLERS),将该值保存到回退设置中(前面提到的 MY_FALLBACK_DOWNLOAD_HANDLER),并将默认设置设置为插件提供的组件(例如 MyDownloadHandler)。如果回退设置已由用户设置,则不应更改它。

这样,如果存在多个想要修改同一设置的插件,它们都将回退到前一个插件的组件,然后回退到 Scrapy 默认组件。其顺序取决于 ADDONS 设置中的优先级顺序。

Add-on examples (插件示例)

设置一些基本配置:

from myproject.pipelines import MyPipeline

class MyAddon:
    def update_settings(self, settings):
        settings.set("DNSCACHE_ENABLED", True, "addon")
        settings.remove_from_list("METAREFRESH_IGNORE_TAGS", "noscript")
        settings.setdefault_in_component_priority_dict(
            "ITEM_PIPELINES", MyPipeline, 200
        )

提示

在编辑组件优先级字典设置(如 ITEM_PIPELINES)时,请考虑使用 replace_in_component_priority_dict()set_in_component_priority_dict()setdefault_in_component_priority_dict() 等设置方法以避免错误。

检查依赖项:

class MyAddon:
    def update_settings(self, settings):
        try:
            import boto
        except ImportError:
            raise NotConfigured("MyAddon requires the boto library")
        ...

访问爬虫实例:

class MyAddon:
    def __init__(self, crawler) -> None:
        super().__init__()
        self.crawler = crawler

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)

    def update_settings(self, settings): ...

使用回退组件:

from scrapy.core.downloader.handlers.http import HTTPDownloadHandler
from scrapy.utils.misc import build_from_crawler

FALLBACK_SETTING = "MY_FALLBACK_DOWNLOAD_HANDLER"

class MyHandler:
    lazy = False

    def __init__(self, settings, crawler):
        dhcls = load_object(settings.get(FALLBACK_SETTING))
        self._fallback_handler = build_from_crawler(dhcls, crawler)

    def download_request(self, request, spider):
        if request.meta.get("my_params"):
            # handle the request
            ...
        else:
            return self._fallback_handler.download_request(request, spider)

class MyAddon:
    def update_settings(self, settings):
        if not settings.get(FALLBACK_SETTING):
            settings.set(
                FALLBACK_SETTING,
                settings.getwithbase("DOWNLOAD_HANDLERS")["https"],
                "addon",
            )
        settings["DOWNLOAD_HANDLERS"]["https"] = MyHandler