- Scrapy 教程
- Scrapy - 首頁
- Scrapy 基本概念
- Scrapy - 概述
- Scrapy - 環境配置
- Scrapy - 命令列工具
- Scrapy - 爬蟲 (Spiders)
- Scrapy - 選擇器 (Selectors)
- Scrapy - 專案 (Items)
- Scrapy - 專案載入器
- Scrapy - Shell
- Scrapy - 專案管道 (Item Pipeline)
- Scrapy - 資料匯出 (Feed exports)
- Scrapy - 請求 & 響應 (Requests & Responses)
- Scrapy - 連結提取器 (Link Extractors)
- Scrapy - 設定 (Settings)
- Scrapy - 異常處理 (Exceptions)
- Scrapy 實戰專案
- Scrapy - 建立專案
- Scrapy - 定義專案
- Scrapy - 第一個爬蟲
- Scrapy - 爬取資料
- Scrapy - 提取專案資料
- Scrapy - 使用專案資料
- Scrapy - 跟蹤連結
- Scrapy - 爬取資料
- Scrapy 有用資源
- Scrapy - 快速指南
- Scrapy - 有用資源
- Scrapy - 討論
Scrapy - 專案載入器
描述
專案載入器提供了一種方便的方式來填充從網站上抓取的專案資料。
宣告專案載入器
專案載入器的宣告方式與專案 (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
在上面的程式碼中,您可以看到輸入處理器使用 `_in` 字尾宣告,輸出處理器使用 `_out` 字尾宣告。
ItemLoader.default_input_processor 和 ItemLoader.default_output_processor 屬性用於宣告預設的輸入/輸出處理器。
使用專案載入器填充專案
要使用專案載入器,首先使用類似字典的物件進行例項化,或者不使用任何物件,在這種情況下,專案使用在 ItemLoader.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"]
2. //div[@class = "product_name"]
之後,對 desc 欄位使用了類似的請求。大小資料使用 add_css() 方法提取,last_updated 使用 add_value() 方法填充值為 "yesterday"。
一旦所有資料收集完畢,呼叫 ItemLoader.load_item() 方法,該方法返回使用 add_xpath()、add_css() 和 add_value() 方法提取資料的填充專案。
輸入和輸出處理器
專案載入器的每個欄位包含一個輸入處理器和一個輸出處理器。
提取資料時,輸入處理器會處理資料,並將結果儲存在 ItemLoader 中。
接下來,在收集資料後,呼叫 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 行** - 從 xpath1 提取 title 的資料,並透過輸入處理器,將其結果收集並存儲在 ItemLoader 中。
**第 2 行** - 同樣,從 xpath2 提取 title 並透過相同的輸入處理器,將其結果新增到為 [1] 收集的資料中。
**第 3 行** - 從 css 選擇器提取 title 並透過相同的輸入處理器,將其結果新增到為 [1] 和 [2] 收集的資料中。
**第 4 行** - 接下來,分配值 "demo" 並透過輸入處理器。
**第 5 行** - 最後,從所有欄位內部收集資料並傳遞給輸出處理器,並將最終值分配給 Item。
宣告輸入和輸出處理器
輸入和輸出處理器在 ItemLoader 定義中宣告。除此之外,它們也可以在**專案欄位**元資料中指定。
例如:
import scrapy
from scrapy.loader.processors import Join, MapCompose, TakeFirst
from w3lib.html 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'<strong>world</strong>'])
>>> il.add_value('size', [u'<span>100 kg</span>'])
>>> 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)
下表顯示了 ItemLoader 物件的引數:
| 序號 | 引數 & 描述 |
|---|---|
| 1 | item 透過呼叫 `add_xpath()`、`add_css()` 或 `add_value()` 來填充的專案。 |
| 2 | selector 用於從網站提取資料。 |
| 3 | response 用於使用 `default_selector_class` 構造選擇器。 |
下表顯示了 ItemLoader 物件的方法:
| 序號 | 方法 & 描述 | 示例 |
|---|---|---|
| 1 |
透過給定的處理器和關鍵字引數,值由 `get_value()` 方法處理。 |
>>> from scrapy.loader.processors import TakeFirst >>> loader.get_value(u'title: demoweb', TakeFirst(), unicode.upper, re = 'title: (.+)') 'DEMOWEB` |
| 2 |
它處理值並新增到欄位中,首先透過 `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 |
它用新值替換收集到的資料。 |
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 |
它用於透過接收 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 |
它接收 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 |
它使用網站上的 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 |
它接收 CSS 選擇器,用於提取 Unicode 字串。 |
loader.get_css("div.item-name")
loader.get_css("div#length", TakeFirst(),
re = "the length is (.*)")
|
| 8 |
它類似於 `add_value()` 方法,區別在於它向欄位新增 CSS 選擇器。 |
loader.add_css('name', 'div.item-name')
loader.add_css('length', 'div#length',
re = 'the length is (.*)')
|
| 9 |
它使用 CSS 選擇器替換提取的資料。 |
loader.replace_css('name', 'div.item-name')
loader.replace_css('length', 'div#length',
re = 'the length is (.*)')
|
| 10 |
當資料收集完畢時,此方法使用收集到的資料填充專案並返回它。 |
def parse(self, response):
l = ItemLoader(item = Product(),
response = response)
l.add_xpath('title', '//
div[@class = "product_title"]')
loader.load_item()
|
| 11 |
它用於使用 XPath 選擇器建立巢狀載入器。 |
loader = ItemLoader(item = Item())
loader.add_xpath('social', '
a[@class = "social"]/@href')
loader.add_xpath('email', '
a[@class = "email"]/@href')
|
| 12 |
它用於使用 CSS 選擇器建立巢狀載入器。 |
loader = ItemLoader(item = Item())
loader.add_css('social', 'a[@class = "social"]/@href')
loader.add_css('email', 'a[@class = "email"]/@href')
|
下表顯示了 ItemLoader 物件的屬性:
| 序號 | 屬性 & 描述 |
|---|---|
| 1 | item ItemLoader 執行解析的物件。 |
| 2 | context 這是當前活動的 ItemLoader 的上下文。 |
| 3 |
如果在建構函式中未給出,則用於表示專案。 |
| 4 |
僅對未指定輸入處理器的欄位使用 `default_input_processors`。 |
| 5 |
僅對未指定輸出處理器的欄位使用 `default_output_processors`。 |
| 6 |
如果在建構函式中未給出,則用於構造選擇器的類。 |
| 7 | selector 可用於從網站提取資料的物件。 |
巢狀載入器
它用於在從文件的子部分解析值時建立巢狀載入器。如果您不建立巢狀載入器,則需要為要提取的每個值指定完整的 XPath 或 CSS。
例如,假設資料正在從標題頁面提取:
<header> <a class = "social" href = "http://facebook.com/whatever">facebook</a> <a class = "social" href = "http://twitter.com/whatever">twitter</a> <a class = "email" href = "mailto:someone@example.com">send mail</a> </header>
接下來,您可以透過向標題新增相關值來使用標題選擇器建立巢狀載入器:
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---)。如果您不想在最終商品名稱中包含這些短橫線,您可以重用預設的 Product Item Loader,如下面的程式碼所示:
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
它返回從接收到的值列表中第一個非空值。例如:
>>> 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('<br>')
>>> proc(['a', 'b', 'c'])
u'a<br>b<br>c'
class scrapy.loader.processors.Compose(*functions, **default_loader_context)
它由一個處理器定義,其每個輸入值都傳遞給第一個函式,該函式的結果傳遞給第二個函式,依此類推,直到最後一個函式返回最終值作為輸出。
例如:
>>> from scrapy.loader.processors import Compose >>> proc = Compose(lambda v: v[0], str.upper) >>> proc(['python', 'scrapy']) 'PYTHON'
class scrapy.loader.processors.MapCompose(*functions, **default_loader_context)
這是一個處理器,其中迭代輸入值並將第一個函式應用於每個元素。接下來,將這些函式呼叫的結果連線起來以構建新的可迭代物件,然後將其應用於第二個函式,依此類推,直到最後一個函式。
例如:
>>> def filter_scrapy(x): return None if x == 'scrapy' else x >>> from scrapy.loader.processors import MapCompose >>> proc = MapCompose(filter_scrapy, unicode.upper) >>> proc([u'hi', u'everyone', u'im', u'pythonscrapy']) [u'HI, u'IM', u'PYTHONSCRAPY']
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']