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"]
- //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']