Scrapy - 项目装载程序

描述

项目加载器提供了一种方便的方法来填充从网站上删除的项目.

声明项目加载器

项目装载程序的声明类似于项目.

例如 :

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 属性用于声明默认输入/输出过程sors.

使用项目加载器来填充项目

要使用项目加载器,首先使用类似dict的对象实例化,或者不使用项目使用的项目在 ItemLoader.default_item_class 属性中指定的类.

  • 您可以使用选择器将值收集到项目加载器.

  • 您可以在同一项目字段中添加更多值,其中Item Loader将使用适当的处理程序来添加这些值.

以下代码演示如何使用Item Loaders : 填充项目;

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 字段/b>方法 : 去;

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

此后,类似的请求用于 desc 字段.使用 add_css()方法提取大小数据,使用 add_value()方法将 last_updated 填充值"昨天".

收集完所有数据后,调用 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中提取并通过输入处理器,其结果被收集并存储在ItemLoader中.

第2行 : 类似地,标题从xpath2中提取并通过相同的输入处理器,其结果被添加到为[1]收集的数据中.

第3行 : 去;标题从css选择器中提取并通过相同的输入处理器,结果被添加到为[1]和[2]收集的数据中.

第4行 : 接下来,分配值"demo"并通过输入处理器传递.

第5行 : 最后,数据在内部从所有字段收集并传递到输出处理器,最终值分配给项目.

声明输入和输出处理器

输入和输出处理器在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'}

项目加载器上下文

Item Loader Context是输入和输出处理器之间共享的任意键值的字典.

例如,假设你有一个函数 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 arguements,它告诉Item Loader它可以接收Item Loader上下文.有几种方法可以更改Item Loader上下文的值 :

  • 修改当前有效的Item Loader上下文 :

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

  • On Item Loader instantiation :

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

  • 输入/输出处理器的Item Loader声明,用Item Loader上下文实例化 :

 
 class ProductLoader(ItemLoader):
 length_out = MapCompose(parse_length,unit ="mm")

ItemLoader对象

这是一个返回新项加载器以填充给定项的对象.它有以下类 :

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

下表显示了ItemLoader对象的参数 :

Sr.No参数&说明
1

item

这是通过调用add_xpath(),add_css()或add_value()来填充的项目.

2

选择器

它用于从网站提取数据.

3

响应

它用于使用default_selector_class构造选择器.

下表显示了ItemLoader对象的方法 :

Sr.No方法&说明示例
1

get_value(值,*处理器,** kwargs)

通过给定的处理器和关键字参数,该值由get_value()方法处理.

 
>>>来自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)

它用新值替换收集的数据.

 
 lo ader.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">长度为45厘米< ;/DIV&GT; 
 loader.get_xpath("//div [@id ='length']",TakeFirst(),re ="长度为(.*)")
5

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

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

 
#HTML code:< div class ="item-name"> DVD&LT;/DIV&GT; 
 loader.add_xpath('name','//div [@class ="item-name"]')
#HTML code:< div id ="length">长度为45厘米</div> 
 loader.add_xpath('length','//div [@id ="length"]',re ='长度为(.*)')
6

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

它使用 XPath 从站点替换收集的数据.

 
#HTML code:< div class ="item-name"> DVD< ;/DIV&GT; 
 loader.replace_xpath('name','//div [@class ="item-name"]')
#HTML code:< div id ="length">长度为45厘米</div> 
 loader.replace_xpath('length','//div [@id ="length"]',re ='长度为(.*)')
7

get_css(css,* processors,** kwargs)

它接收用于提取unicode字符串的CSS选择器.

 
 loader.get_css("div.item-name")
 loader.get_css("div #length") ,TakeFirst(),re ="长度是(.*)")
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 ='长度为(.*)')
9

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

它使用CSS替换提取的数据选择器.

 
 loader.replace_css('name','div.item -name')
 loader.replace_css('length','div #length',re ='长度为(.*)')
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')

下表显示了ItemLoader对象的属性 :

Sr.No属性&说明
1

item

这是一个Item Loader执行解析的对象.

2

context

这是项目加载器的当前上下文处于活动状态.

3

default_item_class

如果未在构造函数中给出,则用于表示项目.

4

default_input_processor

未指定输入处理器的字段是唯一使用default_input_processors的字段.

5

default_output_processor

未指定输出处理器的字段是唯一使用default_output_processors的字段.

6

default_selector_class

它是用于构造选择器的类,如果它没有在构造函数中给出.

7

选择器

这是一个可用于提取的对象来自网站的数据.

嵌套装载机

它用于在解析文档子节中的值时创建嵌套加载器.如果不创建嵌套加载器,则需要为要提取的每个值指定完整的XPath或CSS.

例如,假设从标题中提取数据page :

<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 ---).您可以通过重用默认的产品项目加载器来删除这些破折号,如果您不希望它在最终产品名称中,如下面的代码所示 :

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

它返回原始值而不改变它.例如 :

 
>>>来自scrapy.loader.processors import Identity 
>>> proc = Identity()
>>> proc(['a','b','c'])
 ['a','b','c']

class scrapy.loader.processors.TakeFirst

它从接收值列表中返回非空/非空的第一个值.例如 :

>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['a', 'b', 'c'])
['a', 'b', 'c']

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)

这是一个迭代输入值的处理器,第一个函数应用于每个元素.接下来,将这些函数调用的结果连接起来构建新的iterable,然后将其应用于第二个函数,依此类推,直到最后一个函数.

例如 :

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