Item Loaders(项目加载器),意义,当项目很大的时候,提取的字段数以百计,做维护是很困难的。
所以scrapy就提供了ItemLoader这样一个容器,在这个容器里面可以配置item中各个字段的提取规则。可以通过函数分析原始数据,并对Item字段进行赋值,非常的便捷。参考网站:https://blog.csdn.net/zwq912318834/article/details/79530828
可以这么来看 Item 和 Itemloader:Item提供保存抓取到数据的容器,而 Itemloader提供的是填充容器的机制。
Itemloader提供的是一种灵活,高效的机制,可以更方便的被spider或source format (HTML, XML, etc)扩展并重写,更易于维护,尤其是分析规则特别复杂繁多的时候。
使用方法如下
第一步:实例化对象
首先在Item.py文件中定义一个类,这里定义一个articleDetailItem类
其次在爬虫文件中使用类似的字典的对象或者自定义的Item对象进行实例化,如下:
# 文件 boleSpider.py
mport scrapy
from scrapy.loader import ItemLoader
def parse_detail(self, response):
# 需要实例化ItemLoader, 注意第一个参数必须是实例化的对象...
atricleItemLoader = ItemLoader(item = articleDetailItem(), response=response)
然后填充数据,使用标准的三个方法,add_xpath、add_css、add_value。
# 调用xpath选择器,提取title信息
atricleItemLoader.add_xpath('title', '//div[@class="entry-header"]/h1/text()')
# 调用css选择器,提取praise_nums信息
atricleItemLoader.add_css('praise_nums', '.vote-post-up h10::text')
# 直接给字段赋值,尤其需要注意,不管赋值的数据是什么,都会自动转换成list类型
atricleItemLoader.add_value('url', response.url)
最后将数据提取出去,使用load_item()方法,具体实例如下:
articleInfo = atricleItemLoader.load_item()
第二步:进一步处理。 如果提取出来的数据需要取其中的一个或者对去除数据进一步处理,需要改写item.py文件,引入 输入处理器input_processor和输出处理器output_processor,实例代码如下:
class articleDetailItem(scrapy.Item):
# 标题
title = scrapy.Field()
# 文章创建时间
create_date = scrapy.Field(
# 转换前是'create_date':'\r\n\r\n 2018/03/14 · '
# 转换后是'create_date': datetime.date(2018, 3, 14),
input_processor = MapCompose(date_convert),
output_processor = TakeFirst()
)
# 文章链接地址
url = scrapy.Field(
# 转换前是'url': ['http://blog.jobbole.com/113771/']
# 转换后是'url': 'http://blog.jobbole.com/113699/'
output_processor = TakeFirst()
)
其中TakeFirst()取第一个,Mapcompose()函数是引入处理函数的,其中的参数date_convert是一个函数名字,这个需要在itmes.py文件中最前边写date_convert这个函数。itmes.py完整代码如下
# 文件items.py
import datetime
import scrapy
# 定义一个时间处理转换函数
# 将 '\r\n\r\n 2018/03/06 · ' 转换成 datetime.date(2018, 3, 14)
def date_convert(value):
try:
create_date = datetime.datetime.strptime(value, "%Y/%m/%d").date()
except Exception as e:
create_date = datetime.datetime.now().date()
return create_date
# 用于存储解析文章的详细信息
class articleDetailItem(scrapy.Item):
# 文章创建时间
create_date = scrapy.Field(
# 转换前是'create_date':'\r\n\r\n 2018/03/14 · '
# 转换后是'create_date': datetime.date(2018, 3, 14),
input_processor = MapCompose(date_convert),
output_processor = TakeFirst()
)
类似TakeFirst()的函数系统自定义的函数还有很多,常用的如下:
TakeFirst():返回第一个非空(non-null/ non-empty)值,常用于单值字段的输出处理器,无参数。
Identity():最简单的处理器,不进行任何处理,直接返回原来的数据。无参数。
Join():返回用分隔符连接后的值。分隔符默认为空格。不接受Loader contexts():当使用默认分隔符的时候,这个处理器等同于如下这个:u' '.join
Compose():用给定的多个函数的组合,来构造的处理器。list对象(注意不是指list中的元素),依次被传递到第一个函数,然后输出,再传递到第二个函数,一个接着一个,直到最后一个函数返回整个处理器的输出。
默认情况下,当遇到None值(list中有None值)的时候停止处理。可以通过传递参数stop_on_none = False改变这种行为。
MapCompose():与Compose处理器类似,区别在于各个函数结果在内部传递的方式(会涉及到list对象解包的步骤):
输入值是被迭代的处理的,List对象中的每一个元素被单独传入,第一个函数进行处理,然后处理的结果被连接起来形成一个新的迭代器,并被传入第二个函数,以此类推,直到最后一个函数。最后一个函数的输出被连接起来形成处理器的输出。
每个函数能返回一个值或者一个值列表,也能返回None(会被下一个函数所忽略)
这个处理器提供了很方便的方式来组合多个处理单值的函数。因此它常用于输入处理器,因为传递过来的是一个List对象。
重用和扩展ItemLoaders
从上面的信息来看,ItemLoaders是非常灵活的,但是假设有个需求,所有的字段,我们都要去取第一个,那么如果有300个字段,我们就要添加300次,每个都要写,就会觉得很麻烦。那么有没有办法统一设置呢,答案是有的=>可以定义一个自己的ItemLoader类:ArticleItemLoader(继承自ItemLoader类)
scrapy中默认原始的 ItemLoader 类是这样写的,这个类卸载__init__.py文件中,具体如下:
# E:\Miniconda\Lib\site-packages\scrapy\loader\__init__.py
class ItemLoader(object):
default_item_class = Item
# 可以看到是有默认的输入/输出处理器的,而且默认是什么都不做
default_input_processor = Identity()
default_output_processor = Identity()
default_selector_class = Selector
而我们自定义Item类需要在item.py如下填写:
# 文件items.py
from scrapy.loader import ItemLoader
# 需要继承内置的ItemLoader类
class ArticleItemLoader(ItemLoader):
# 自定义itemloader,默认的输出处理器为取第一个非空元素
default_output_processor = TakeFirst()
具体的在爬虫.py使用时,们就不能再简单的使用原有的ItemLoader,而是使用我们自己定义的 ArticleItemLoader 来填充数据:
# 文件boleSpider.py
from ArticleSpider.items import articleDetailItem, ArticleItemLoader
# 使用自定义的ArticleItemLoader实例化一个item_loader 对象
# 然后发现,结果都是从list中取出了一个值:说明我们的设置已经生效了。
item_loader = ArticleItemLoader(item = articleDetailItem(), response=response)
item_loader.add_xpath('title', '//div[@class="entry-header"]/h1/text()')