Feed 导出

在实现爬虫时,最常需要的功能之一就是能够正确地存储抓取到的数据,并且通常这意味着生成一个包含抓取数据的“导出文件”(通常称为“导出 Feed”),以便其他系统使用。

Scrapy 通过 Feed 导出功能开箱即用地提供了此功能,它允许您使用多种序列化格式和存储后端生成包含抓取项目的 Feed。

此页面提供了所有 Feed 导出功能的详细文档。如果您正在寻找分步指南,请查看 Zyte 的导出指南

序列化格式

为了序列化抓取的数据,Feed 导出使用 项目导出器。这些格式开箱即用地受支持。

但是,您还可以通过 FEED_EXPORTERS 设置扩展受支持的格式。

JSON

JSON Lines

CSV

  • FEEDS 设置中 format 键的值:csv

  • 使用的导出器:CsvItemExporter

  • 要指定要导出的列、它们的顺序和列名,请使用 FEED_EXPORT_FIELDS。其他 Feed 导出器也可以使用此选项,但对于 CSV 来说它很重要,因为与许多其他导出格式不同,CSV 使用固定的标题。

XML

Pickle

Marshal

存储

使用 Feed 导出时,您可以使用一个或多个 URI(通过 FEEDS 设置)定义存储 Feed 的位置。Feed 导出支持多种存储后端类型,这些类型由 URI 方案定义。

开箱即用地支持的存储后端包括

如果所需的外部库不可用,则某些存储后端可能不可用。例如,如果未安装 boto3 库,则 S3 后端不可用。

存储 URI 参数

存储 URI 还可以包含在创建 Feed 时替换的参数。这些参数包括

  • %(time)s - 在创建 Feed 时替换为时间戳

  • %(name)s - 替换为爬虫名称

任何其他命名参数都将替换为名称相同的爬虫属性。例如,%(site_id)s 将在创建 Feed 时替换为 spider.site_id 属性。

以下是一些示例来说明

  • 使用每个爬虫一个目录存储到 FTP 中

  • 使用每个爬虫一个目录存储到 S3 中

    • s3://mybucket/scraping/feeds/%(name)s/%(time)s.json

注意

爬虫参数 成为爬虫属性,因此它们也可以用作存储 URI 参数。

存储后端

本地文件系统

Feed 存储在本地文件系统中。

  • URI 方案:file

  • URI 示例:file:///tmp/export.csv

  • 所需的外部库:无

请注意,对于本地文件系统存储(仅限于此),如果您指定绝对路径(例如 /tmp/export.csv)(仅限 Unix 系统),则可以省略该方案。或者,您也可以使用 pathlib.Path 对象。

FTP

Feed 存储在 FTP 服务器上。

  • URI 方案:ftp

  • URI 示例:ftp://user:[email protected]/path/to/export.csv

  • 所需的外部库:无

FTP 支持两种不同的连接模式:主动或被动。Scrapy 默认使用被动连接模式。要改为使用主动连接模式,请将 FEED_STORAGE_FTP_ACTIVE 设置设置为 True

此存储后端中 FEEDSoverwrite 键的默认值为:True

注意

overwrite 中的 True 值会导致您丢失数据的先前版本。

此存储后端使用 延迟文件传递

S3

Feed 存储在 Amazon S3 上。

  • URI 方案:s3

  • URI 示例

    • s3://mybucket/path/to/export.csv

    • s3://aws_key:aws_secret@mybucket/path/to/export.csv

  • 所需外部库:boto3 >= 1.20.0

AWS 凭证可以通过 URI 中的用户名/密码传递,也可以通过以下设置传递

您还可以使用以下设置定义自定义 ACL、自定义端点和导出 Feed 的区域名称

此存储后端中 FEEDSoverwrite 键的默认值为:True

注意

overwrite 中的 True 值会导致您丢失数据的先前版本。

此存储后端使用 延迟文件传递

Google Cloud Storage (GCS)

2.3 版新增功能。

Feed 存储在Google Cloud Storage 上。

  • URI 方案:gs

  • URI 示例

    • gs://mybucket/path/to/export.csv

  • 所需外部库:google-cloud-storage

