如何使用scrapy中的ItemLoader提取数据?
1. 简述
- 我们在用scrapy爬取数据时,首先就要明确我们要爬取什么数据。scrapy提供了Item对象这种简单的容器,我们可以通过Item定义提取数据的格式,需要爬取哪些字段,其提供了类似于字典的API以及用于声明可用字段的简单语法。如下所示:
- 下面以爬取伯乐在线文章详情页为范例:http://blog.jobbole.com/all-posts/

import scrapy
class articleDetailItem(scrapy.Item):
title = scrapy.Field()
create_date = scrapy.Field()
url = scrapy.Field()
url_object_id = scrapy.Field()
front_image_url = scrapy.Field()
front_image_path = scrapy.Field()
praise_nums = scrapy.Field()
comment_nums = scrapy.Field()
fav_nums = scrapy.Field()
tags = scrapy.Field()
content = scrapy.Field(serializer = str)
- Item字段说明:
- Field 对象指明了每个字段的元数据(metadata)。例如上面例子中 content 字段中指明了该字段的序列化函数为str。
- 可以为每个字段指明任何类型的元数据。Field 对象对接受的值没有任何限制。Field 对象中保存的每个键可以由多个组件使用,并且只有这些组件知道这个键的存在。设置 Field 对象的主要目的就是在一个地方定义好所有的元数据。
- 需要注意的是,用来声明item的 Field 对象并没有被赋值为class的属性。 不过可以通过 Item.fields 属性进行访问。
- 然后在spider.py中,按照一定的规则来进行数据的提取,如下:
from ArticleSpider.items import articleDetailItem
def parseArticelDetail(self, response):
articleObject = articleDetailItem()
fav_nums = response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").extract()[0]
match_re = re.match(".*?(\d+).*", fav_nums)
if match_re:
fav_nums = match_re.group(1)
else:
fav_nums = 0
- 但是当项目很大,提取的字段数以百计,那么各种提取规则会越来越多,按照这种方式来做,维护的工作将会是一场噩梦!
- 所以scrapy就提供了ItemLoader这样一个容器,在这个容器里面可以配置item中各个字段的提取规则。可以通过函数分析原始数据,并对Item字段进行赋值,非常的便捷。
- 可以这么来看 Item 和 Itemloader:Item提供保存抓取到数据的容器,而 Itemloader提供的是填充容器的机制。
- Itemloader提供的是一种灵活,高效的机制,可以更方便的被spider或source format (HTML, XML, etc)扩展并重写,更易于维护,尤其是分析规则特别复杂繁多的时候。
2. 环境
- 系统:win7
- Scrapy 1.4.0
- python 3.6.1
3. ItemLoader使用步骤
3.1. 实例化ItemLoader对象
from scrapy.loader import ItemLoader
- 要使用Itemloader,必须先将它实例化。可以使用类似字典的对象或者我们之前定义的Item对象来进行实例化。
import scrapy
from scrapy.loader import ItemLoader
def parse_detail(self, response):
atricleItemLoader = ItemLoader(item = articleDetailItem(), response=response)
atricleItemLoader.add_xpath('title', '//div[@class="entry-header"]/h1/text()')
articleInfo = atricleItemLoader.load_item()
print(f"articleInfo = {articleInfo}")
- 参数说明:重要的参数有两个
- 第一个参数:item对象, 传递进来的 Item是之前定义的,也可以是一个类似字典的对象。特别需要注意的是,传递的是一个实例,不是类名。……(当然不使用对象也可以,当不用对象进行实例化的时候,Item会自动使用ItemLoader.default_item_class 属性中指定的Item 类在Item Loader constructor中实例化)
- 第二个参数:response,指定用于提取数据的源数据。
3.2. ItemLoader填充数据的三种方法
- 实例化ItemLoader对象之后,接下来,就要开始收集数值到ItemLoader了。ItemLoader提供了三个重要的方法将数据填充进来:
def parse_detail(self, response):
atricleItemLoader = ItemLoader(item = article