Scrapy爬蟲入門教程七 Item Loaders(項(xiàng)目加載器)

Python版本管理:pyenv和pyenv-virtualenv
Scrapy爬蟲入門教程一 安裝和基本使用
Scrapy爬蟲入門教程二 官方提供Demo
Scrapy爬蟲入門教程三 命令行工具介紹和示例
Scrapy爬蟲入門教程四 Spider(爬蟲)
Scrapy爬蟲入門教程五 Selectors(選擇器)
Scrapy爬蟲入門教程六 Items(項(xiàng)目)
Scrapy爬蟲入門教程七 Item Loaders(項(xiàng)目加載器)
Scrapy爬蟲入門教程八 交互式 shell 方便調(diào)試
Scrapy爬蟲入門教程九 Item Pipeline(項(xiàng)目管道)
Scrapy爬蟲入門教程十 Feed exports(導(dǎo)出文件)
Scrapy爬蟲入門教程十一 Request和Response(請求和響應(yīng))
Scrapy爬蟲入門教程十二 Link Extractors(鏈接提取器)

開發(fā)環(huán)境:
Python 3.6.0 版本 (當(dāng)前最新)
Scrapy 1.3.2 版本 (當(dāng)前最新)

項(xiàng)目加載器

項(xiàng)目加載器提供了一種方便的機(jī)制來填充抓取的項(xiàng)目盒让。即使可以使用自己的類似字典的API填充項(xiàng)目,項(xiàng)目加載器提供了一個(gè)更方便的API司蔬,通過自動(dòng)化一些常見的任務(wù)邑茄,如解析原始提取的數(shù)據(jù),然后分配它從剪貼過程中填充他們俊啼。

換句話說肺缕,Items提供了抓取數(shù)據(jù)的容器,而Item Loader提供了填充該容器的機(jī)制吨些。

項(xiàng)目加載器旨在提供一種靈活搓谆,高效和容易的機(jī)制,通過爬蟲或源格式(HTML豪墅,XML等)擴(kuò)展和覆蓋不同的字段解析規(guī)則泉手,而不會成為維護(hù)的噩夢。

使用裝載機(jī)項(xiàng)目來填充的項(xiàng)目

要使用項(xiàng)目加載器偶器,您必須首先實(shí)例化它斩萌。您可以使用類似dict的對象(例如Item或dict)實(shí)例化它,也可以不使用它屏轰,在這種情況下颊郎,項(xiàng)目將在Item Loader構(gòu)造函數(shù)中使用屬性中指定的Item類自動(dòng)ItemLoader.default_item_class 實(shí)例化。

然后霎苗,您開始收集值到項(xiàng)裝載程序姆吭,通常使用選擇器。您可以向同一項(xiàng)目字段添加多個(gè)值; 項(xiàng)目加載器將知道如何使用適當(dāng)?shù)奶幚砗瘮?shù)“加入”這些值唁盏。

這里是Spider中典型的Item Loader用法内狸,使用Items部分中聲明的Product項(xiàng):

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()

通過快速查看該代碼,我們可以看到該name字段正從頁面中兩個(gè)不同的XPath位置提壤謇蕖:

  1. //div[@class="product_name"]
  2. //div[@class="product_title"]
    換句話說昆淡,通過使用add_xpath()方法從兩個(gè)XPath位置提取數(shù)據(jù)來收集數(shù)據(jù)。這是稍后將分配給name字段的數(shù)據(jù)刽严。

之后昂灵,類似的調(diào)用用于pricestock字段(后者使用帶有add_css()方法的CSS選擇器),最后使用不同的方法last_update直接使用文字值(today)填充字段add_value()舞萄。

最后眨补,收集的所有數(shù)據(jù)時(shí),該ItemLoader.load_item()方法被稱為實(shí)際上返回填充先前提取并與收集到的數(shù)據(jù)的項(xiàng)目add_xpath()倒脓, add_css()add_value()調(diào)用渤涌。

輸入和輸出處理器

