初识 Scrapy - Item Loader

1. 前言

Scrapy并不是直接填充items,而是有自己的机制。

items为爬取的数据提供容器,Item Loader为该容器提供了填充机制。

2. 使用Item Loader

from scrapy.loader import ItemLoader
from myproject.items import Product

def parse(self, response):
    l = ItemLoader(item=Product(), response=response)
    l.add_xpath('name', '//div[@class="product_name"]')
    l.add_xpath('name', '//div[@class="product_title"]')
    l.add_xpath('price', '//p[@id="price"]')
    l.add_css('stock', 'p#stock]')
    l.add_value('last_updated', 'today') # you can also use literal values
    return l.load_item()

3. 输入和输出处理器

一个Item Loader为每一个 item的字段都包含了一个输入处理器和输出处理器。

  • 当提取的数据被Item Loader接收(如:add_xpath(), add_css(), add_value()方法)时会使用输入处理器处理它们,并保存在ItemLoader中。
  • 然后调用ItemLoader.load_item()方法获得Item对象并在输出处理器处理这写数据之后进行填充到item中。

举个例子,

l = ItemLoader(Product(), some_selector)
l.add_xpath('name', xpath1) # (1)
l.add_xpath('name', xpath2) # (2)
l.add_css('name', css) # (3)
l.add_value('name', 'test') # (4)
return l.load_item() # (5)
  1. 数据从xpath1抽取出来,传递给 name 字段的输入处理器。输入处理器的结果存在ItemLoader中。
  2. 与第一步类似。输入处理器的结果append到第一步的结果中。
  3. 与第二步类似。只不过是从CSS 选择器中提取数据。将结果append到之前的结果中。
  4. 与第三步类似。只不过此次不需要从选择器中提取数据(数据直接给了)。结果append到之前的结果中。
  5. 将1, 2,3, 4步中收集的数据传递给对应字段的输出处理器。将输出处理器的结果分配给item中的对应字段。

值得注意的是,处理器只是可调用对象,用要解析的数据调用,并返回一个已解析的值。所以您可以使用任何函数作为输入或输出处理器。唯一的要求是他们必须接受一个(并且只有一个)为可迭代对象的位置参数。

输入和输出处理器都必须接收一个可迭代对象作为它们的第一个参数。这些函数的输出可以是任何东西。输入处理器的结果将附加到包含收集值(针对该字段)的内部列表(在加载程序中)。输出处理器的结果是最终分配给该项的值。

您需要记住的另一件事是,输入处理器返回的值在内部收集(在列表中),然后传递给输出处理器来填充字段。

4. 声明Item Loader

通过定义一个类来声明。

from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose, Join

class ProductLoader(ItemLoader):

    default_output_processor = TakeFirst()

    name_in = MapCompose(unicode.title) # name字段的输入处理器
    name_out = Join() # name字段的输出处理器

    price_in = MapCompose(unicode.strip)

    # ...

5. 声明 输入/输出处理器

输入/输出处理器可以在Item Loader定义中声明。还可以在Item Field元素内指明输入/输出处理器。

import scrapy
from scrapy.loader.processors import Join, MapCompose, TakeFirst
from w3lib.html import remove_tags

def filter_price(value):
    if value.isdigit():
        return value

class Product(scrapy.Item):
    name = scrapy.Field(
        input_processor=MapCompose(remove_tags),
        output_processor=Join(),
    )
    price = scrapy.Field(
        input_processor=MapCompose(remove_tags, filter_price),
        output_processor=TakeFirst(),
    )

输入和输出处理器的优先顺序如下:

  1. Item Loader字段特定属性: field_infield_out(最优先)
  2. 字段元数据 (input_processoroutput_processor 关键字参数)
  3. Item Loader 默认值: ItemLoader.default_input_processor()ItemLoader.default_output_processor()(最低优先级)

6. Item Loder 上下文

Item Loder 上下文是任意键/值的字典,在项加载器中的所有输入和输出处理器之间共享。 可以在声明,实例化或使用Item Loader时传递。它们用于修改输入/输出处理器的行为

如果你想根据Item Loader上下文的中的内容修改输入/输出处理器的行为。就用它呗。

7. 嵌套Loader

从文档的子部分分析相关值时,创建嵌套加载器可能很有用。假设您正在从一个页面的页脚提取细节。

8. 参考文献

[1] Scrapy 官方文档 Item Loaders

猜你喜欢

转载自blog.csdn.net/besmarterbestronger/article/details/107095796