📅  最后修改于: 2020-10-31 14:33:45             🧑  作者: Mango
项目加载器提供了一种便捷的方法来填充从网站上抓取的项目。
项加载器的声明类似于项。
例如-
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 Loader,请首先使用类似dict的对象实例化,或者不使用该对象实例化(如果该项目使用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()
如上所示,使用add_xpath()方法从两个不同的XPath提取标题字段-
1. //div[@class = "product_title"]
2. //div[@class = "product_name"]
此后,将类似的请求用于desc字段。尺寸数据使用add_css()方法提取和LAST_UPDATED填充有值“昨天”使用add_value()方法。
收集完所有数据后,调用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行-最后,从所有字段内部收集数据,并将其传递到输出处理器,并将最终值分配给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'world'])
>>> il.add_value('size', [u'100 kg'])
>>> 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争论,它告诉Item Loader它可以接收Item Loader上下文。有几种方法可以更改Item Loader上下文的值-
修改当前活动的项目加载器上下文-
loader = ItemLoader (product)
loader.context ["unit"] = "mm"
在Item Loader实例上-
loader = ItemLoader(product, unit = "mm")
在使用Item Loader上下文实例化的输入/输出处理器的Item Loader声明中-
class ProductLoader(ItemLoader):
length_out = MapCompose(parse_length, unit = "mm")
它是一个对象,该对象返回新的项目加载器以填充给定的项目。它具有以下类别-
class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)
下表显示了ItemLoader对象的参数-
Sr.No | Parameter & Description |
---|---|
1 |
item It is the item to populate by calling add_xpath(), add_css() or add_value(). |
2 |
selector It is used to extract data from websites. |
3 |
response It is used to construct selector using default_selector_class. |
下表显示了ItemLoader对象的方法-
Sr.No | Method & Description | Example |
---|---|---|
1 |
get_value(value, *processors, **kwargs) By a given processor and keyword arguments, the value is processed by get_value() method. |
>>> from 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) It processes the value and adds to the field where it is first passed through get_value by giving processors and keyword arguments before passing through field input processor. |
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) It replaces the collected data with a new value. |
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 |
get_xpath(xpath, *processors, **kwargs) It is used to extract unicode strings by giving processors and keyword arguments by receiving XPath. |
# HTML code: |
5 |
add_xpath(field_name, xpath, *processors, **kwargs) It receives XPath to the field which extracts unicode strings. |
# HTML code: |
6 |
replace_xpath(field_name, xpath, *processors, **kwargs) It replaces the collected data using XPath from sites. |
# HTML code: |
7 |
get_css(css, *processors, **kwargs) It receives CSS selector used to extract the unicode strings. |
loader.get_css("div.item-name") loader.get_css("div#length", TakeFirst(), re = "the length is (.*)") |
8 |
add_css(field_name, css, *processors, **kwargs) It is similar to add_value() method with one difference that it adds CSS selector to the field. |
loader.add_css('name', 'div.item-name') loader.add_css('length', 'div#length', re = 'the length is (.*)') |
9 |
replace_css(field_name, css, *processors, **kwargs) It replaces the extracted data using CSS selector. |
loader.replace_css('name', 'div.item-name') loader.replace_css('length', 'div#length', re = 'the length is (.*)') |
10 |
load_item() When the data is collected, this method fills the item with collected data and returns it. |
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) It is used to create nested loaders with an XPath selector. |
loader = ItemLoader(item = Item()) loader.add_xpath('social', ' a[@class = "social"]/@href') loader.add_xpath('email', ' a[@class = "email"]/@href') |
12 |
nested_css(css) It is used to create nested loaders with a CSS selector. |
loader = ItemLoader(item = Item()) loader.add_css('social', 'a[@class = "social"]/@href') loader.add_css('email', 'a[@class = "email"]/@href') |
下表显示了ItemLoader对象的属性-
Sr.No | Attribute & Description |
---|---|
1 |
item It is an object on which the Item Loader performs parsing. |
2 |
context It is the current context of Item Loader that is active. |
3 |
default_item_class It is used to represent the items, if not given in the constructor. |
4 |
default_input_processor The fields which don’t specify input processor are the only ones for which default_input_processors are used. |
5 |
default_output_processor The fields which don’t specify the output processor are the only ones for which default_output_processors are used. |
6 |
default_selector_class It is a class used to construct the selector, if it is not given in the constructor. |
7 |
selector It is an object that can be used to extract the data from sites. |
它用于在解析文档小节中的值时创建嵌套加载程序。如果不创建嵌套的加载器,则需要为要提取的每个值指定完整的XPath或CSS。
例如,假设数据是从标题页中提取的-
接下来,您可以通过向标头添加相关值来创建带有标头选择器的嵌套加载器-
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)
以下是一些常用的内置处理器-
它返回原始值而不更改它。例如-
>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['a', 'b', 'c'])
['a', 'b', 'c']
它从接收到的值列表中返回非空/非空的第一个值。例如-
>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'a', 'b', 'c'])
'a'
它返回附加到分隔符的值。默认的分隔符是u”,它等效于函数u” . join 。例如-
>>> from scrapy.loader.processors import Join
>>> proc = Join()
>>> proc(['a', 'b', 'c'])
u'a b c'
>>> proc = Join('
')
>>> proc(['a', 'b', 'c'])
u'a
b
c'
它由处理器定义,每个输入值都传递给第一个函数,该函数的结果传递给第二个函数,依此类推,直到ast函数返回最终值作为输出。
例如-
>>> from scrapy.loader.processors import Compose
>>> proc = Compose(lambda v: v[0], str.upper)
>>> proc(['python', 'scrapy'])
'PYTHON'
它是一个处理器,在该处理器中迭代输入值,并且将第一个函数应用于每个元素。接下来,将这些函数调用的结果连接起来以构建新的可迭代对象,然后将其应用于第二个函数,依此类推,直到最后一个函数。
例如-
>>> 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']
此类使用提供的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']