Item详解
本文轉(zhuǎn)載自http://blog.csdn.net/sdulsj/article/details/52984619
Item是保存結(jié)構(gòu)數(shù)據(jù)的地方,Scrapy可以將解析結(jié)果以字典形式返回,但是Python中字典缺少結(jié)構(gòu),在大型爬蟲系統(tǒng)中很不方便。
Item提供了類字典的API,并且可以很方便的聲明字段,很多Scrapy組件可以利用Item的其他信息。
定義Item
定義Item非常簡單,只需要繼承scrapy.Item類,并將所有字段都定義為scrapy.Field類型即可
import scrapyclass Product(scrapy.Item):name = scrapy.Field()price = scrapy.Field()stock = scrapy.Field()last_updated = scrapy.Field(serializer=str)Item Fields
Field對象可用來對每個字段指定元數(shù)據(jù)。例如上面last_updated的序列化函數(shù)指定為str,可任意指定元數(shù)據(jù),不過每種元數(shù)據(jù)對于不同的組件意義不一樣。
Item使用示例
你會看到Item的使用跟Python中的字典API非常類似
創(chuàng)建Item
>>> product = Product(name='Desktop PC', price=1000) >>> print product Product(name='Desktop PC', price=1000)獲取值
>>> product['name'] Desktop PC >>> product.get('name') Desktop PC>>> product['price'] 1000>>> product['last_updated'] Traceback (most recent call last):... KeyError: 'last_updated'>>> product.get('last_updated', 'not set') not set>>> product['lala'] # getting unknown field Traceback (most recent call last):... KeyError: 'lala'>>> product.get('lala', 'unknown field') 'unknown field'>>> 'name' in product # is name field populated? True>>> 'last_updated' in product # is last_updated populated? False>>> 'last_updated' in product.fields # is last_updated a declared field? True>>> 'lala' in product.fields # is lala a declared field? False設(shè)置值
>>> product['last_updated'] = 'today' >>> product['last_updated'] today>>> product['lala'] = 'test' # setting unknown field Traceback (most recent call last):... KeyError: 'Product does not support field: lala'訪問所有的值
>>> product.keys() ['price', 'name']>>> product.items() [('price', 1000), ('name', 'Desktop PC')]Item Loader
Item Loader為我們提供了生成Item的相當(dāng)便利的方法。Item為抓取的數(shù)據(jù)提供了容器,而Item Loader可以讓我們非常方便的將輸入填充到容器中。
下面我們通過一個例子來展示一般使用方法:
from scrapy.loader import ItemLoader from myproject.items import Productdef 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 valuesreturn l.load_item()注意上面的name字段是從兩個xpath路徑添累加后得到。
輸入/輸出處理器
每個Item Loader對每個Field都有一個輸入處理器和一個輸出處理器。輸入處理器在數(shù)據(jù)被接受到時執(zhí)行,當(dāng)數(shù)據(jù)收集完后調(diào)用ItemLoader.load_item()時再執(zhí)行輸出處理器,返回最終結(jié)果。
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)執(zhí)行流程是這樣的:
自定義Item Loader
使用類定義語法,下面是一個例子
from scrapy.loader import ItemLoader from scrapy.loader.processors import TakeFirst, MapCompose, Joinclass ProductLoader(ItemLoader):default_output_processor = TakeFirst()name_in = MapCompose(unicode.title)name_out = Join()price_in = MapCompose(unicode.strip)# ...通過_in和_out后綴來定義輸入和輸出處理器,并且還可以定義默認(rèn)的ItemLoader.default_input_processor和ItemLoader.default_input_processor.
在Field定義中聲明輸入/輸出處理器
還有個地方可以非常方便的添加輸入/輸出處理器,那就是直接在Field定義中
import scrapy from scrapy.loader.processors import Join, MapCompose, TakeFirst from w3lib.html import remove_tagsdef filter_price(value):if value.isdigit():return valueclass 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(),)優(yōu)先級:
Tips:一般來講,將輸入處理器定義在Item Loader的定義中field_in,然后將輸出處理器定義在Field元數(shù)據(jù)中
Item Loader上下文
Item Loader上下文被所有輸入/輸出處理器共享,比如你有一個解析長度的函數(shù)
def parse_length(text, loader_context):unit = loader_context.get('unit', 'm')# ... length parsing code goes here ...return parsed_length初始化和修改上下文的值
loader = ItemLoader(product) loader.context['unit'] = 'cm'loader = ItemLoader(product, unit='cm')class ProductLoader(ItemLoader):length_out = MapCompose(parse_length, unit='cm')內(nèi)置的處理器
總結(jié)
- 上一篇: linux系统双显示器怎么设置复制,在
- 下一篇: 信息炸弹——Message Boom