初識 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章