Scrapy項目加載器(Item Loader)

項目加載器提供了一個方便的方式來填補從網站上刮取的項目。

聲明項目加載器


項目加載器的聲明類:Items。例如:

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

class DemoLoader(ItemLoader):

default\_output\_processor = TakeFirst()

title\_in = MapCompose(unicode.title)
title\_out = Join()

size\_in = MapCompose(unicode.strip)

# you can continue scraping here 

在上面的代碼可以看到,輸入處理器使用 _id 作爲後綴以及輸出處理器聲明使用_out 作爲後綴聲明。ItemLoader.default_input_processor 和 ItemLoader.default_output_processor 屬性用於聲明默認輸入/輸出處理器。

使用項目加載器來填充項目


要使用項目加載器,先用類似字典的對象,或項目使用 Loader.default_item_class 屬性指定 Item 類實例化。

  • 可以使用選擇器來收集值到項目加載器。

  • 可以在同一項目字段中添加更多的值,項目加載器將使用相應的處理程序來添加這些值。

下面的代碼演示項目是如何使用項目加載器來填充:

from scrapy.loader import ItemLoader
from demoproject.items import Demo

def parse(self, response):
l = ItemLoader(item = Product(), response = response)
l.add_xpath("title", "//div[@class='product_title']")
l.add_xpath("title", "//div[@class='product_name']")
l.add_xpath("desc", "//div[@class='desc']")
l.add_css("size", "div#size]")
l.add_value("last_updated", "yesterday")
return l.load_item()

如上圖所示,有兩種不同的XPath,使用 add_xpath()方法從標題(title)字段提取:

1. //div[@class="product_title"]

  1. //div[@class="product_name"] 

此後,類似請求用於內容描述(desc)字段。size數據使用 add_css()方法提取和last_updated 使用add_value()方法使用值「yesterday」來填充。

完成所有收集數據的,調用 ItemLoader.load_item() 方法返回填充並使用 add_xpath(),add_css()和 dadd_value()方法提取數據項。

輸入和輸出處理器


一個項目加載器的各個字段包含一個輸入處理器和一個輸出處理器。

  • 當提取數據時,輸入處理器處理結果,交將結果存儲在數據加載器。

  • 接下來,收集數據後,調用 ItemLoader.load_item() 方法來獲得 Item 對象。

  • 最後,指定輸出處理器到該項目的結果。

下面的代碼演示針對特定字段如何調用輸入和輸出處理器:

l = ItemLoader(Product(), some_selector)
l.add_xpath("title", xpath1) # [1]
l.add_xpath("title", xpath2) # [2]
l.add_css("title", css) # [3]
l.add_value("title", "demo") # [4]
return l.load_item() # [5]

  • 第1行: 標題(title)的數據是從xpath1提取並通過輸入處理器,其結果被收集並存儲在 ItemLoader 中。

  • 第2行: 同樣地,標題(title)從xpath2提取並通過相同的輸入處理器,其結果收集的數據加到[1]中。

  • 第3行: 標題(title)被從css選擇萃取和通過相同的輸入處理器傳遞並將收集的數據結果加到[1]及[2]。

  • 第4行: 接着,將「demo」值分配並傳遞到輸入處理器。

  • 第5行: 最後,數據是從所有字段內部收集並傳遞給輸出處理器,最終值將分配給項目。

聲明輸入和輸出處理器


輸入和輸出的處理器在項目加載器(ItemLoader )定義聲明。除此之外,它們還可以在項目字段的元數據指定。

例如:

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

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

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

>>> from scrapy.loader import ItemLoader

il = ItemLoader(item=Product())
il.add_value('title', [u'Hello', u'world'])
il.add_value('size', [u'100 kg'])
il.load_item()

它顯示的輸出結果如下:

{'title': u'Hello world', 'size': u'100 kg'}

項目加載器上下文


項目加載器上下文是輸入和輸出的處理器中共享的任意鍵值的字典。

例如,假設有一個函數parse_length:

def parse_length(text, loader_context):
unit = loader_context.get('unit', 'cm')
# You can write parsing code of length here
return parsed_length 