有关身份验证的更多信息,请参阅Google Cloud 文档

您可以通过以下设置设置项目 ID访问控制列表 (ACL)

此存储后端中 FEEDSoverwrite 键的默认值为:True

注意

overwrite 中的 True 值会导致您丢失数据的先前版本。

此存储后端使用 延迟文件传递

标准输出

Feed 写入到 Scrapy 进程的标准输出。

  • URI 方案:stdout

  • URI 示例:stdout:

  • 所需的外部库:无

延迟文件交付

如上所述,一些描述的存储后端使用延迟文件交付。

这些存储后端不会在抓取这些项目时将项目上传到 Feed URI。相反,Scrapy 将项目写入一个临时的本地文件,并且只有在所有文件内容都写入后(即在抓取结束时),该文件才会上传到 Feed URI。

如果您希望在使用这些存储后端之一时尽早开始项目交付,请使用FEED_EXPORT_BATCH_ITEM_COUNT 将输出项目拆分为多个文件,每个文件具有指定的最大项目数。这样,一旦某个文件达到最大项目数,该文件就会交付到 Feed URI,从而允许项目交付在抓取结束之前开始。

项目过滤

2.6.0 版新增功能。

您可以通过在Feed 选项中使用item_classes选项来过滤要允许用于特定 Feed 的项目。只有指定类型的项目才会添加到 Feed 中。

item_classes选项由ItemFilter类实现,它是item_filterFeed 选项的默认值。

您可以通过实现ItemFilteraccepts方法并以feed_options作为参数来创建您自己的自定义过滤类。

例如

class MyCustomFilter:
    def __init__(self, feed_options):
        self.feed_options = feed_options

    def accepts(self, item):
        if "field1" in item and item["field1"] == "expected_data":
            return True
        return False

您可以将自定义过滤类分配给Feed 的选项中的item_filter。有关示例,请参阅FEEDS

ItemFilter

class scrapy.extensions.feedexport.ItemFilter(feed_options: dict[str, Any] | None)[source]

这将由 FeedExporter 用于确定是否应允许将项目导出到特定 Feed。

参数:

feed_options (dict) – FeedExporter 传递的特定于 Feed 的选项

accepts(item: Any) bool[source]

如果应导出item,则返回True,否则返回False

参数:

item (Scrapy 项目) – 用户想要检查是否可接受的已抓取项目

返回值:

如果接受,则为True,否则为False

返回类型:

bool

后处理

2.6.0 版新增功能。

Scrapy 提供了一个选项来激活插件,以在将 Feed 导出到 Feed 存储之前对其进行后处理。除了使用内置插件之外,您还可以创建自己的插件

这些插件可以通过 Feed 的postprocessing选项激活。该选项必须传递一个按您希望 Feed 处理的顺序排列的后处理插件列表。这些插件可以声明为导入字符串,也可以使用插件的导入类。插件的参数可以通过 Feed 选项传递。有关示例,请参阅Feed 选项

内置插件

class scrapy.extensions.postprocessing.GzipPlugin(file: BinaryIO, feed_options: dict[str, Any])[source]

使用gzip压缩接收到的数据。

接受的feed_options参数

  • gzip_compresslevel

  • gzip_mtime

  • gzip_filename

有关参数的更多信息,请参阅gzip.GzipFile

class scrapy.extensions.postprocessing.LZMAPlugin(file: BinaryIO, feed_options: dict[str, Any])[source]

使用lzma压缩接收到的数据。

接受的feed_options参数

  • lzma_format

  • lzma_check

  • lzma_preset

  • lzma_filters

注意

在 pypy 7.3.1 及更早版本中无法使用lzma_filters

有关参数的更多信息,请参阅lzma.LZMAFile

class scrapy.extensions.postprocessing.Bz2Plugin(file: BinaryIO, feed_options: dict[str, Any])[source]

使用 bz2 压缩接收到的数据。

接受的feed_options参数

  • bz2_compresslevel

有关参数的更多信息,请参阅 bz2.BZ2File

自定义插件

每个插件都是一个类,必须实现以下方法

__init__(self, file, feed_options)

初始化插件。