項(xiàng)目加載器對于每個(gè)(項(xiàng)目)字段包含一個(gè)輸入處理器和一個(gè)輸出處理器。輸入處理器只要它的接收處理所提取的數(shù)據(jù)(通過add_xpath()把还,add_css()或 add_value()方法)和輸入處理器的結(jié)果被收集并保持ItemLoader內(nèi)部。收集所有數(shù)據(jù)后,ItemLoader.load_item()調(diào)用該 方法來填充和獲取填充 Item對象吊履。這是當(dāng)輸出處理器使用先前收集的數(shù)據(jù)(并使用輸入處理器處理)調(diào)用時(shí)安皱。輸出處理器的結(jié)果是分配給項(xiàng)目的最終值。

讓我們看一個(gè)例子來說明如何為特定字段調(diào)用輸入和輸出處理器(同樣適用于任何其他字段):

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)

所以會發(fā)生什么:

  1. 從數(shù)據(jù)xpath1提取出來艇炎,并通過所傳遞的輸入處理器的的name字段酌伊。輸入處理器的結(jié)果被收集并保存在項(xiàng)目加載器中(但尚未分配給項(xiàng)目)。
  2. 從中xpath2提取數(shù)據(jù)缀踪,并通過(1)中使用的同一輸入處理器居砖。輸入處理器的結(jié)果附加到(1)中收集的數(shù)據(jù)(如果有)。
  3. 這種情況類似于先前的情況驴娃,除了數(shù)據(jù)從cssCSS選擇器提取奏候,并且通過在(1)和(2)中使用的相同的輸入處理器。輸入處理器的結(jié)果附加到在(1)和(2)中收集的數(shù)據(jù)(如果有的話)唇敞。
  4. 這種情況也與之前的類似蔗草,除了要收集的值直接分配间螟,而不是從XPath表達(dá)式或CSS選擇器中提取驯杜。但是允坚,該值仍然通過輸入處理器翻伺。在這種情況下嚷掠,由于該值不可迭代引矩,因此在將其傳遞給輸入處理器之前纬向,它將轉(zhuǎn)換為單個(gè)元素的可迭代新啼,因?yàn)檩斎胩幚砥骺偸墙邮盏?/li>
  5. 在步驟(1)鞋屈,(2)范咨,(3)和(4)中收集的數(shù)據(jù)通過name字段的輸出處理器。輸出處理器的結(jié)果是分配給name 項(xiàng)目中字段的值谐区。

值得注意的是湖蜕,處理器只是可調(diào)用對象,它們使用要解析的數(shù)據(jù)調(diào)用宋列,并返回解析的值昭抒。所以你可以使用任何功能作為輸入或輸出處理器。唯一的要求是它們必須接受一個(gè)(也只有一個(gè))位置參數(shù)炼杖,這將是一個(gè)迭代器灭返。

注意

輸入和輸出處理器都必須接收一個(gè)迭代器作為它們的第一個(gè)參數(shù)。這些函數(shù)的輸出可以是任何東西坤邪。輸入處理器的結(jié)果將附加到包含收集的值(對于該字段)的內(nèi)部列表(在加載程序中)熙含。輸出處理器的結(jié)果是最終分配給項(xiàng)目的值。

另一件需要記住的事情是艇纺,輸入處理器返回的值在內(nèi)部(在列表中)收集怎静,然后傳遞到輸出處理器以填充字段邮弹。

最后,但并非最不重要的是蚓聘,Scrapy自帶一些常用的處理器內(nèi)置的方便腌乡。

聲明項(xiàng)目加載器

項(xiàng)目加載器通過使用類定義語法聲明為Items。這里是一個(gè)例子:

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_out = Join()

    price_in = MapCompose(unicode.strip)

    # ...

可以看到夜牡,輸入處理器使用_in后綴聲明与纽,而輸出處理器使用_out后綴聲明。您還可以使用ItemLoader.default_input_processor和 ItemLoader.default_output_processor屬性聲明默認(rèn)輸入/輸出 處理器塘装。

