Scrapy学习笔记VI--Item Loaders

本文详细介绍了Scrapy中的Item Loaders,它是用于填充Items数据的工具,包含Input和Output Processor。Item Loaders允许定义输入和输出处理器的优先级,并提供了Item Loader Context来改变处理器行为。此外,还讨论了嵌套Loaders的使用场景以及如何重用和扩展Item Loaders,文中给出了多个示例来说明其工作原理。
摘要由CSDN通过智能技术生成

Item Loaders

理解:Items为爬取的数据提供容器,而Item Loaders为容器填充数据(提取数据的路径、规则等等……为了方便,便于管理、扩展)

可以先阅读最下方的几个例子,在来一 一对照复习用法

from scrapy.loader import ItemLoader
from myproject.items import Product     # 项目中已经定义的items 类

def parse(self, response):
    l = ItemLoader(item=Product(), response=response)    #参数为Product类数据模板(已经定义好的容器) ,服务器返回的Response
    l.add_xpath('name', '//div[@class="product_name"]')   #定义数据提取路径,收集并保存在item loaders中,还未存入item数据模板中
    l.add_xpath('name', '//div[@class="product_title"]') #定义数据提取路径,收集并保存在item loaders中,还未存入item数据模板中
    l.add_xpath('price', '//p[@id="price"]') #收集price,定义数据提取路径,收集并保存在item loaders中,还未存入item数据模板中
    l.add_css('stock', 'p#stock]')    #收集stock,定义数据提取路径,收集并保存在item loaders中,还未存入item数据模板中use literal values   #直接定义last_updated的数据,可为literal(迭代),
    return l.load_item()   #收集所有数据后,返回已填充的数据,并保存在items的数据模板中(各个field)
  • Input and Output processors

    每一个字段都包含一个Input(收集数据存入列表中)和output(存入items的各个字段中)的过程,如上述例子。
    对象中的第一个参数必须是可迭代的,如“name”,“price”……

  • Declaring item loaders(声明item loaders)

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

class ProductLoader(ItemLoader):    #定义下载器类

    default_output_processor = TakeFirst()   #定义默认的output processor,还可自己定义 

    name_in = MapCompose(unicode.title)  # 以"_in"后缀定义input
    name_out = Join()   #以"_out"后缀定义output

    price_in = MapCompose(unicode.strip)

    # ...
  • Declaring Input and Output Processors #定义input和output的 processor
#定义item字段
import scrapy
from scrapy.loader.processors import Join, MapCompose, TakeFirst
from w3lib.html import remove_tags

def filter_price(value):     #判断value是否为数字
    if value.isdigit():
        return value

class Product(scrapy.Item):
    name = scrapy.Field(
        input_processor=MapCompose(remove_tags),
        output_processor=Join(),
    )
    price = scrapy.Field(
        input_processor=MapCompose(remove_tags, filter_price),    #定义price字段中的input processor 收集规则
        output_processor=TakeFirst(),  #定义price字段中output的存入item的规则
    ) 
>>> from scrapy.loader import ItemLoader
>>> il = ItemLoader(item=Product())  #item下载器初始化
>>> il.add_value('name', [u'Welcome to my', u'<strong>website</strong>'])
>>> il.add_value('price', [u'&euro;', u'<span>1000</span>'])
>>> il.load_item()
{'name': u'Welcome to my website', 'price': u'1000'}
input和output各定义的优先级:
 1. field_in 和 field_out
 2. Field metadata (input_processor and output_processor key)

price = scrapy.Field(
input_processor=MapCompose(remove_tags, filter_price), #定义price字段中的input processor 收集规则
output_processor=TakeFirst(), #定义price字段中output的存入item的规则
)

3.  ItemLoader.default_input_processor() and ItemLoader.default_output_processor()
  • Item Loader Context (需进一步理解, item loader 的指令环境?)

常用来改变input/output processor 的行为,传入指令,如str.upper(把字符串变大写)

在input和output processors中共享的一对字典(任意键值)

在 Item loader中指出可以接受Item Loader Context指令(通过传入参数 loader_context

  • ItemLoader objects
class scrapy.loader.ItemLoader([item,selector,response,])**kwargs)   #返回一个新的itemloader为item填充数据,没有传入item,使用默认的default_item_class

这些参数指定了loader context(loader的指令环境? 通过context属性)

get_xxx   
add_xxx

load_item()  为item填充数据,并且返回。通过

outprocesor获取到value并分配到指定的item field

nested_xpath  嵌套的Xpath提取

get_collected_values(field_name)  #获得field字段的值