参数:
  • file – 类文件对象,至少实现了 writetellclose 方法

  • feed_options (dict) – 供稿特定的 选项

write(self, data)

处理并将 data (bytesmemoryview) 写入插件的目标文件。它必须返回写入的字节数。

close(self)

清理插件。

例如,您可能希望关闭一个文件包装器,您可能已使用该包装器来压缩写入在 __init__ 方法中接收的文件中的数据。

警告

不要从 __init__ 方法中关闭文件。

要将参数传递给您的插件,请使用 供稿选项。然后,您可以从插件的 __init__ 方法中访问这些参数。

设置

这些是用于配置供稿导出的设置

FEEDS

版本 2.1 中的新功能。

默认值:{}

一个字典,其中每个键都是一个供稿 URI(或 pathlib.Path 对象),每个值都是一个嵌套字典,包含特定供稿的配置参数。

此设置对于启用供稿导出功能是必需的。

有关支持的 URI 方案,请参阅 存储后端

例如

{
    'items.json': {
        'format': 'json',
        'encoding': 'utf8',
        'store_empty': False,
        'item_classes': [MyItemClass1, 'myproject.items.MyItemClass2'],
        'fields': None,
        'indent': 4,
        'item_export_kwargs': {
           'export_empty_fields': True,
        },
    },
    '/home/user/documents/items.xml': {
        'format': 'xml',
        'fields': ['name', 'price'],
        'item_filter': MyCustomFilter1,
        'encoding': 'latin1',
        'indent': 8,
    },
    pathlib.Path('items.csv.gz'): {
        'format': 'csv',
        'fields': ['price', 'name'],
        'item_filter': 'myproject.filters.MyCustomFilter2',
        'postprocessing': [MyPlugin1, 'scrapy.extensions.postprocessing.GzipPlugin'],
        'gzip_compresslevel': 5,
    },
}

以下是接受的键的列表以及如果未为特定供稿定义提供该键则用作回退值的设置

FEED_EXPORT_ENCODING

默认值:None

供稿要使用的编码。

如果未设置或设置为 None(默认值),则对除了 JSON 输出之外的所有内容都使用 UTF-8,出于历史原因,JSON 输出使用安全的数字编码(\uXXXX 序列)。

如果您希望 JSON 也使用 UTF-8,请使用 utf-8

版本 2.8 中的更改: startproject 命令现在在生成的 settings.py 文件中将此设置设置为 utf-8

FEED_EXPORT_FIELDS

默认值:None

使用 FEED_EXPORT_FIELDS 设置定义要导出的字段、它们的顺序及其输出名称。有关更多信息,请参阅 BaseItemExporter.fields_to_export

FEED_EXPORT_INDENT

默认值:0

在每个级别上用于缩进输出的空格数。如果 FEED_EXPORT_INDENT 是一个非负整数,则数组元素和对象成员将以该缩进级别进行漂亮打印。缩进级别为 0(默认值)或负数,将把每个项目放在新的一行上。None 选择最紧凑的表示形式。

目前仅由 JsonItemExporterXmlItemExporter 实现,即当您导出到 .json.xml 时。

FEED_STORE_EMPTY

默认值:True

是否导出空 Feed(即没有项目的 Feed)。如果 False,并且没有项目要导出,则不会创建新文件,也不会修改现有文件,即使启用了 覆盖 Feed 选项

FEED_STORAGES

默认值:{}

一个字典,包含项目支持的其他 Feed 存储后端。键是 URI 方案,值是存储类的路径。

FEED_STORAGE_FTP_ACTIVE

默认值:False

将 Feed 导出到 FTP 服务器时是否使用主动连接模式(True)还是使用被动连接模式(False,默认值)。

有关 FTP 连接模式的信息,请参阅 主动 FTP 和被动 FTP 有什么区别?

FEED_STORAGE_S3_ACL

默认值:''(空字符串)

一个字符串,包含项目导出到 Amazon S3 的 Feed 的自定义 ACL。

有关可用值的完整列表,请访问 Amazon S3 文档中的 预设 ACL 部分。

FEED_STORAGES_BASE

默认值

