更好的scrapy技能:如何使用scrapy itemloader nest输出dict列表而不是list

时间:2017-01-20 04:55:13

标签: python scrapy

我正在尝试使用scrapy itemloader,我以前只是项目,我希望我的代码更少 例如: 如果我想从页面解析汽车信息列表,我需要car_name,car_color ...但对于某些汽车,颜色为None, 我以前这样写:

cars = response.xpath(carsxpath)
for car in cars:
    car_name = car.xpath(car_name_xpath)
    car_color = car.xpath(car_color_xpath)
    item = CarItem()
    item['car_name'] = car_name
    item['car_color'] = car_color
    yield item

但是最近,我找到了Itemloader,它可以简化代码,从文档中,我发现它的工作原理如下:

loader = ItemLoader(item={}, response=response)
carloader = loader.nested_xpath('car_xpath')
carloader.add('car_name', car_name_xpath)
carloader.add('car_color', car_color_xpath)
cars = loader.load_item()

因为我发现它之前不需要像car_name,car_color这样的tmp var,但是使用这个问题,汽车就是列表的字典,比如

cars = {'car_name':[car_names],'car_color':[car_colors]}

但这对于产生项目是不方便的,我想获得像

这样的输出
cars = [{'carname':carname1,'carclor':carcolor1'}, {'carname':carname2,'carclor':carcolor2'}...]

所以我的问题是'有没有办法在scrapy本身处理这个?',如果我需要处理更多,我宁愿使用我以前的方式,而不是Itemloader

2 个答案:

答案 0 :(得分:0)

您可以为ItemLoader指定一些处理器,这些处理器会在将值添加到项目加载器后对该值执行某些操作。例如,添加项目时只需要第一个元素:

from scrapy.loader.processors import TakeFirst()

loader = ItemLoader(item={}, response=response)
carloader = loader.nested_xpath('car_xpath')
carloader.car_name_out = TakeFirst()
carloader.add('car_name', car_name_xpath)
carloader.car_color_out = TakeFirst()
carloader.add('car_color', car_color_xpath)
cars = loader.load_item()

更优雅地看起来像:

class MyLoader(ItemLoader):
    default_item_class = dict
    car_name_out = TakeFirst()
    car_color_out = TakeFirst()

class MySpider(scrapy.Spider):
    loader = MyLoader(item={}, response=response)
    carloader = loader.nested_xpath('car_xpath')
    carloader.add('car_name', car_name_xpath)
    carloader.add('car_color', car_color_xpath)
    cars = loader.load_item()

答案 1 :(得分:0)

ItemLoader旨在填充单个项目,而不是其中的列表,因此最好使用以下内容:

for sel in response.xpath('car_xpath'):
    l = ItemLoader(selector=sel)
    l.add_xpath('car_name', car_name_xpath)
    l.add_xpath('car_color', car_color_xpath)
    yield l.load_item()

这完全合并了你以前的方法和ItemLoader的用法。