get_output_value(field_name)     #通过out processor获得field的字段值 ,并不对item填充数据或者改变

get_input_processor(field_name)

get_output_processor(field_name)
  • ItemLoader 有以下属性
    item : item对象通过item loader进行解析

context : item loader 当前生效的context(上下文环境)

default_item_class

default_input_processor

default_output_processor

default_selector_class

selector

  • Nested Loaders 嵌套的loaders(加载器?)
    有重复路径时使用
<footer>
    <a class="social" href="http://facebook.com/whatever">Like Us</a>
    <a class="social" href="http://twitter.com/whatever">Follow Us</a>
    <a class="email" href="mailto:whatever@example.com">Email Us</a>
</footer>

不使用nested loaders:

loader = ItemLoader(item=Item())   #初始化ItemLoader 
# load stuff not in the footer
loader.add_xpath('social', '//footer/a[@class = "social"]/@href')   #使用全路径
loader.add_xpath('email', '//footer/a[@class = "email"]/@href')
loader.load_item()

使用nested loaders:

loader = ItemLoader(item=Item())
# load stuff not in the footer
footer_loader = loader.nested_xpath('//footer') # 避免重复footer路径
footer_loader.add_xpath('social', 'a[@class = "social"]/@href')
footer_loader.add_xpath('email', 'a[@class = "email"]/@href')
# no need to call footer_loader.load_item()
loader.load_item()
  • Reusing and extending Item Loaders
    当整个项目越来越大,越来越臃肿,要优化代码,减少重复代码的出现

  • Available built-in processors
    可用的内置处理器

eg. 1

class scrapy.loader.processors.Identity  #不做任何事情,返回的原始值不变,也不接收loader contexts
>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['one', 'two', 'three'])
['one', 'two', 'three']

eg.2

class scrapy.loader.processors.TakeFirst #从提取数据开始返回第一个不为空的value ,通常使用在output processor 给单个的字段赋值  ,不接收任何参数和 loader context
>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'one', 'two', 'three'])
'one'

eg. 3

 class scrapy.loader.processors.Join(separator=u' ')  #把返回的值加入到分离器中提供给结构体,默认使用u" "(加个空格),不接收loader context
 >>> from scrapy.loader.processors import Join
>>> proc = Join()  #默认value之间加个空格
>>> proc(['one', 'two', 'three'])
u'one two three'
>>> proc = Join('<br>')
>>> proc(['one', 'two', 'three'])
u'one<br>two<br>three'   #在每个value中间加入<br>

eg. 4

class scrapy.loader.processors.Compose(*functions, **default_loader_context) # 传入方法,loader-context(类似于上下文命令,如下定义str.upper:字符串变大写),当value=None时,process停止,通过改变stop_on_none=False.改变这种行为

>>> from scrapy.loader.processors import Compose
>>> proc = Compose(lambda v: v[0], str.upper)  #当传入了loader_context(str.upper)参数,processor就会自动检测到 active Loader Context,并实现
>>> proc(['hello', 'world'])
'HELLO'

#ItemLoader.context() 属性优先于active Loader context

eg. 5

class scrapy.loader.processors.MapCompose(*functions, **default_loader_context)   # 和compose函数类似,区别如下:
#1. 传递可迭代的参数   
#2.第一个方法作用于每一个元素,结果会重新集合在一个可迭代的对象中-->然后上一个返回的对象依次调用下一个function,直到列表中的每一个元素都被执行过。最后把由输出到output of the processor   
#3.可以返回一个value,也可返回value的列表,也可返回None  
#4.此函数被用作input processor ,当extract()提取数据并返回开一个Unicode列表时。

>>> def filter_world(x):
...     return None if x == 'world' else x
...
>>> from scrapy.loader.processors import MapCompose
>>> proc = MapCompose(filter_world, unicode.upper)
>>> proc([u'hello', u'world', u'this', u'is', u'scrapy'])
[u'HELLO, u'THIS', u'IS', u'SCRAPY']

eg. 6

class scrapy.loader.processors.SelectJmes(json_path) 

>>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose  #函数在同一时间只提供一个输出结果
>>> proc = SelectJmes("foo") #for direct use on lists and dictionaries
>>> proc({'foo': 'bar'})
'bar'
>>> proc({'foo': {'bar': 'baz'}})
{'bar': 'baz'}

json中:
>>> import json
>>> proc_single_json_str = Compose(json.loads, SelectJmes("foo"))
>>> proc_single_json_str('{"foo": "bar"}')
u'bar'
>>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('foo')))
>>> proc_json_list('[{"foo":"bar"}, {"baz":"tar"}]')
[u'bar']

如有错误请指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值