{
    "": "scrapy.extensions.feedexport.FileFeedStorage",
    "file": "scrapy.extensions.feedexport.FileFeedStorage",
    "stdout": "scrapy.extensions.feedexport.StdoutFeedStorage",
    "s3": "scrapy.extensions.feedexport.S3FeedStorage",
    "ftp": "scrapy.extensions.feedexport.FTPFeedStorage",
}

一个字典,包含 Scrapy 支持的内置 Feed 存储后端。可以通过在 FEED_STORAGES 中将其 URI 方案分配为 None 来禁用这些后端中的任何一个。例如,要禁用内置的 FTP 存储后端(不进行替换),请将其放在 settings.py

FEED_STORAGES = {
    "ftp": None,
}

FEED_EXPORTERS

默认值:{}

一个字典,包含项目支持的其他导出器。键是序列化格式,值是 项目导出器 类的路径。

FEED_EXPORTERS_BASE

默认值

{
    "json": "scrapy.exporters.JsonItemExporter",
    "jsonlines": "scrapy.exporters.JsonLinesItemExporter",
    "jsonl": "scrapy.exporters.JsonLinesItemExporter",
    "jl": "scrapy.exporters.JsonLinesItemExporter",
    "csv": "scrapy.exporters.CsvItemExporter",
    "xml": "scrapy.exporters.XmlItemExporter",
    "marshal": "scrapy.exporters.MarshalItemExporter",
    "pickle": "scrapy.exporters.PickleItemExporter",
}

一个字典,包含 Scrapy 支持的内置 Feed 导出器。可以通过在 FEED_EXPORTERS 中将其序列化格式分配为 None 来禁用这些导出器中的任何一个。例如,要禁用内置的 CSV 导出器(不进行替换),请将其放在 settings.py

FEED_EXPORTERS = {
    "csv": None,
}

FEED_EXPORT_BATCH_ITEM_COUNT

版本 2.3.0 中的新功能。

默认值:0

如果分配了一个大于 0 的整数,则 Scrapy 会生成多个输出文件,每个输出文件最多存储指定数量的项目。

生成多个输出文件时,必须在 Feed URI 中使用以下占位符中的至少一个来指示如何生成不同的输出文件名

  • %(batch_time)s - 在创建 Feed 时替换为时间戳(例如 2020-03-28T14-45-08.237134

  • %(batch_id)d - 替换为批次的从 1 开始的序列号。

    使用 printf 样式字符串格式化 来更改数字格式。例如,要使批次 ID 成为一个 5 位数字(根据需要引入前导零),请使用 %(batch_id)05d(例如 3 变成 00003123 变成 00123)。

例如,如果您的设置包含

FEED_EXPORT_BATCH_ITEM_COUNT = 100

并且您的 crawl 命令行是

scrapy crawl spidername -o "dirname/%(batch_id)d-filename%(batch_time)s.json"

上面的命令行可以生成如下目录树

->projectname
-->dirname
--->1-filename2020-03-28T14-45-08.237134.json
--->2-filename2020-03-28T14-45-09.148903.json
--->3-filename2020-03-28T14-45-10.046092.json

其中第一个和第二个文件正好包含 100 个项目。最后一个包含 100 个或更少的项目。

FEED_URI_PARAMS

默认值:None

一个字符串,包含一个函数的导入路径,用于设置要应用于 Feed URI 的参数,使用 printf 样式字符串格式化

函数签名应如下所示

scrapy.extensions.feedexport.uri_params(params, spider)

返回一个 dict,其中包含键值对,用于使用 printf 样式字符串格式化 应用于 Feed URI。

参数:

注意

该函数应返回一个新字典,就地修改接收到的 params 已被弃用。

例如,要在 Feed URI 中包含源蜘蛛的 name

  1. 在项目中的某个地方定义以下函数

    # myproject/utils.py
    def uri_params(params, spider):
        return {**params, "spider_name": spider.name}
    
  2. 在您的设置中将 FEED_URI_PARAMS 指向该函数

    # myproject/settings.py
    FEED_URI_PARAMS = "myproject.utils.uri_params"
    
  3. 在您的 Feed URI 中使用 %(spider_name)s

    scrapy crawl <spider_name> -o "%(spider_name)s.jsonl"