聲明輸入和輸出處理器

如上一節(jié)所述急迂,輸入和輸出處理器可以在Item Loader定義中聲明,這種方式聲明輸入處理器是很常見的蹦肴。但是僚碎,還有一個(gè)地方可以指定要使用的輸入和輸出處理器:在項(xiàng)目字段 元數(shù)據(jù)中。這里是一個(gè)例子:

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(),
    )
>>> from scrapy.loader import ItemLoader
>>> il = ItemLoader(item=Product())
>>> il.add_value('name', [u'Welcome to my', u'<strong>website</strong>'])
>>> il.add_value('price', [u'€', u'<span>1000</span>'])
>>> il.load_item()
{'name': u'Welcome to my website', 'price': u'1000'}

輸入和輸出處理器的優(yōu)先級順序如下:

  1. 項(xiàng)目加載程序字段特定屬性:field_in和field_out(最高優(yōu)先級)
  2. 字段元數(shù)據(jù)(input_processor和output_processor鍵)
  3. 項(xiàng)目加載器默認(rèn)值:ItemLoader.default_input_processor()和 ItemLoader.default_output_processor()(最低優(yōu)先級)

參見:重用和擴(kuò)展項(xiàng)目加載器冗尤。

項(xiàng)目加載器上下文

項(xiàng)目加載器上下文是在項(xiàng)目加載器中的所有輸入和輸出處理器之間共享的任意鍵/值的dict听盖。它可以在聲明,實(shí)例化或使用Item Loader時(shí)傳遞裂七。它們用于修改輸入/輸出處理器的行為皆看。

例如,假設(shè)您有一個(gè)parse_length接收文本值并從中提取長度的函數(shù):

def  parse_length (text 背零, loader_context ):
    unit  =  loader_context 腰吟。get ('unit' , 'm' )
    #...長度解析代碼在這里... 
    return  parsed_length

通過接受一個(gè)loader_context參數(shù)徙瓶,該函數(shù)顯式地告訴Item Loader它能夠接收一個(gè)Item Loader上下文毛雇,因此Item Loader在調(diào)用它時(shí)傳遞當(dāng)前活動(dòng)的上下文,因此處理器功能(parse_length在這種情況下)可以使用它們侦镇。

有幾種方法可以修改Item Loader上下文值:

  1. 通過修改當(dāng)前活動(dòng)的Item Loader上下文(context屬性):

    loader = ItemLoader(product)
    loader.context['unit'] = 'cm'
    
  2. On Item Loader實(shí)例化(Item Loader構(gòu)造函數(shù)的關(guān)鍵字參數(shù)存儲在Item Loader上下文中):

    loader = ItemLoader(product, unit='cm')
    
  3. On Item Loader聲明灵疮,對于那些支持使用Item Loader上下文實(shí)例化的輸入/輸出處理器。MapCompose是其中之一:

    class ProductLoader(ItemLoader):
        length_out = MapCompose(parse_length, unit='cm')
    

ItemLoader對象

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

返回一個(gè)新的Item Loader來填充給定的Item壳繁。如果沒有給出項(xiàng)目震捣,則使用中的類自動(dòng)實(shí)例化 default_item_class。

當(dāng)使用選擇器或響應(yīng)參數(shù)實(shí)例化時(shí)闹炉,ItemLoader類提供了使用選擇器從網(wǎng)頁提取數(shù)據(jù)的方便的機(jī)制蒿赢。

參數(shù):

  • item(Item對象)-項(xiàng)目實(shí)例來填充用以后調(diào)用 add_xpath(),add_css()或add_value()渣触。
  • selector(Selectorobject) - 當(dāng)使用add_xpath()(或羡棵。add_css())或replace_xpath() (或replace_css())方法時(shí),從中提取數(shù)據(jù)的選擇器 嗅钻。
  • response(Responseobject) - 用于使用構(gòu)造選擇器的響應(yīng) default_selector_class皂冰,除非給出選擇器參數(shù)店展,在這種情況下,將忽略此參數(shù)灼擂。
    項(xiàng)目壁查,選擇器,響應(yīng)和剩余的關(guān)鍵字參數(shù)被分配給Loader上下文(可通過context屬性訪問)剔应。