通過接收loader_context參數,它告訴項目加載器可以收到項目加載器上下文。有幾種方法可以改變項目加載器上下文的值:

  • 修改當前的活動項目加載器上下文:

    loader = ItemLoader (product)
    loader.context ["unit"] = "mm"

  • 在項目加載器實例中修改:

    loader = ItemLoader(product, unit="mm")

  • 在加載器項目聲明與項目加載器上下文實例輸入/輸出處理器中修改:

    class ProductLoader(ItemLoader):

      length\_out = MapCompose(parse\_length, unit="mm")

ItemLoader對象

它是一個對象,它返回一個新項加載器到填充給定項目。它有以下類:

class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)

下面的表顯示 ItemReader 對象的參數:

S.N.

參數 & 描述

1

item
它是通過 calling add_xpath(), add_css() 或 add_value()的填充項

2

selector

它用來從網站提取數據

3

response

它是用 default_selector_class 來構造選擇器

下表顯示項目加載器(ItemLoader)對象的方法:

S.N.

方法 & 描述

示例

1

get_value(value, *processors, **kwargs)

由一個給定的處理器和關鍵字參數,該值在getValue()方法處理

>>> from scrapy.loader.processors import TakeFirst
>>> loader.get\_value(u'title: demoweb', TakeFirst(), unicode.upper, re='title: (.+)')
'DEMOWEB\`

2

add_value(field_name, value, *processors, **kwargs)
它首先通過get_value傳遞處理值,並增加到字段中

loader.add\_value('title', u'DVD')
loader.add\_value('colors', \[u'black', u'white'\])
loader.add\_value('length', u'80')
loader.add\_value('price', u'2500')

3

replace_value(field_name, value, *processors, **kwargs)

它用一個新值替換所收集的數據

loader.replace\_value('title', u'DVD')
loader.replace\_value('colors', \[u'black', u'white'\])
loader.replace\_value('length', u'80')
loader.replace\_value('price', u'2500')

4

get_xpath(xpath, *processors, **kwargs)

它用於由接到的XPath給處理器和關鍵字參數提取unicode字符串

# HTML code: <div class="item-name">DVD</div>
loader.get\_xpath("//div\[@class='item-name'\]")
# HTML code: <div id="length">the length is 45cm</div>
loader.get\_xpath("//div\[@id='length'\]", TakeFirst(), re="the length is (.\*)")

5

add_xpath(field_name, xpath, *processors, **kwargs)

它接收XPath提取unicode字符串到字段中

# HTML code: <div class="item-name">DVD</div>
loader.add\_xpath('name', '//div\[@class="item-name"\]')
# HTML code: <div id="length">the length is 45cm</div>
loader.add\_xpath('length', '//div\[@id="length"\]', re='the length is (.\*)')

6

replace_xpath(field_name, xpath, *processors, **kwargs)

它使用XPath取換了從網站收集的數據

# HTML code: <div class="item-name">DVD</div>
loader.replace\_xpath('name', '//div\[@class="item-name"\]')
# HTML code: <div id="length">the length is 45cm</div>
loader.replace\_xpath('length', '//div\[@id="length"\]', re='the length is (.\*)')

7

get_css(css, *processors, **kwargs)

它接收用於提取unicode字符串的CSS選擇器

loader.get\_css("div.item-name")
loader.get\_css("div#length", TakeFirst(), re="the length is (.\*)")

8

add_css(field_name, css, *processors, **kwargs)

它類似於add_value()方法,它增加CSS選擇器到字段中

loader.add\_css('name', 'div.item-name')
loader.add\_css('length', 'div#length', re='the length is (.\*)')

9

replace_css(field_name, css, *processors, **kwargs)

它使用CSS選擇器取代了提取的數據

loader.replace\_css('name', 'div.item-name')
loader.replace\_css('length', 'div#length', re='the length is (.\*)')

10

load_item()

當收集數據後,這個方法填充收集到數據的項目並返回

def parse(self, response):
    l = ItemLoader(item=Product(), response=response)
    l.add\_xpath('title', '//div\[@class="product\_title"\]')
    loader.load\_item()

11

nested_xpath(xpath)

