Scrapy—— Item Loaders

用Item Loader来填充Item

Item Loaders 提供了一种便捷的方式填充抓取到的Items。虽然Items可以使用自带的类字典形式API填充,但是Items Loaders提供了更便捷的API,可以分析原始数据并对Item进行赋值。
另一方面,Items提供保存抓取数据的容器,而Item Loaders提供的时填充容器的机制。Item Loaders提供的是一种灵活,高效的机制,可以更方便的被spider或source format扩展,并且容易维护的、不同的内容分析规则。
要使用Item Loader,必须先将它实例化,可以使用类似字典的对象来进行实例化,当不使用对象进行实例化时,Item会自动使用ItemLoader.default_item_class属性中指定ltem类在Item Loader constructor中实例化。
然后开始收集数值到Item Loader时,通常使用Selectors。可以在item field里面添加多个数值,Item Loader 将知道如何使用合适的处理函数来添加这些数值。
典型用法

from scrapy.loader import ItemLoader from myproject.items import Product def parse(self, response): l = ItemLoader(item=Product(), response=response) l.add_xpath('name', '//div[@class="product_name"]') l.add_xpath('name', '//div[@class="product_title"]') l.add_xpath('price', '//p[@id="price"]') l.add_css('stock', 'p#stock]') l.add_value('last_updated', 'today') # you can also use literal values return l.load_item()

使用add_xpath()方法从两个Xpath位置提取数据来收集数据,这是稍后将分配给name字段的数据。之后,可诶四的调用用于ptice和stock字段,最后使用不同的方法last_update直接使用文字值填充字段add_value()。收集数据时,该ItemLoader.load_item()方法被称为实际上返回调重先前提取并收集到的数据的项目add_xpath()add_css()add_value()调用。

输出和输入处理器

项目加载器对于每个字段包含一个输入和输出处理器。输入处理器只要它的接收处理所提取的数据和输入处理器的结果被收集并保持Item Loader内部。收集所有数据后,ItemLoader.load_item()调用该方法来填充Item对象。这是当输出处理器使用先前收集的数据调用时,输出处理器的结果时分配给项目的最终值。
如何为特定字段调用输入和输出处理器

l = ItemLoader(Product(), some_selector) l.add_xpath('name', xpath1) # (1) l.add_xpath('name', xpath2) # (2) l.add_css('name', css) # (3) 
l.add_value('name', 'test') # (4)
 return l.load_item() # (5)

内部运行过程:

  • (1)从数据xpath1提取出来,并通过所传递的输入处理器的name字段。输入处理器的结果被收集并保存在项目皆在其中(单尚未分配给项目);
  • (2)从xpath2提取数据。并通过1中使用的同一输入处理器。输入处理器的结果附加到1中收集的数据。
  • (3)类似于1和2,除了数据从CSS选择器提取,并且通过在1和2中使用的相同的输入处理器。输入处理器的结果附加到1和2中收集的数据。
  • (4)类似于之前的情况,除了要收集的值直接分配。但是该值人仍然通过输入处理器。在这种情况下,由于该值不可迭代,一次在将其传递给输入处理器之前,它将转换为单个元素的可迭代,因为输入处理器总是接收迭代。
  • (5)在步骤1,2,3,4中收集的数据通过name字段的输出处理器。输出处理器的结果是分配给name项目中字段的值。

处理器值时可调用的对象,它们使用要解析的数据调用,并返回解析的值。所以你可以使用任何功能作为输入或输出处理器。唯一要求是它们必须接受一个位置参数,这将是一个迭代器。
深刻理解

  • 输入处理器用于收集提取数据;
  • 输出处理器用于将数据分配给字段;

声明项目加载器

通过使用类定义语法声明为items。

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




class ProductLoader(ItemLoader):
    
    default_output_processor = TakeFirst()
    
    name_in=MapCompose(unicode.title)
    name_out=Join()
    
    
    price_in=MapCompose(unicode.strip)
    
    #...

输入处理器使用_in后缀声明,而输出处理器使用_out后缀声明。号可以使用ItemLoader.default_input_processor和 ItemLoader.default_output_processor属性声明默认输入和输出处理器。

声明输入和输出处理器

输入和输出处理器可以在Item Loader定义中声明,这种方式声明输入处理器比较常见。还有一种方式是在项目字段元数据中。

import scrapy
from scrapy.loader.processors import TakeFirst,MapCompose,Join
from w3lib.html import remove_tags


def filter_price(args):
    if args.isdigit():
        return args


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),
        output_processor=TakeFirst(),

    )

if __name__=="__main__":
    i1=ItemLoader(item=Product())
    i1.add_value('name',[u'Welcome to my',u'<strong>website</strong>'])
    i1.add_value('price',[u'%',u'<span>1000</span>'])
    print i1.load_item()
    
    
# {'name': u'Welcome to my website', 'price': u'1000'}

输入输出处理器优先级顺序:

1,项目加载程序字段特定属性field_in和field_out;
2,字段元数据input_processor和output_processor;
3,项目加载默认值ItemLoader.default_input_processor()和 ItemLoader.default_output_processor();

项目加载其上下文

项目加载器上下文是在项目加载器中的所有输入和输出处理器之间供像的任意键/值的dict。它可以在声明,实例化或使用Item Loader时传递,用于修改输入/输出处理器的行为。

假设有一个parse_lengh接收文本值并从中提取长度的函数。

def  parse_length(text,loader_context ):
    unit = loader_context.get('unit','m' )
    #...长度解析代码在这里... 
    return  parsed_length

通过接收一个loader_context参数,该函数显式的告诉Item Loader它能够接受一个Item Loader上下文,因此Item Loader在调用它时传递当前活动的上下文,因此处理器功能可以使用它们。

有几种方法可以修改当前活动的Item Loader上下文:

1,通过修改当前或定的Item Loader上下文:

loader = ItemLoader(product)
loader.context['unit'] = 'cm'

2,On Item Loader实例化

loader = ItemLoader(product, unit='cm')

3,On Item Loader声明,对于那些支持使用ItemLoader上下文实例化的输入和输出处理器。MapCompose是其中之一。

class ProductLoader(ItemLoader):
    length_out = MapCompose(parse_length, unit='cm')

ItemLoader对象

class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)

返回一个新的Item Loader来填充给定的Item。如果没有给出项目,则使用其中的类自动实例化default_item_class。
当使用选择器或响应参数实例化时,Item Loader类提供了使用选择器从网页中提取数据的方便机制。

参数:

  • item:项目实例来填充用以后调用add_xpath(),add_css()或add_value()。
  • selector:当使用add_xpath()(或。add_css())或replace_xpath() (或replace_css())方法时,从中提取数据的选择器 。
  • response(Responseobject) - 用于使用构造选择器的响应 default_selector_class,除非给出选择器参数,在这种情况下,将忽略此参数。
    项目,选择器,响应和剩余的关键字参数被分配给Loader上下文。

ItemLoader实例方法

  • get_value(value,* processors,** kwargs )处理给定value的给丁processors和关键字参数。
    可用的关键字参数:
    re:用于使用方法从给定值提取数据,在处理器之前应用:
>>> from scrapy.loader.processors import TakeFirst
>>> loader.get_value(u'name: foo', TakeFirst(), unicode.upper, re='name: (.+)')
'FOO
  • add_value(field_name,value,* processors,** kwargs处理,然后添加给定value给给定字段。该值首先通过get_value()赋予 processors和kwargs,然后通过 字段输入处理器及其结果追加到为该字段收集的数据。如果字段已包含收集的数据,则会添加新数据。给定field_name可以是None,在这种情况下可以添加多个字段的值。并且已处理的值应为一个字段,其中field_name映射到值。

  • replace_value(field_name,value,* processors,** kwargs )类似于add_value()单是用新值替换收集的数据,而不是添加它。

  • get_xpath(xpath,* processors,** kwargs )类似于ItemLoader.get_value()但接收的是XPath而不是值,用于从此相关联的选择器提取unicode字符串的列表
    ItemLoader。
    xpath:从中提取数据的xpath
    re:用于从所选Xpath区域提取数据的正则表达式。

  • add_xpath(field_name,xpath,* processor,** kwargs )类似ItemLoader.add_value()但接收XPath而不是值,用于从与此相关联的选择器提取unicode字符串的列表ItemLoader。

  • replace_xpath(field_name,xpath,* processor,** kwargs )类似于add_xpath()但替换收集的数据,而不是添加它。

  • get_css(css,* processors,** kwargs )类似于ItemLoader.get_value()但接收一个CSS选择器而不是一个值,用于从与此相关的选择器提取一个unicode字符串列表ItemLoader。

  • add_css(field_name,css,* processors,** kwargs )类似于ItemLoader.add_value()但接收一个CSS选择器而不是一个值,用于从与此相关的选择器提取一个unicode字符串列表ItemLoader。

  • replace_css(field_name,css,* processors,** kwargs )类似于add_css()但替换收集的数据,而不是添加它。

  • load_item()使用目前收集的数据填充项目,并返回。收集的数据首先通过输出处理器,已获得要分配给每个项目字段的最终值。

  • nested_xpath(xpath )使用xpath选择器创建嵌套加载器。所提供的选择器应用于与此相关的选择器。

  • nested_css(css )使用css选择器创建嵌套加载器。所提供的选择器应用于与此相关的选择器ItemLoader。

  • get_collected_values(field_name )返回给定字段的收集值。

  • get_output_value(field_name )返回给定字段使用输出处理器解析的收集值。此方法根本不填充或修改项目。

  • get_input_processor(field_name )返回给定字段的输入处理器。

  • get_output_processor(field_name )返回给定字段的输出处理器。

ItemLoader实例具有以下属性

  • itemItem此项目加载器解析的对象;
  • context此项目Loader的当前活动上下文;
  • default_item_classItem类,用于在构造函数中未给出时实例化项;
  • default_input_processor用于不指定一个字段的字段的默认输入处理器。
  • default_output_processor用于不指定一个字段的字段的默认输出处理器。
  • default_selector_class所使用的类构造selector的此 ItemLoader,如果只响应在构造函数给出。如果在构造函数中给出了选择器,则忽略此属性。此属性有时在子类中被覆盖。
  • selectorSelector从中提取数据的对象。它是在构造函数中给出的选择器,或者是从构造函数中使用的给定的响应创建的 default_selector_class。此属性意味着是只读的。

嵌套装载器

示例文档

<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:[email protected]">Email Us</a> </footer>

如果没有嵌套加载器,则需要为要提取的每个值指定完整的xpath。像这样:

loader = ItemLoader(item=Item()) # 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()

如果使用页脚选择器创建嵌套加载器,并相对于页脚添加值,功能是相同的,但是你避免重复页脚选择器。

loader = ItemLoader(item=Item()) # load stuff not in the footer footer_loader = loader.nested_xpath('//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()

重用和扩展项目加载器

当你的项目很大时,维护成为一个根本的问题,特别是当你必须处理每个爬虫的许多不同的解析规划,有很多异常,但也想重用公共处理器。
项目加载器旨在减轻解析规则的维护负担,同时不会失去灵活性,同时提供了扩展和覆盖它们的方便机制。

例如,假设某个特定站点以三个短划线(例如)包含其产品名称,并且您不希望最终在最终产品名称中删除那些破折号。

from scrapy.loader.processors import MapCompose from myproject.ItemLoaders import ProductLoader def strip_dashes(x): return x.strip('-') class SiteSpecificLoader(ProductLoader): name_in = MapCompose(strip_dashes, ProductLoader.name_in)


另一种扩展项目,当你有多种源格式,例如XML和HTML,在XML版本中,你可能想要删除CDTA事件。

from scrapy.loader.processors import MapCompose from myproject.ItemLoaders import ProductLoader from myproject.utils.xml import remove_cdata class XmlProductLoader(ProductLoader): name_in = MapCompose(remove_cdata, ProductLoader.name_in)


对于处理器,更常见的是在字段元数据中声明它们,因为它们通常仅依赖于字段而不是特定站点解析规则。

可用内置处理器

  • class scrapy.loader.processors.Identity最简单的处理器,神魔都不做。它返回原始值不变,不接受任何构造函数参数,也不接受Loader上下文。
  • class scrapy.loader.processors.TakeFirst从接收到的值中返沪ui第一个非空值,因此它通常用作单值字典的输出处理器。它不接受任何构造函数参数,也不接受Loader上下文。
>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'one', 'two', 'three'])
'one'

  • class scrapy.loader.processors.Join(separator=u' ')返回与构造函数中给定的分隔符连接的值,默认为,不接受上下文。当使用默认分隔符时,此处理器相当于:u’’.join.
>>> from scrapy.loader.processors import Join >>> proc = Join() >>> proc(['one', 'two', 'three']) u'one two three' >>> proc = Join('<br>') >>> proc(['one', 'two', 'three']) u'one<br>two<br>three'
  • class scrapy.loader.processors.Compose(*functions, **default_loader_context)由给定函数的组合构成的处理器。这意味着该处理器的每个输入值都被传递给第一个函数,并且该函数的结果被传递给第二个函数,以此类推,直到最后一个函数返回该处理器的输出值。默认情况下,停止进行None值,可以通过传递关键字参数来更改此行为stop_on_none=False。
    每个功能可以可选的接收loader_cntext参数。在构造函数中传递的关键字参数用作传递给每个函数调用的默认Loader上下文值。但是传递给函数的最后一个Loader上下文值将被当前可用该属性访问的当前活动Loader上下文覆盖。
  • class scrapy.loader.processors.MapCompose(*functions, **default_loader_context)与处理器类似,由给定功能的组成的compose处理器,与此处理器的区别在与内部结果在函数之间传递的方式。(传递的值可迭代)

该处理器的输入值被迭代,并且第一函数被应用于每个元素。这些函数调用的结果被连接以构造新的迭代,然后用于应用第二个函数,以此类推。直到最后一个函数被应用于收集的值列表的每个值。最后一个函数的输出值被连接在一起已产生该处理器的输出。
每个特定函数可以返回值或值列表,这些值通过应用于其他输入值的相同函数返回的值列表展平。函数也可以返回None在这种情况下该函数的输被忽略。
此处理器提供了一种方便方法来组合只使用单个只的函数。由于这个原因,MapCompose处理器通常用作输入处理器,因为数据通常使用选择器的 extract()方法提取,选择器返回unicode字符串的列表

  • class scrapy.loader.processors.SelectJmes(json_path)使用提供给构造函数的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']

猜你喜欢

转载自blog.csdn.net/mashaokang1314/article/details/82717627