Item是保存结构数据的地方,Scrapy可以将解析结果以字典形式返回,但是Python中字典缺少结构,在大型爬虫系统中很不方便。

Item提供了类字典的API,并且可以很方便的声明字段,很多Scrapy组件可以利用Item的其他信息。

定义Item

定义Item非常简单,只需要继承scrapy.Item类,并将所有字段都定义为scrapy.Field类型即可

  1. import scrapy
  2. class Product(scrapy.Item):
  3. name = scrapy.Field()
  4. price = scrapy.Field()
  5. stock = scrapy.Field()
  6. last_updated = scrapy.Field(serializer=str)

Item Fields

Field对象可用来对每个字段指定元数据。例如上面last_updated的序列化函数指定为str,可任意指定元数据,不过每种元数据对于不同的组件意义不一样。

Item使用示例

你会看到Item的使用跟Python中的字典API非常类似

创建Item

  1. >>> product = Product(name='Desktop PC', price=1000)
  2. >>> print product
  3. Product(name='Desktop PC', price=1000)

获取值

  1. >>> product['name']
  2. Desktop PC
  3. >>> product.get('name')
  4. Desktop PC
  5. >>> product['price']
  6. 1000
  7. >>> product['last_updated']
  8. Traceback (most recent call last):
  9. ...
  10. KeyError: 'last_updated'
  11. >>> product.get('last_updated', 'not set')
  12. not set
  13. >>> product['lala'] # getting unknown field
  14. Traceback (most recent call last):
  15. ...
  16. KeyError: 'lala'
  17. >>> product.get('lala', 'unknown field')
  18. 'unknown field'
  19. >>> 'name' in product  # is name field populated?
  20. True
  21. >>> 'last_updated' in product  # is last_updated populated?
  22. False
  23. >>> 'last_updated' in product.fields  # is last_updated a declared field?
  24. True
  25. >>> 'lala' in product.fields  # is lala a declared field?
  26. False

设置值

  1. >>> product['last_updated'] = 'today'
  2. >>> product['last_updated']
  3. today
  4. >>> product['lala'] = 'test' # setting unknown field
  5. Traceback (most recent call last):
  6. ...
  7. KeyError: 'Product does not support field: lala'

访问所有的值

  1. >>> product.keys()
  2. ['price', 'name']
  3. >>> product.items()
  4. [('price', 1000), ('name', 'Desktop PC')]

Item Loader

Item Loader为我们提供了生成Item的相当便利的方法。Item为抓取的数据提供了容器,而Item Loader可以让我们非常方便的将输入填充到容器中。

下面我们通过一个例子来展示一般使用方法:

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

注意上面的name字段是从两个xpath路径添累加后得到。

输入/输出处理器

每个Item Loader对每个Field都有一个输入处理器和一个输出处理器。输入处理器在数据被接受到时执行,当数据收集完后调用ItemLoader.load_item()时再执行输出处理器,返回最终结果。

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

执行流程是这样的:

  1. xpath1中的数据被提取出来,然后传输到name字段的输入处理器中,在输入处理器处理完后生成结果放在Item Loader里面(这时候没有赋值给item)
  2. xpath2数据被提取出来,然后传输给(1)中同样的输入处理器,因为它们都是name字段的处理器,然后处理结果被附加到(1)的结果后面
  3. 跟2一样
  4. 跟3一样,不过这次是直接的字面字符串值,先转换成一个单元素的可迭代对象再传给输入处理器
  5. 上面4步的数据被传输给name的输出处理器,将最终的结果赋值给name字段

自定义Item Loader

使用类定义语法,下面是一个例子

  1. from scrapy.loader import ItemLoader
  2. from scrapy.loader.processors import TakeFirst, MapCompose, Join
  3. class ProductLoader(ItemLoader):
  4. default_output_processor = TakeFirst()
  5. name_in = MapCompose(unicode.title)
  6. name_out = Join()
  7. price_in = MapCompose(unicode.strip)
  8. # ...

通过_in_out后缀来定义输入和输出处理器,并且还可以定义默认的ItemLoader.default_input_processorItemLoader.default_input_processor.

在Field定义中声明输入/输出处理器

还有个地方可以非常方便的添加输入/输出处理器,那就是直接在Field定义中

  1. import scrapy
  2. from scrapy.loader.processors import Join, MapCompose, TakeFirst
  3. from w3lib.html import remove_tags
  4. def filter_price(value):
  5. if value.isdigit():
  6. return value
  7. class Product(scrapy.Item):
  8. name = scrapy.Field(
  9. input_processor=MapCompose(remove_tags),
  10. output_processor=Join(),
  11. )
  12. price = scrapy.Field(
  13. input_processor=MapCompose(remove_tags, filter_price),
  14. output_processor=TakeFirst(),
  15. )

优先级:

  1. 在Item Loader中定义的field_infield_out
  2. Filed元数据(input_processoroutput_processor关键字)
  3. Item Loader中的默认的

Tips:一般来讲,将输入处理器定义在Item Loader的定义中field_in,然后将输出处理器定义在Field元数据中

Item Loader上下文

