本文共 5348 字,大约阅读时间需要 17 分钟。
项目加载器提供了一个方便的方式来填补从网站上刮取的项目。
声明项目加载器
项目加载器的声明类:Items。例如:
from scrapy.loader import ItemLoaderfrom scrapy.loader.processors import TakeFirst, MapCompose, Joinclass DemoLoader(ItemLoader): default_output_processor = TakeFirst() title_in = MapCompose(unicode.title) title_out = Join() size_in = MapCompose(unicode.strip) # you can continue scraping here
在上面的代码可以看到,输入处理器使用 _id 作为后缀以及输出处理器声明使用_out 作为后缀声明。
ItemLoader.default_input_processor
和 ItemLoader.default_output_processor 属性用于声明默认输入/输出处理器。
使用项目加载器来填充项目
要使用项目加载器,
先用类似字典的对象,
或项目使用 Loader.default_item_class 属性指定 Item 类实例化。
可以使用选择器来收集值到项目加载器。
可以在同一项目字段中添加更多的值,
项目加载器将使用相应的处理程序来添加这些值
下面的代码演示项目是如何使用项目加载器来填充:
from scrapy.loader import ItemLoaderfrom demoproject.items import Demodef 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)字段提取:
1. //div[@class="product_title"]2. //div[@class="product_name"]
此后,类似请求用于内容描述(desc)字段。size数据使用 add_css()方法提取和last_updated 使用add_value()方法使用值“yesterday”来填充。
完成所有收集数据的,调用 ItemLoader.load_item() 方法返回填充并使用 add_xpath(),add_css()和 dadd_value()方法提取数据项。
输入和输出处理器
一个项目加载器的各个字段包含一个输入处理器和一个输出处理器。
当提取数据时,输入处理器处理结果,交将结果存储在数据加载器。
接下来,收集数据后,调用 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行: 标题(title)的数据是从xpath1提取并通过输入处理器,其结果被收集并存储在 ItemLoader 中。
第2行: 同样地,标题(title)从xpath2提取并通过相同的输入处理器,其结果收集的数据加到[1]中。
第3行: 标题(title)被从css选择萃取和通过相同的输入处理器传递并将收集的数据结果加到[1]及[2]。
第4行: 接着,将“demo”值分配并传递到输入处理器。
第5行: 最后,数据是从所有字段内部收集并传递给输出处理器,最终值将分配给项目
声明输入和输出处理器
输入和输出的处理器在项目加载器(ItemLoader )定义声明。除此之外,它们还可以在项目字段的元数据指定。
例如:
import scrapyfrom scrapy.loader.processors import Join, MapCompose, TakeFirstfrom w3lib.htmll import remove_tagsdef filter_size(value): if value.isdigit(): return valueclass 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参数,它告诉项目加载器可以收到项目加载器上下文。有几种方法可以改变项目加载器上下文的值:
修改当前的活动项目加载器上下文:
loader = ItemLoader (product)loader.context ["unit"] = "mm"
在项目加载器实例中修改:
loader = ItemLoader(product, unit="mm")
class ProductLoader(ItemLoader): length_out = MapCompose(parse_length, unit="mm")
它是一个对象,它返回一个新项加载器到填充给定项目。它有以下类:
class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)
嵌套加载器
这是使用从文档解析分段的值来创建嵌套加载器。如果不创建嵌套装载器,需要为您想提取的每个值指定完整的XPath或CSS。
例如,假设要从一个标题页中提取数据:
facebook twitter send mail
接下来,您可以通过添加相关的值到页眉来创建头选择器嵌套装载器:
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 MapComposefrom demoproject.ItemLoaders import DemoLoaderdef 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
回一个值来自收到列表的值即非空/非null值。 例如:
>>> 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('')>>> proc(['a', 'b', 'c'])u'abc'
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']
转载地址:http://rabtf.baihongyu.com/