ItemLoader 實(shí)例有以下方法:

get_value(value,* processors语御,** kwargs )
處理給定value的給定processors和關(guān)鍵字參數(shù)峻贮。

可用的關(guān)鍵字參數(shù):

參數(shù): re(str 或compiled regex)
一個(gè)正則表達(dá)式extract_regex(),用于使用方法從給定值提取數(shù)據(jù)应闯,在處理器之前應(yīng)用
例子:

>>> from scrapy.loader.processors import TakeFirst
>>> loader.get_value(u'name: foo', TakeFirst(), unicode.upper, re='name: (.+)')
'FOO`

add_value(field_name纤控,value,* processors碉纺,** kwargs )
處理船万,然后添加給value定字段的給定。

該值首先通過get_value()賦予 processors和kwargs骨田,然后通過 字段輸入處理器及其結(jié)果追加到為該字段收集的數(shù)據(jù)耿导。如果字段已包含收集的數(shù)據(jù),則會添加新數(shù)據(jù)态贤。

給定field_name可以是None舱呻,在這種情況下可以添加多個(gè)字段的值。并且已處理的值應(yīng)為一個(gè)字段悠汽,其中field_name映射到值箱吕。

例子:

loader.add_value('name', u'Color TV')
loader.add_value('colours', [u'white', u'blue'])
loader.add_value('length', u'100')
loader.add_value('name', u'name: foo', TakeFirst(), re='name: (.+)')
loader.add_value(None, {'name': u'foo', 'sex': u'male'})

replace_value(field_name,value柿冲,* processors茬高,** kwargs )
類似于add_value()但是用新值替換收集的數(shù)據(jù),而不是添加它假抄。

get_xpath(xpath怎栽,* processors,** kwargs )
類似于ItemLoader.get_value()但接收XPath而不是值慨亲,用于從與此相關(guān)聯(lián)的選擇器提取unicode字符串的列表ItemLoader婚瓜。

參數(shù):

  • xpath(str) - 從中??提取數(shù)據(jù)的XPath
  • re(str 或compiled regex) - 用于從所選XPath區(qū)域提取數(shù)據(jù)的正則表達(dá)式
    例子:
# HTML snippet: <p class="product-name">Color TV</p>
loader.get_xpath('//p[@class="product-name"]')
# HTML snippet: <p id="price">the price is $1200</p>
loader.get_xpath('//p[@id="price"]', TakeFirst(), re='the price is (.*)')

add_xpath(field_name,xpath刑棵,* processor巴刻,** kwargs )
類似于ItemLoader.add_value()但接收XPath而不是值,用于從與此相關(guān)聯(lián)的選擇器提取unicode字符串的列表ItemLoader蛉签。

見get_xpath()的kwargs胡陪。

參數(shù):
xpath(str) - 從中??提取數(shù)據(jù)的XPath

例子:

# HTML snippet: <p class="product-name">Color TV</p>
loader.add_xpath('name', '//p[@class="product-name"]')
# HTML snippet: <p id="price">the price is $1200</p>
loader.add_xpath('price', '//p[@id="price"]', re='the price is (.*)')

replace_xpath(field_name沥寥,xpath,* processor柠座,** kwargs )
類似于add_xpath()但替換收集的數(shù)據(jù)邑雅,而不是添加它。

get_css(css妈经,* processors淮野,** kwargs )
類似于ItemLoader.get_value()但接收一個(gè)CSS選擇器而不是一個(gè)值,用于從與此相關(guān)的選擇器提取一個(gè)unicode字符串列表ItemLoader吹泡。

參數(shù):

  • css(str) - 從中??提取數(shù)據(jù)的CSS選擇器
  • re(str 或compiled regex) - 用于從所選CSS區(qū)域提取數(shù)據(jù)的正則表達(dá)式
    例子:
# HTML snippet: <p class="product-name">Color TV</p>
loader.get_css('p.product-name')
# HTML snippet: <p id="price">the price is $1200</p>
loader.get_css('p#price', TakeFirst(), re='the price is (.*)')

add_css(field_name骤星,css,* processors爆哑,** kwargs )
類似于ItemLoader.add_value()但接收一個(gè)CSS選擇器而不是一個(gè)值洞难,用于從與此相關(guān)的選擇器提取一個(gè)unicode字符串列表ItemLoader。

見get_css()的kwargs揭朝。

參數(shù):
css(str) - 從中??提取數(shù)據(jù)的CSS選擇器
例子:

# HTML snippet: <p class="product-name">Color TV</p>
loader.add_css('name', 'p.product-name')
# HTML snippet: <p id="price">the price is $1200</p>
loader.add_css('price', 'p#price', re='the price is (.*)')

replace_css(field_name队贱,css,* processors潭袱,** kwargs )
類似于add_css()但替換收集的數(shù)據(jù)柱嫌,而不是添加它。

load_item()
使用目前收集的數(shù)據(jù)填充項(xiàng)目敌卓,并返回慎式。收集的數(shù)據(jù)首先通過輸出處理器,以獲得要分配給每個(gè)項(xiàng)目字段的最終值趟径。

nested_xpath(xpath )
使用xpath選擇器創(chuàng)建嵌套加載器瘪吏。所提供的選擇器應(yīng)用于與此相關(guān)的選擇器ItemLoader。嵌套裝載機(jī)股份Item 與母公司ItemLoader這么調(diào)用add_xpath()蜗巧, add_value()掌眠,replace_value()等會像預(yù)期的那樣。

nested_css(css )
使用css選擇器創(chuàng)建嵌套加載器幕屹。所提供的選擇器應(yīng)用于與此相關(guān)的選擇器ItemLoader蓝丙。嵌套裝載機(jī)股份Item 與母公司ItemLoader這么調(diào)用add_xpath(), add_value()望拖,replace_value()等會像預(yù)期的那樣渺尘。

get_collected_values(field_name )
返回給定字段的收集值。

get_output_value(field_name )
返回給定字段使用輸出處理器解析的收集值说敏。此方法根本不填充或修改項(xiàng)目鸥跟。

get_input_processor(field_name )
返回給定字段的輸入處理器。

get_output_processor(field_name )
返回給定字段的輸出處理器。

ItemLoader 實(shí)例具有以下屬性:

item
Item此項(xiàng)目加載器解析的對象医咨。

context
此項(xiàng)目Loader 的當(dāng)前活動(dòng)上下文枫匾。

default_item_class
Item類(或工廠),用于在構(gòu)造函數(shù)中未給出時(shí)實(shí)例化項(xiàng)拟淮。

default_input_processor
用于不指定一個(gè)字段的字段的默認(rèn)輸入處理器干茉。

default_output_processor
用于不指定一個(gè)字段的字段的默認(rèn)輸出處理器。

default_selector_class
所使用的類構(gòu)造selector的此 ItemLoader很泊,如果只響應(yīng)在構(gòu)造函數(shù)給出角虫。如果在構(gòu)造函數(shù)中給出了選擇器,則忽略此屬性委造。此屬性有時(shí)在子類中被覆蓋上遥。

selector
Selector從中提取數(shù)據(jù)的對象。它是在構(gòu)造函數(shù)中給出的選擇器争涌,或者是從構(gòu)造函數(shù)中使用的給定的響應(yīng)創(chuàng)建的 default_selector_class。此屬性意味著是只讀的辣恋。

嵌套裝載器

當(dāng)解析來自文檔的子部分的相關(guān)值時(shí)亮垫,創(chuàng)建嵌套加載器可能是有用的。假設(shè)您從頁面的頁腳中提取細(xì)節(jié)伟骨,看起來像:

例:

<footer>
    <a class="social" >Like Us</a>
    <a class="social" >Follow Us</a>
    <a class="email" href="mailto:whatever@example.com">Email Us</a>
