Feed 导出

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

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

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

序列化格式

为了序列化抓取的数据,feed导出使用Item exporters。这些格式是开箱即用的:

但你也可以通过 FEED_EXPORTERS 设置来扩展支持的格式。

JSON

  • FEEDS 设置中 format 键的值:json

  • 使用的导出器:JsonItemExporter

  • 如果您在使用JSON处理大量数据时,请参阅此警告

JSON行

CSV

  • FEEDS 设置中 format 键的值:csv

  • 使用的导出器:CsvItemExporter

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

XML

Pickle

元帅

存储

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

支持的存储后端包括:

如果所需的外部库不可用,某些存储后端可能不可用。例如,只有在安装了boto3库时,S3后端才可用。

存储URI参数

存储URI还可以包含在创建feed时被替换的参数。这些参数是:

  • %(time)s - 在创建feed时被时间戳替换

  • %(name)s - 被蜘蛛名称替换

任何其他命名参数都会被同名的蜘蛛属性替换。例如,%(site_id)s 在创建feed时会被 spider.site_id 属性替换。

以下是一些示例来说明:

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

    • ftp://user:password@ftp.example.com/scraping/feeds/%(name)s/%(time)s.json

  • 使用每个爬虫一个目录的方式存储在S3中:

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

注意

Spider arguments 成为蜘蛛属性,因此它们也可以用作存储URI参数。

存储后端

本地文件系统

数据源存储在本地文件系统中。

  • URI 方案: file

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

  • 所需的外部库:无

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

FTP

数据存储在FTP服务器中。

  • URI 方案: ftp

  • 示例URI: ftp://user:pass@ftp.example.com/path/to/export.csv

  • 所需的外部库:无

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

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

注意

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

此存储后端使用延迟文件交付

S3

数据源存储在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 中的用户/密码传递,也可以通过以下设置传递:

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

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

注意

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

此存储后端使用延迟文件交付

Google 云存储 (GCS)

新版本2.3新增。

数据源存储在Google Cloud Storage上。

  • URI 方案: gs

  • 示例URI:

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

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

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

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

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

注意

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

此存储后端使用延迟文件交付

标准输出

feeds被写入Scrapy进程的标准输出。

  • URI 方案: stdout

  • 示例URI: stdout:

  • 所需的外部库:无

延迟文件交付

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

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

如果您希望在使用这些存储后端时更早开始项目交付,请使用FEED_EXPORT_BATCH_ITEM_COUNT将输出项目分割成多个文件,每个文件包含指定的最大项目数。这样,一旦文件达到最大项目数,该文件就会被交付到feed URI,从而允许项目交付在爬取结束之前就开始。

项目过滤

新版本2.6.0中新增。

您可以通过在feeds options中使用item_classes选项来筛选您希望允许特定订阅源的项目。只有指定类型的项目才会被添加到订阅源中。

item_classes 选项由 ItemFilter 类实现,该类是 item_filter feed option 的默认值。

你可以通过实现ItemFilter的方法accepts并将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

项目过滤器

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

这将由FeedExporter用于决定是否允许将项目导出到特定feed。

Parameters:

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

accepts(item: Any) bool[源代码]

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

Parameters:

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

Returns:

True 如果被接受,False 否则

Return type:

bool

后处理

新版本2.6.0中新增。

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

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

内置插件

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

注意

lzma_filters 不能在 pypy 7.3.1 及更早版本中使用。

有关参数的更多信息,请参见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)

初始化插件。

Parameters:
  • file – 类似文件的对象,至少实现了writetellclose方法

  • feed_options (dict) – 特定于feed的 选项

write(self, data)

处理和写入数据 (bytesmemoryview) 到插件的目标文件中。 它必须返回写入的字节数。

close(self)

清理插件。

例如,您可能想要关闭一个文件包装器,该包装器可能用于压缩写入到在__init__方法中接收的文件中的数据。

警告

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

要向您的插件传递参数,请使用feed options。然后,您可以从插件的__init__方法中访问这些参数。

设置

这些是用于配置feed导出的设置:

动态

新版本2.1新增。

默认值:{}

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

此设置是启用数据导出功能所必需的。

请参阅存储后端以了解支持的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(默认),则对所有内容使用UTF-8编码,除了JSON输出, 由于历史原因,JSON输出使用安全的数字编码(\uXXXX序列)。

如果你想在JSON中也使用UTF-8,请使用utf-8

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

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

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

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

FEED_STORAGE_S3_ACL

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

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

有关可用值的完整列表,请访问Amazon S3文档中的Canned 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存储后端的字典。你可以通过将None分配给它们的URI方案来禁用这些后端中的任何一个,例如在FEED_STORAGES中。例如,要禁用内置的FTP存储后端(无需替换),请将此放入你的settings.py中:

FEED_STORAGES = {
    "ftp": None,
}

FEED_EXPORTERS

默认值:{}

一个包含您的项目支持的额外导出器的字典。键是序列化格式,值是指向Item exporter类的路径。

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-style string formatting来 更改数字格式。例如,要使批次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

一个字符串,包含用于设置参数的函数的导入路径,这些参数将使用 printf-style string formatting 应用到 feed URI。

函数签名应如下所示:

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

返回一个键值对的dict,使用printf-style字符串格式化应用到feed URI。

Parameters:

注意

该函数应返回一个新的字典,不建议直接修改接收到的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"