它是通過XPath選擇器來創建嵌套加載器

loader = ItemLoader(item=Item())
loader.add\_xpath('social', 'a\[@class = "social"\]/@href')
loader.add\_xpath('email', 'a\[@class = "email"\]/@href')

12

nested_css(css)

它被用來創建一個CSS選擇器嵌套加載器

loader = ItemLoader(item=Item())
loader.add\_css('social', 'a\[@class = "social"\]/@href')
loader.add\_css('email', 'a\[@class = "email"\]/@href')    

下表顯示項目加載器對象的屬性:

S.N.

屬性 & 描述

1

item

它是項目加載器進行解析的對象

2

context

這是項目加載器是活躍的當前上下文

3

default_item_class

如果在構造沒有給出,它用來表示項

4

default_input_processor

不指定輸入處理器中的字段,只有一個用於其默認輸入處理器

5

default_output_processor

不指定輸出處理器中的字段,只有一個用於其默認的輸出處理器

6

default_selector_class

如果它沒有在構造給定,它是使用來構造選擇器的一個類

7

selector

它是一個用來從站點提取數據的對象

嵌套加載器


這是使用從文檔解析分段的值來創建嵌套加載器。如果不創建嵌套裝載器,需要爲您想提取的每個值指定完整的XPath或CSS。

例如,假設要從一個標題頁中提取數據:

接下來,您可以通過添加相關的值到頁眉來創建頭選擇器嵌套裝載器:

loader = ItemLoader(item=Item())
header_loader = loader.nested_xpath('//header')
header_loader.add_xpath('social', 'a[@class = "social"]/@href')
header_loader.add_xpath('email', 'a[@class = "email"]/@href')
loader.load_item()

重用和擴展項目加載器


項目加載器的設計以緩解維護,當要獲取更多的蜘蛛時項目變成一個根本的問題。

舉例來說,假設一個網站自己的產品名稱是由三條短線封閉的(例如: ---DVD---)。 您可以通過重複使用默認產品項目加載器,如果你不希望它在最終產品名稱所示,下面的代碼刪除這些破折號:

from scrapy.loader.processors import MapCompose
from demoproject.ItemLoaders import DemoLoader

def strip_dashes(x):
return x.strip('-')

class SiteSpecificLoader(DemoLoader):
title_in = MapCompose(strip_dashes, DemoLoader.title_in)

可用內置處理器


以下是一些常用的內置處理器:

  • class scrapy.loader.processors.Identity

    它返回原始的值而並不修改它。 例如:

    >>> from scrapy.loader.processors import Identity

    proc = Identity()
    proc(['a', 'b', 'c'])
    ['a', 'b', 'c']

  • class scrapy.loader.processors.TakeFirst

    它返回一個值來自收到列表的值即非空/非null值。 例如:

    >>> from scrapy.loader.processors import TakeFirst

    proc = TakeFirst()
    proc(['', 'a', 'b', 'c'])
    'a'

  • class scrapy.loader.processors.Join(separator = u' ')

    它返回附連到分隔符的值。默認的分隔符是 u'',這相當於於 u' '.join 的功能。例如:

    >>> from scrapy.loader.processors import Join

    proc = Join()
    proc(['a', 'b', 'c'])
    u'a b c'
    proc = Join('
    ')
    proc(['a', 'b', 'c'])
    u'a
    b
    c'

  • class scrapy.loader.processors.SelectJmes(json_path)

    此類查詢使用提供JSON路徑值,並返回輸出。

    例如:

    >>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose

    proc = SelectJmes("hello")
    proc({'hello': 'scrapy'})
    'scrapy'
    proc({'hello': {'scrapy': 'world'}})
    {'scrapy': 'world'}

    下面是一個查詢通過導入JSON值的代碼:

    >>> import json

    proc_single_json_str = Compose(json.loads, SelectJmes("hello"))
    proc_single_json_str('{"hello": "scrapy"}')
    u'scrapy'
    proc_json_list = Compose(json.loads, MapCompose(SelectJmes('hello')))
    proc_json_list('[{"hello":"scrapy"}, {"world":"env"}]')
    [u'scrapy']