Item 导出器
抓取到 Item 后,你通常会想把这些 Item 持久化或导出,以便在其他应用程序中使用这些数据。毕竟,这是抓取过程的全部目的。
为此,Scrapy 提供了一系列 Item 导出器,用于不同的输出格式,例如 XML、CSV 或 JSON。
使用 Item 导出器
如果你时间紧张,只想使用 Item 导出器输出抓取到的数据,请参阅 Feed 导出。否则,如果你想了解 Item 导出器的工作原理或需要更多自定义功能(默认导出未涵盖的),请继续阅读下文。
要使用 Item 导出器,必须使用其必需的参数对其进行实例化。每个 Item 导出器需要不同的参数,因此请查阅每个导出器的文档以确定,具体请参见内置 Item 导出器参考。实例化导出器后,你必须
1. 调用 start_exporting()
方法,表示导出过程开始
2. 对于要导出的每个 Item,调用 export_item()
方法
3. 最后调用 finish_exporting()
方法,表示导出过程结束
这里你可以看到一个 Item Pipeline,它使用多个 Item 导出器根据 Item 中某个字段的值将抓取到的 Item 分组到不同的文件中
from itemadapter import ItemAdapter
from scrapy.exporters import XmlItemExporter
class PerYearXmlExportPipeline:
"""Distribute items across multiple XML files according to their 'year' field"""
def open_spider(self, spider):
self.year_to_exporter = {}
def close_spider(self, spider):
for exporter, xml_file in self.year_to_exporter.values():
exporter.finish_exporting()
xml_file.close()
def _exporter_for_item(self, item):
adapter = ItemAdapter(item)
year = adapter["year"]
if year not in self.year_to_exporter:
xml_file = open(f"{year}.xml", "wb")
exporter = XmlItemExporter(xml_file)
exporter.start_exporting()
self.year_to_exporter[year] = (exporter, xml_file)
return self.year_to_exporter[year][0]
def process_item(self, item, spider):
exporter = self._exporter_for_item(item)
exporter.export_item(item)
return item
Item 字段的序列化
默认情况下,字段值会原样传递给底层序列化库,如何序列化它们的决定权委托给各个具体的序列化库。
然而,你可以自定义每个字段值在传递给序列化库之前如何进行序列化。
有两种方法可以自定义字段的序列化方式,如下所述。
1. 在字段中声明序列化器
如果你使用 Item
,可以在字段元数据中声明一个序列化器。序列化器必须是一个可调用对象,它接收一个值并返回其序列化后的形式。
示例
import scrapy
def serialize_price(value):
return f"$ {str(value)}"
class Product(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field(serializer=serialize_price)
2. 重写 serialize_field() 方法
你也可以重写 serialize_field()
方法,自定义字段值的导出方式。
请确保在自定义代码之后调用基类的 serialize_field()
方法。
示例
from scrapy.exporters import XmlItemExporter
class ProductXmlExporter(XmlItemExporter):
def serialize_field(self, field, name, value):
if name == "price":
return f"$ {str(value)}"
return super().serialize_field(field, name, value)
内置 Item 导出器参考
以下是 Scrapy 捆绑的 Item 导出器列表。其中一些包含输出示例,这些示例假定你正在导出以下两个 Item
Item(name="Color TV", price="1200")
Item(name="DVD player", price="200")
BaseItemExporter
- class scrapy.exporters.BaseItemExporter(fields_to_export=None, export_empty_fields=False, encoding='utf-8', indent=0, dont_fail=False)[源]
这是所有 Item 导出器(抽象)的基类。它提供了所有(具体)Item 导出器使用的通用功能支持,例如定义要导出的字段、是否导出空字段以及使用哪种编码。
这些功能可以通过
__init__
方法参数进行配置,这些参数会填充各自的实例属性:fields_to_export
、export_empty_fields
、encoding
、indent
。在 2.0 版本新增: dont_fail 参数。
- serialize_field(field, name, value)[源]
返回给定字段的序列化值。如果你想控制特定字段或值的序列化/导出方式,可以重写此方法(在你自定义的 Item 导出器中)。
默认情况下,此方法会在item 字段中声明的序列化器中查找,并返回应用该序列化器到值的结果。如果找不到序列化器,则原样返回值。
- start_exporting()[源]
表示导出过程开始。一些导出器可能会用此方法生成一些必需的头部信息(例如,
XmlItemExporter
)。在导出任何 Item 之前,必须调用此方法。
- finish_exporting()[源]
表示导出过程结束。一些导出器可能会用此方法生成一些必需的尾部信息(例如,
XmlItemExporter
)。在没有更多 Item 要导出后,必须始终调用此方法。
- fields_to_export
要导出的字段,它们的顺序 [1] 和输出名称。
可能的值为
None
(所有字段 [2],默认)一个字段列表
['field1', 'field2']
一个字典,其中键是字段,值是输出名称
{'field1': 'Field 1', 'field2': 'Field 2'}
- export_empty_fields
是否在导出数据中包含空/未填充的 item 字段。默认为
False
。一些导出器(如CsvItemExporter
)会忽略此属性,始终导出所有空字段。此选项对于字典 Item 无效。
- encoding
输出字符编码。
- indent
每个级别输出的缩进空格数。默认为
0
。indent=None
选择最紧凑的表示形式,所有 Item 在同一行,无缩进indent<=0
每个 Item 独立一行,无缩进indent>0
每个 Item 独立一行,按提供的数值缩进
PythonItemExporter
XmlItemExporter
- class scrapy.exporters.XmlItemExporter(file, item_element='item', root_element='items', **kwargs)[源]
将 Item 以 XML 格式导出到指定的文件对象。
- 参数:
此
__init__
方法的额外关键字参数被传递给BaseItemExporter
的__init__
方法。此导出器的典型输出如下
<?xml version="1.0" encoding="utf-8"?> <items> <item> <name>Color TV</name> <price>1200</price> </item> <item> <name>DVD player</name> <price>200</price> </item> </items>
除非在
serialize_field()
方法中重写,否则多值字段会通过将每个值序列化到一个<value>
元素中来导出。这很方便,因为多值字段非常常见。例如,Item
Item(name=['John', 'Doe'], age='23')
将被序列化为
<?xml version="1.0" encoding="utf-8"?> <items> <item> <name> <value>John</value> <value>Doe</value> </name> <age>23</age> </item> </items>
CsvItemExporter
- class scrapy.exporters.CsvItemExporter(file, include_headers_line=True, join_multivalued=',', errors=None, **kwargs)[源]
将 Item 以 CSV 格式导出到给定的文件类对象。如果设置了
fields_to_export
属性,它将用于定义 CSV 列、它们的顺序和列名。export_empty_fields
属性对此导出器没有影响。- 参数:
file – 用于导出数据的文件类对象。其
write
方法应接受bytes
(以二进制模式打开的磁盘文件,一个io.BytesIO
对象等)include_headers_line (str) – 如果启用,导出器将输出一个头部行,包含从
BaseItemExporter.fields_to_export
或第一个导出的 Item 字段获取的字段名。join_multivalued – 用于连接多值字段的字符(或多个字符),如果找到的话。
errors (str) – 可选字符串,指定如何处理编码和解码错误。更多信息请参阅
io.TextIOWrapper
。
此
__init__
方法的额外关键字参数被传递给BaseItemExporter
的__init__
方法,剩余参数则传递给csv.writer()
函数,因此你可以使用任何csv.writer()
函数参数来自定义此导出器。此导出器的典型输出如下
product,price Color TV,1200 DVD player,200
PickleItemExporter
- class scrapy.exporters.PickleItemExporter(file, protocol=0, **kwargs)[源]
将 Item 以 pickle 格式导出到给定的文件类对象。
- 参数:
file – 用于导出数据的文件类对象。其
write
方法应接受bytes
(以二进制模式打开的磁盘文件,一个io.BytesIO
对象等)protocol (int) – 要使用的 pickle 协议。
更多信息,请参阅
pickle
。此
__init__
方法的额外关键字参数被传递给BaseItemExporter
的__init__
方法。Pickle 不是人类可读的格式,因此不提供输出示例。
PprintItemExporter
- class scrapy.exporters.PprintItemExporter(file, **kwargs)[源]
将 Item 以 pretty print(美观打印)格式导出到指定的文件对象。
- 参数:
file – 用于导出数据的文件类对象。其
write
方法应接受bytes
(以二进制模式打开的磁盘文件,一个io.BytesIO
对象等)
此
__init__
方法的额外关键字参数被传递给BaseItemExporter
的__init__
方法。此导出器的典型输出如下
{'name': 'Color TV', 'price': '1200'} {'name': 'DVD player', 'price': '200'}
较长的行(如果存在)会进行美观格式化。
JsonItemExporter
- class scrapy.exporters.JsonItemExporter(file, **kwargs)[源]
将 Item 以 JSON 格式导出到指定的文件类对象,将所有对象写入一个对象列表。额外的
__init__
方法参数被传递给BaseItemExporter
的__init__
方法,剩余参数则传递给JSONEncoder
的__init__
方法,因此你可以使用任何JSONEncoder
的__init__
方法参数来自定义此导出器。- 参数:
file – 用于导出数据的文件类对象。其
write
方法应接受bytes
(以二进制模式打开的磁盘文件,一个io.BytesIO
对象等)
此导出器的典型输出如下
[{"name": "Color TV", "price": "1200"}, {"name": "DVD player", "price": "200"}]
警告
JSON 是一种非常简单灵活的序列化格式,但对于大量数据来说扩展性不好,因为在任何语言的 JSON 解析器中,增量(即流模式)解析的支持度都不高(甚至根本不支持),而且大多数解析器只会将整个对象解析到内存中。如果你想要 JSON 的强大和简单性,同时又需要更适合流式处理的格式,可以考虑使用
JsonLinesItemExporter
代替,或者将输出分割成多个块。
JsonLinesItemExporter
- class scrapy.exporters.JsonLinesItemExporter(file, **kwargs)[源]
将 Item 以 JSON 格式导出到指定的文件类对象,每行写入一个 JSON 编码的 Item。额外的
__init__
方法参数被传递给BaseItemExporter
的__init__
方法,剩余参数则传递给JSONEncoder
的__init__
方法,因此你可以使用任何JSONEncoder
的__init__
方法参数来自定义此导出器。- 参数:
file – 用于导出数据的文件类对象。其
write
方法应接受bytes
(以二进制模式打开的磁盘文件,一个io.BytesIO
对象等)
此导出器的典型输出如下
{"name": "Color TV", "price": "1200"} {"name": "DVD player", "price": "200"}
与
JsonItemExporter
生成的格式不同,此导出器生成的格式非常适合序列化大量数据。