</footer>

如果沒有嵌套加載器饮潦,則需要為要提取的每個(gè)值指定完整的xpath(或css)。

例:

loader = ItemLoader(item=Item())
# load stuff not in the footer
loader.add_xpath('social', '//footer/a[@class = "social"]/@href')
loader.add_xpath('email', '//footer/a[@class = "email"]/@href')
loader.load_item()

相反携狭,您可以使用頁腳選擇器創(chuàng)建嵌套加載器继蜡,并相對于頁腳添加值。功能是相同的逛腿,但您避免重復(fù)頁腳選擇器稀并。

例:

loader = ItemLoader(item=Item())
# load stuff not in the footer
footer_loader = loader.nested_xpath('//footer')
footer_loader.add_xpath('social', 'a[@class = "social"]/@href')
footer_loader.add_xpath('email', 'a[@class = "email"]/@href')
# no need to call footer_loader.load_item()
loader.load_item()

您可以任意嵌套加載器,并且可以使用xpath或css選擇器单默。作為一般的指導(dǎo)原則碘举,當(dāng)他們使你的代碼更簡單,但不要超越嵌套或使用解析器可能變得難以閱讀使用嵌套加載程序搁廓。

重用和擴(kuò)展項(xiàng)目加載器

隨著你的項(xiàng)目越來越大引颈,越來越多的爬蟲,維護(hù)成為一個(gè)根本的問題境蜕,特別是當(dāng)你必須處理每個(gè)爬蟲的許多不同的解析規(guī)則蝙场,有很多異常,但也想重用公共處理器粱年。

項(xiàng)目加載器旨在減輕解析規(guī)則的維護(hù)負(fù)擔(dān)售滤,同時(shí)不會失去靈活性,同時(shí)提供了擴(kuò)展和覆蓋它們的方便的機(jī)制逼泣。因此趴泌,項(xiàng)目加載器支持傳統(tǒng)的Python類繼承舟舒,以處理特定爬蟲(或爬蟲組)的差異。

例如嗜憔,假設(shè)某個(gè)特定站點(diǎn)以三個(gè)短劃線(例如)包含其產(chǎn)品名稱秃励,并且您不希望最終在最終產(chǎn)品名稱中刪除那些破折號。---Plasma TV---

以下是如何通過重用和擴(kuò)展默認(rèn)產(chǎn)品項(xiàng)目Loader(ProductLoader)來刪除這些破折號:

from scrapy.loader.processors import MapCompose
from myproject.ItemLoaders import ProductLoader

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

class SiteSpecificLoader(ProductLoader):
    name_in = MapCompose(strip_dashes, ProductLoader.name_in)

另一種擴(kuò)展項(xiàng)目加載器可能非常有用的情況是吉捶,當(dāng)您有多種源格式夺鲜,例如XML和HTML。在XML版本中呐舔,您可能想要?jiǎng)h除CDATA事件币励。下面是一個(gè)如何做的例子:

from scrapy.loader.processors import MapCompose
from myproject.ItemLoaders import ProductLoader
from myproject.utils.xml import remove_cdata

class XmlProductLoader(ProductLoader):
    name_in = MapCompose(remove_cdata, ProductLoader.name_in)

這就是你通常擴(kuò)展輸入處理器的方式。

對于輸出處理器珊拼,更常見的是在字段元數(shù)據(jù)中聲明它們食呻,因?yàn)樗鼈兺ǔH依賴于字段而不是每個(gè)特定站點(diǎn)解析規(guī)則(如輸入處理器)。另請參見: 聲明輸入和輸出處理器澎现。

還有許多其他可能的方法來擴(kuò)展仅胞,繼承和覆蓋您的項(xiàng)目加載器,不同的項(xiàng)目加載器層次結(jié)構(gòu)可能更適合不同的項(xiàng)目剑辫。Scrapy只提供了機(jī)制; 它不強(qiáng)加任何特定的組織你的Loader集合 - 這取決于你和你的項(xiàng)目的需要干旧。

