Scrapy之ItemLoader

直接用response的xpath或css方法可以很方便地进行解析,但是代码通常会写得很杂乱。而且有时候对网页进行解析的时候,会遇到同一个字段有多个xpath逻辑的情况。例如,我在解析亚马逊商品页的时候

name = response.xpath('//span[@id="productTitle"]/text()').extract_first("")
if not name:
    name = response.xpath('//span[@id="ebooksProductTitle"]/text()').extract_first("")

Scrapy提供了ItemLoader,可以让代码简洁不少。

from scrapy.loader import ItemLoader

item_loader = ItemLoader(item=Item(),response=response)  #通过Item和response实例化ItemLoader
item_loader.add_xpath('name','//span[@id="productTitle"]/text()')
item_loader.add_xpath('name','//span[@id="ebooksProductTitle"]/text()')
#有需要的话可以添加参数processors和参数re
#如item_loader.add_xpath('name','//span[@id="productTitle"]/text()*',TakeFirst(),re='.*?(\d+).*')
yield item_loader.load_item()

ItemLoader提供了add_xpath(), add_css(), add_value()等方法对字段进行填充。add_css()和add_xpath()类似,而add_value()则是直接将值添加进字段对应的list中。

这里会将从两个xpath中提取到的值,组装成一个list存放在item_loader中。注意现在还只是存放在item_loader中,在对所有字段完成xpath提取之后,要通过load_item()方法将数据传入item中,其返回值就是item。

数据——>输入处理器——>ItemLoader——>输出处理器——>Item

另外要注意的是,如果不进行任何处理的话,现在得到的item会是这样

{
    'name': [value1, value2]
}

为了处理这些数据,我们可以对item_loader中的输入处理器和输出处理器进行修改。

方法一:编写自己的ItemLoader

 

from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose

class ProductItemLoader(ItemLoader):
    default_output_processor = TakeFirst()                #更改所有字段默认的输出处理器

    name_in = MapCompose(function1,function2)           #更改name字段的输入处理器

可以选择通过更改default_input_processor和default_output_processor的方法,更改所有字段默认的输入输出处理器(原本是什么也不做)。也可以通过修改  字段_in和字段_out  来为某个字段选择输入输出处理器。

这里TakeFirst方法,作用是取出list中第一个不为None和空字符串的值,即经过输出处理器后'name'字段的值变为value1。MapCompose方法则是将list中的每一个元素,依次被function1和function2两个函数处理,大家可以自行编写处理函数,函数的参数就是value。

事实上,这里的输入/输出处理器就是带有__call__方法的类,有需要的话可以自行编写。例如:

class NameHandle(object):
#将name字段的两个value合并,并取出
    def __call__(self, values):
        name = ''
        for value in values:
            if value is not None:
                name += value
        return name

方法二:在Item的字段中设置

class ProductspiderItem(scrapy.Item):
    name = scrapy.Field(
        input_processor = MapCompose(DeleteSpace),
        output_processor = TakeFirst()
    )

修改input_processor和output_processor即可

 

有时候我们会希望将多级页面爬取到的数据组装成一个item,如果还想使用ItemLoader的话,可以用parent参数进行数据传递。例如:

class ProductSpider(scrapy.Spider):

    def parse(self,response):
        #略
        yield Request(url=parse.urljoin(response.url,review_url), meta={'item_loader':item_loader1},callback=self.parse_review)

    def parse_review(self,response):
        item_loader2 = ItemLoader(item=ProductspiderItem(),response=response,parent=response.meta.get('item_loader'))

这样一来parse_review中的item_loader2将会继承上级函数parse中item_loader1中存放的数据

 

#以上是我在用Scrapy写项目的过程中自己查文档和总结的,如果有错误欢迎指出

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值