Item Loader上下文被所有输入/输出处理器共享,比如你有一个解析长度的函数

  1. def parse_length(text, loader_context):
  2. unit = loader_context.get('unit', 'm')
  3. # ... length parsing code goes here ...
  4. return parsed_length

初始化和修改上下文的值

  1. loader = ItemLoader(product)
  2. loader.context['unit'] = 'cm'
  3. loader = ItemLoader(product, unit='cm')
  4. class ProductLoader(ItemLoader):
  5. length_out = MapCompose(parse_length, unit='cm')

内置的处理器

  1. Identity 啥也不做
  2. TakeFirst 返回第一个非空值,通常用作输出处理器
  3. Join 将结果连起来,默认使用空格’ ‘
  4. Compose 将函数链接起来形成管道流,产生最后的输出
  5. MapCompose 跟上面的Compose类似,区别在于内部结果在函数中的传递方式.它的输入值是可迭代的,首先将第一个函数依次作用于所有值,产生新的可迭代输入,作为第二个函数的输入,最后生成的结果连起来返回最终值,一般用在输入处理器中。
  6. SelectJmes 使用json路径来查询值并返回结果转
    Scrapy笔记(5)- Item详解

转 Scrapy笔记(5)- Item详解的更多相关文章

  1. qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)

    原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...

  2. 自学Zabbix4.2 web监控项创建+item详解

    自学Zabbix4.2 web监控项创建+item详解 1. web监控项创建 1.1  Scenario 选项卡 Name: 监控项的名称 Application: 放到哪个应用中 Authenti ...

  3. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...

  4. Scrapy的Item_loader机制详解

    一.ItemLoader与Item的区别 ItemLoader是负责数据的收集.处理.填充,item仅仅是承载了数据本身 数据的收集.处理.填充归功于item loader中两个重要组件: 输入处理i ...

  5. Hive笔记--sql语法详解及JavaAPI

    Hive SQL 语法详解:http://blog.csdn.net/hguisu/article/details/7256833Hive SQL 学习笔记(常用):http://blog.sina. ...

  6. 算法笔记--sg函数详解及其模板

    算法笔记 参考资料:https://wenku.baidu.com/view/25540742a8956bec0975e3a8.html sg函数大神详解:http://blog.csdn.net/l ...

  7. Android笔记——四大组件详解与总结

     android四大组件分别为activity.service.content provider.broadcast receiver. ------------------------------- ...

  8. Struts2学习笔记(二)——配置详解

    1.Struts2配置文件加载顺序: default.properties(默认常量配置) struts-default.xml(默认配置文件,主要配置bean和拦截器) struts-plugin. ...

  9. Struts2学习笔记二 配置详解

    Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...

随机推荐

  1. 18 Django-组件拾遗

    一 Django的form组件 forms组件 二 Django的model form组件 这是一个神奇的组件,通过名字我们可以看出来,这个组件的功能就是把model和form组合起来,先来一个简单的 ...

  2. Android 微信支付步骤

    以前自己写过微信支付,今天让我用h5调用微信支付,结果还浪费了点时间,虽然时间不长. 1.导入jar包 .微信提供的jar包 2.写你的微信支付的代码,其实如果参数都有了就一段代码: public v ...

  3. BF算法(蛮力匹配算法)

    将主串M指定位置和目标串S开始位置进行对比,如果相同将M的下一个字符和S的下一个字符对比,如果不同则M的下一个字符和S的开始位置对比,直到S中每一个字符和M中的连续字符串相等,否则不匹配. C#代码- ...

  4. 2.route路由配置

    转自 http://www.cnblogs.com/peida/archive/2013/03/05/2943698.html Linux系统的route命令用于显示和操作IP路由表(show / m ...

  5. Maven学习 (三) 使用m2eclipse创建web项目

    1.首先确认你的eclipse已经安装好m2eclipse的环境,可以参照上两篇Maven学习内容 2.新建一个maven的项目 3.下一步默认配置,使用默认的工作空间,或者你可以自己选择其他的空间 ...

  6. 关于main与wmain函数

    最近写一个控制台程序,并且希望该控制台程序运行时不显示控制台窗口,于是在程序include语句下面加入如下代码 #pragma comment (linker,"/subsystem:\&q ...

  7. 解决idea无法下载插件的问题

    分析原因: 使用了 https 协议下载而导致的问题. 解决办法: 找到 File -> Settings -> Appearance & Behavior -> Syste ...

  8. GLIBCXX3.4.21 not find

    在执行世界杯的二进制代码和安装keepaway中会遇到GLIBCXX3.4.21 not find的问题,其解决办法就是升级安装GCC. 一.首先查看当前gcc版本 $ strings /usr/li ...

  9. time模块与random模块,六位含字母随机验证码

    # time模块# import time# time.time()#计算这一时刻时间戳 *******# time.sleep(1)#让cpu休眠一定时间 *******# time.clock() ...

  10. SDK接入注意点

    1. 新建的android项目,要把MainActivity.java里生成的东西全部删去,最好只留个onCreate入口方法,不然会产生什么“hello world”,会把自己写的View内的东西覆 ...