可用內(nèi)置處理器

即使您可以使用任何可調(diào)用函數(shù)作為輸入和輸出處理器,Scrapy也提供了一些常用的處理器妹蔽,如下所述椎眯。其中一些,像MapCompose(通常用作輸入處理器)組成按順序執(zhí)行的幾個(gè)函數(shù)的輸出胳岂,以產(chǎn)生最終的解析值编整。

下面是所有內(nèi)置處理器的列表:

class scrapy.loader.processors.Identity

最簡單的處理器,什么都不做旦万。它返回原始值不變闹击。它不接收任何構(gòu)造函數(shù)參數(shù),也不接受Loader上下文成艘。

例:

>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['one', 'two', 'three'])
['one', 'two', 'three']

class scrapy.loader.processors.TakeFirst

從接收到的值中返回第一個(gè)非空值/非空值赏半,因此它通常用作單值字段的輸出處理器。它不接收任何構(gòu)造函數(shù)參數(shù)淆两,也不接受Loader上下文断箫。

例:

>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'one', 'two', 'three'])
'one'



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

返回與構(gòu)造函數(shù)中給定的分隔符聯(lián)接的值,默認(rèn)為秋冰。它不接受加載器上下文仲义。u' '

當(dāng)使用默認(rèn)分隔符時(shí),此處理器相當(dāng)于以下功能: u' '.join

例子:

>>> from scrapy.loader.processors import Join
>>> proc = Join()
>>> proc(['one', 'two', 'three'])
u'one two three'
>>> proc = Join('<br>')
>>> proc(['one', 'two', 'three'])
u'one<br>two<br>three'



class scrapy.loader.processors.Compose(*functions, **default_loader_context)

由給定函數(shù)的組合構(gòu)成的處理器。這意味著該處理器的每個(gè)輸入值都被傳遞給第一個(gè)函數(shù)埃撵,并且該函數(shù)的結(jié)果被傳遞給第二個(gè)函數(shù)赵颅,依此類推,直到最后一個(gè)函數(shù)返回該處理器的輸出值暂刘。

默認(rèn)情況下饺谬,停止進(jìn)程N(yùn)one值∫ゼ穑可以通過傳遞關(guān)鍵字參數(shù)來更改此行為stop_on_none=False募寨。

例:

>>> from scrapy.loader.processors import Compose
>>> proc = Compose(lambda v: v[0], str.upper)
>>> proc(['hello', 'world'])
'HELLO'

每個(gè)功能可以可選地接收loader_context參數(shù)。對于那些處理器森缠,這個(gè)處理器將通過該參數(shù)傳遞當(dāng)前活動(dòng)的Loader上下文拔鹰。

在構(gòu)造函數(shù)中傳遞的關(guān)鍵字參數(shù)用作傳遞給每個(gè)函數(shù)調(diào)用的默認(rèn)Loader上下文值。但是贵涵,傳遞給函數(shù)的最后一個(gè)Loader上下文值將被當(dāng)前可用該屬性訪問的當(dāng)前活動(dòng)Loader上下文ItemLoader.context() 覆蓋列肢。


class scrapy.loader.processors.MapCompose(*functions, **default_loader_context)

與處理器類似,由給定功能的組成構(gòu)成的Compose處理器宾茂。與此處理器的區(qū)別在于內(nèi)部結(jié)果在函數(shù)之間傳遞的方式例书,如下所示:

該處理器的輸入值被迭代,并且第一函數(shù)被應(yīng)用于每個(gè)元素刻炒。這些函數(shù)調(diào)用的結(jié)果(每個(gè)元素一個(gè))被連接以構(gòu)造新的迭代,然后用于應(yīng)用??第二個(gè)函數(shù)自沧,等等坟奥,直到最后一個(gè)函數(shù)被應(yīng)用于收集的值列表的每個(gè)值遠(yuǎn)。最后一個(gè)函數(shù)的輸出值被連接在一起以產(chǎn)生該處理器的輸出拇厢。

