Scrapy Item加载器描述
Item加载器提供了一种方便的方式来填充从网站上爬取的Item。
声明Item加载器
Item加载器的声明就像Item一样。
例如–
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 属性用于声明默认的输入/输出处理器。
使用Item加载器来填充Item
要使用Item Loader,首先要用类似dict的对象进行实例化,或者在Item使用ItemLoader.default_item_class属性中指定的Item类的情况下不使用。
- 你可以使用选择器将数值收集到Item加载器中。
-
你可以在同一个Item字段中添加更多的值,在这里,Item Loader将使用一个适当的处理程序来添加这些值。
下面的代码演示了如何使用Item加载器来填充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()
如上所示,有两个不同的XPaths,使用add_xpath()方法从其中提取标题字段 –
1. //div[@class = "product_title"]
2. //div[@class = "product_name"]
此后,一个类似的请求被用于desc字段。使用add_css()方法提取大小数据,使用add_value()方法将last_updated填充为一个值 “yesterday”。
一旦所有的数据被收集起来,调用ItemLoader.load_item()方法,该方法返回充满使用add_xpath()、add_css()和add_value()方法提取的数据的Item。
输入和输出处理器
一个Item装载机的每个字段都包含一个输入处理器和一个输出处理器。
- 当数据被提取后,输入处理器对其进行处理,其结果被存储在ItemLoader中。
-
接下来,在收集完数据后,调用ItemLoader.load_item()方法来获取填充的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行 – 最后,在内部收集所有字段的数据,并传递给输出处理器,最后的数值被分配给Item。
声明输入和输出处理器
输入和输出处理器在ItemLoader定义中被声明。除此以外,它们也可以在Item字段元数据中指定。
例如–
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加载器上下文
Item加载器上下文是一个在输入和输出处理器之间共享的任意键值的口令。
例如,假设你有一个函数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参数,它告诉Item Loader它可以接收Item Loader context。有几种方法可以改变Item Loader context的值 —
- 修改当前活动的物品装载机上下文 –
loader = ItemLoader (product)
loader.context ["unit"] = "mm"
- 在Item加载器实例化时 –
loader = ItemLoader(product, unit = "mm")
- 在输入/输出处理器的Item Loader声明中,用Item Loader上下文实例化—-。
class ProductLoader(ItemLoader):
length_out = MapCompose(parse_length, unit = "mm")
Item加载器对象
它是一个对象,它返回一个新的Item加载器来填充给定的Item。它有以下的类 –
class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)
下表显示了ItemLoader对象的参数。
编号 | 参数 | 说明 |
---|---|---|
1 | item | 它是通过调用add_xpath()、add_css()或add_value()来填充的Item |
2 | selector | 它被用来从网站上提取数据 |
3 | response | 它用于使用default_selector_class来构造选择器 |
下表显示了ItemLoader对象的方法。
编号 | 方法 | 描述 |
---|---|---|
1 | get_value(value, *processors, **kwargs) | 通过一个给定的处理器和关键字参数,该值由get_value()方法处理 |
2 | add_value(field_name, value, *processors, **kwargs) | 它对数值进行处理并添加到首先通过get_value传递的字段中,在通过字段输入处理器之前给出处理器和关键字参数 |
3 | replace_value(field_name, value, *processors, **kwargs) | 它用一个新的值取代了收集的数据 |
4 | get_xpath(xpath, *processors, **kwargs) | 它用于通过给出处理器和关键字参数,通过接收XPath来提取unicode字符串 |
5 | add_xpath(field_name, xpath, *processors, **kwargs) | 它接收到的XPath字段,可以提取单码字串 |
6 | replace_xpath(field_name, xpath, *processors, **kwargs) | 它使用XPath取代了从网站收集的数据 |
7 | get_css(css, *processors, **kwargs) | 它接收用于提取unicode字符串的CSS选择器 |
8 | add_css(field_name, css, *processors, **kwargs) | 它与add_value()方法类似,但有一点不同,它为字段添加CSS选择器 |
9 | replace_css(field_name, css, *processors, **kwargs) | 它使用CSS选择器取代了提取的数据 |
10 | load_item() | 当数据被收集后,该方法将收集到的数据填充到该Item中并返回 |
11 | nested_xpath(xpath) | 它被用来创建带有XPath选择器的嵌套加载器 |
12 | nested_css(css) | 它被用来创建带有CSS选择器的嵌套加载器 |
get_value(value, *processors, **kwargs)示例
>>> from scrapy.loader.processors import TakeFirst
>>> loader.get_value(u'title: demoweb', TakeFirst(),
unicode.upper, re = 'title: (.+)')
'DEMOWEB`
add_value(field_name, value, *processors, **kwargs)示例
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')
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')
get_xpath(xpath, *processors, **kwargs)示例
# 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 (.*)")
add_xpath(field_name, xpath, *processors, **kwargs)示例
# 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 (.*)')
replace_xpath(field_name, xpath, *processors, **kwargs)示例
# 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 (.*)')
get_css(css, *processors, **kwargs)示例
loader.get_css("div.item-name")
loader.get_css("div#length", TakeFirst(),
re = "the length is (.*)")
add_css(field_name, css, *processors, **kwargs)示例
loader.add_css('name', 'div.item-name')
loader.add_css('length', 'div#length',
re = 'the length is (.*)')
replace_css(field_name, css, *processors, **kwargs)示例
loader.replace_css('name', 'div.item-name')
loader.replace_css('length', 'div#length',
re = 'the length is (.*)')
load_item()示例
def parse(self, response):
l = ItemLoader(item = Product(),
response = response)
l.add_xpath('title', '//
div[@class = "product_title"]')
loader.load_item()
nested_xpath(xpath)示例
loader = ItemLoader(item = Item())
loader.add_xpath('social', '
a[@class = "social"]/@href')
loader.add_xpath('email', '
a[@class = "email"]/@href')
nested_css(css)示例
loader = ItemLoader(item = Item())
loader.add_css('social', 'a[@class = "social"]/@href')
loader.add_css('email', 'a[@class = "email"]/@href')
下表显示了ItemLoader对象的属性。
编号 | 属性 | 描述 |
---|---|---|
1 | item | 它是一个对象,Item加载器对其进行解析 |
2 | context | 它是Item装载机的当前上下文,是活动的 |
3 | default_item_class | 如果在构造函数中没有给出,它被用来表示Item。 |
4 | default_input_processor | 没有指定输入处理器的字段是唯一使用default_input_processors的 |
5 | default_output_processor | 没有指定输出处理器的字段是唯一使用default_output_processors的 |
6 | default_selector_class | 它是一个用于构造选择器的类,如果它没有在构造函数中给出 |
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()
重复使用和扩展Item装载器
Item装载机的设计是为了缓解维护,当你的Item获得更多的蜘蛛时,维护就成为一个基本问题。
例如,假设一个网站的产品名称用三个破折号括起来(例如:–DVD–)。你可以通过重新使用默认的产品Item加载器来删除这些破折号,如果你不希望它出现在最终的产品名称中,如下代码所示
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']