每個(gè)特定函數(shù)可以返回值或值列表爱谁,這些值通過應(yīng)用于其他輸入值的相同函數(shù)返回的值列表展平。函數(shù)也可以返回None孝偎,在這種情況下访敌,該函數(shù)的輸出將被忽略,以便在鏈上進(jìn)行進(jìn)一步處理衣盾。

此處理器提供了一種方便的方法來組合只使用單個(gè)值(而不是iterables)的函數(shù)寺旺。由于這個(gè)原因, MapCompose處理器通常用作輸入處理器势决,因?yàn)閿?shù)據(jù)通常使用選擇器的 extract()方法提取阻塑,選擇器返回unicode字符串的列表。

下面的例子應(yīng)該說明它是如何工作的:

>>> def filter_world(x):
...     return None if x == 'world' else x
...
>>> from scrapy.loader.processors import MapCompose
>>> proc = MapCompose(filter_world, unicode.upper)
>>> proc([u'hello', u'world', u'this', u'is', u'scrapy'])
[u'HELLO, u'THIS', u'IS', u'SCRAPY']

與Compose處理器一樣果复,函數(shù)可以接收Loader上下文陈莽,并且構(gòu)造函數(shù)關(guān)鍵字參數(shù)用作默認(rèn)上下文值。有關(guān)Compose更多信息,請參閱 處理器走搁。


class scrapy.loader.processors.SelectJmes(json_path)

使用提供給構(gòu)造函數(shù)的json路徑查詢值独柑,并返回輸出。需要運(yùn)行jmespath(https://github.com/jmespath/jmespath.py)私植。該處理器一次只需要一個(gè)輸入忌栅。

例:

>>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose
>>> proc = SelectJmes("foo") #for direct use on lists and dictionaries
>>> proc({'foo': 'bar'})
'bar'
>>> proc({'foo': {'bar': 'baz'}})
{'bar': 'baz'}

使用Json:

>>> import json
>>> proc_single_json_str = Compose(json.loads, SelectJmes("foo"))
>>> proc_single_json_str('{"foo": "bar"}')
u'bar'
>>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('foo')))
>>> proc_json_list('[{"foo":"bar"}, {"baz":"tar"}]')
[u'bar']
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市兵琳,隨后出現(xiàn)的幾起案子狂秘,更是在濱河造成了極大的恐慌,老刑警劉巖躯肌,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件者春,死亡現(xiàn)場離奇詭異,居然都是意外死亡清女,警方通過查閱死者的電腦和手機(jī)钱烟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嫡丙,“玉大人拴袭,你說我怎么就攤上這事∈锊” “怎么了拥刻?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長父泳。 經(jīng)常有香客問我般哼,道長,這世上最難降的妖魔是什么惠窄? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任蒸眠,我火速辦了婚禮,結(jié)果婚禮上杆融,老公的妹妹穿的比我還像新娘楞卡。我一直安慰自己,他們只是感情好脾歇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布蒋腮。 她就那樣靜靜地躺著,像睡著了一般藕各。 火紅的嫁衣襯著肌膚如雪徽惋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天座韵,我揣著相機(jī)與錄音险绘,去河邊找鬼踢京。 笑死,一個(gè)胖子當(dāng)著我的面吹牛宦棺,可吹牛的內(nèi)容都是我干的瓣距。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼代咸,長吁一口氣:“原來是場噩夢啊……” “哼蹈丸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起呐芥,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤逻杖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后思瘟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荸百,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年滨攻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了够话。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡光绕,死狀恐怖女嘲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诞帐,我是刑警寧澤欣尼,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站停蕉,受9級特大地震影響媒至,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谷徙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驯绎。 院中可真熱鬧完慧,春花似錦、人聲如沸剩失。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拴孤。三九已至脾歧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間演熟,已是汗流浹背鞭执。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工司顿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人兄纺。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓大溜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親估脆。 傳聞我的和親對象是個(gè)殘疾皇子钦奋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容