转 Scrapy笔记(5)- Item详解
Item是保存结构数据的地方,Scrapy可以将解析结果以字典形式返回,但是Python中字典缺少结构,在大型爬虫系统中很不方便。
Item提供了类字典的API,并且可以很方便的声明字段,很多Scrapy组件可以利用Item的其他信息。
定义Item
定义Item非常简单,只需要继承scrapy.Item类,并将所有字段都定义为scrapy.Field类型即可
- import scrapy
- class Product(scrapy.Item):
- name = scrapy.Field()
- price = scrapy.Field()
- stock = scrapy.Field()
- last_updated = scrapy.Field(serializer=str)
Item Fields
Field对象可用来对每个字段指定元数据。例如上面last_updated的序列化函数指定为str,可任意指定元数据,不过每种元数据对于不同的组件意义不一样。
Item使用示例
你会看到Item的使用跟Python中的字典API非常类似
创建Item
- >>> product = Product(name='Desktop PC', price=1000)
- >>> print product
- Product(name='Desktop PC', price=1000)
获取值
- >>> product['name']
- Desktop PC
- >>> product.get('name')
- Desktop PC
- >>> product['price']
- 1000
- >>> product['last_updated']
- Traceback (most recent call last):
- ...
- KeyError: 'last_updated'
- >>> product.get('last_updated', 'not set')
- not set
- >>> product['lala'] # getting unknown field
- Traceback (most recent call last):
- ...
- KeyError: 'lala'
- >>> product.get('lala', 'unknown field')
- 'unknown field'
- >>> 'name' in product # is name field populated?
- True
- >>> 'last_updated' in product # is last_updated populated?
- False
- >>> 'last_updated' in product.fields # is last_updated a declared field?
- True
- >>> 'lala' in product.fields # is lala a declared field?
- False
设置值
- >>> product['last_updated'] = 'today'
- >>> product['last_updated']
- today
- >>> product['lala'] = 'test' # setting unknown field
- Traceback (most recent call last):
- ...
- KeyError: 'Product does not support field: lala'
访问所有的值
- >>> product.keys()
- ['price', 'name']
- >>> product.items()
- [('price', 1000), ('name', 'Desktop PC')]
Item Loader
Item Loader为我们提供了生成Item的相当便利的方法。Item为抓取的数据提供了容器,而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()
注意上面的name字段是从两个xpath路径添累加后得到。
输入/输出处理器
每个Item Loader对每个Field都有一个输入处理器和一个输出处理器。输入处理器在数据被接受到时执行,当数据收集完后调用ItemLoader.load_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)
执行流程是这样的:
xpath1中的数据被提取出来,然后传输到name字段的输入处理器中,在输入处理器处理完后生成结果放在Item Loader里面(这时候没有赋值给item)xpath2数据被提取出来,然后传输给(1)中同样的输入处理器,因为它们都是name字段的处理器,然后处理结果被附加到(1)的结果后面- 跟2一样
- 跟3一样,不过这次是直接的字面字符串值,先转换成一个单元素的可迭代对象再传给输入处理器
- 上面4步的数据被传输给
name的输出处理器,将最终的结果赋值给name字段
自定义Item Loader
使用类定义语法,下面是一个例子
- 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_input_processor.
在Field定义中声明输入/输出处理器
还有个地方可以非常方便的添加输入/输出处理器,那就是直接在Field定义中
- import scrapy
- from scrapy.loader.processors import Join, MapCompose, TakeFirst
- from w3lib.html import remove_tags
- def filter_price(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),
- output_processor=TakeFirst(),
- )
优先级:
- 在Item Loader中定义的
field_in和field_out - Filed元数据(
input_processor和output_processor关键字) - Item Loader中的默认的
Tips:一般来讲,将输入处理器定义在Item Loader的定义中field_in,然后将输出处理器定义在Field元数据中
Item Loader上下文
Item Loader上下文被所有输入/输出处理器共享,比如你有一个解析长度的函数
- def parse_length(text, loader_context):
- unit = loader_context.get('unit', 'm')
- # ... length parsing code goes here ...
- return parsed_length
初始化和修改上下文的值
- loader = ItemLoader(product)
- loader.context['unit'] = 'cm'
- loader = ItemLoader(product, unit='cm')
- class ProductLoader(ItemLoader):
- length_out = MapCompose(parse_length, unit='cm')
内置的处理器
Identity啥也不做TakeFirst返回第一个非空值,通常用作输出处理器Join将结果连起来,默认使用空格’ ‘Compose将函数链接起来形成管道流,产生最后的输出MapCompose跟上面的Compose类似,区别在于内部结果在函数中的传递方式.它的输入值是可迭代的,首先将第一个函数依次作用于所有值,产生新的可迭代输入,作为第二个函数的输入,最后生成的结果连起来返回最终值,一般用在输入处理器中。SelectJmes使用json路径来查询值并返回结果转
Scrapy笔记(5)- Item详解
转 Scrapy笔记(5)- Item详解的更多相关文章
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...
- 自学Zabbix4.2 web监控项创建+item详解
自学Zabbix4.2 web监控项创建+item详解 1. web监控项创建 1.1 Scenario 选项卡 Name: 监控项的名称 Application: 放到哪个应用中 Authenti ...
- expect学习笔记及实例详解【转】
1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...
- Scrapy的Item_loader机制详解
一.ItemLoader与Item的区别 ItemLoader是负责数据的收集.处理.填充,item仅仅是承载了数据本身 数据的收集.处理.填充归功于item loader中两个重要组件: 输入处理i ...
- Hive笔记--sql语法详解及JavaAPI
Hive SQL 语法详解:http://blog.csdn.net/hguisu/article/details/7256833Hive SQL 学习笔记(常用):http://blog.sina. ...
- 算法笔记--sg函数详解及其模板
算法笔记 参考资料:https://wenku.baidu.com/view/25540742a8956bec0975e3a8.html sg函数大神详解:http://blog.csdn.net/l ...
- Android笔记——四大组件详解与总结
android四大组件分别为activity.service.content provider.broadcast receiver. ------------------------------- ...
- Struts2学习笔记(二)——配置详解
1.Struts2配置文件加载顺序: default.properties(默认常量配置) struts-default.xml(默认配置文件,主要配置bean和拦截器) struts-plugin. ...
- Struts2学习笔记二 配置详解
Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...
随机推荐
- 遗传算法 | Java版GA_TSP(我的第一个Java程序)
嗯哼,第一次写博客,准确说是第一次通过文字的方式记录自己的工作,闲话少叙,技术汪的博客就该直奔技术主题(关于排版问题,会在不断写博客的过程中慢慢学习,先将就着用吧,重在技术嘛~~~). 遗传算法(Ge ...
- 在庫購買管理(MM)
■購買管理■ [購買依頼]ME51N: 登録ME52N: 変更ME53N: 照会 [購買発注]ME21N: 登録ME22N: 変更ME23N: 照会 [見積依頼]ME41: 登録ME42: 変更ME4 ...
- 网络编程介绍(uninx/windows)
1.网络中进程之间如何通信? 2.Socket是什么? 3.socket的基本操作 3.1.socket()函数 3.2.bind()函数 3.3.listen().connect()函数 3.4.a ...
- CodeForces 778D Parquet Re-laying 构造
题意: 有两个\(n \times m\)的矩阵\(A,B\),都是由\(1 \times 2\)的砖块铺成,代表初始状态和结束状态 有一种操作可以把两个砖块拼成的\(2 \times 2\)的矩形旋 ...
- easyui js拼接html,class属性失效的问题
问题:要在前一个按钮之后添加相同的样式的按钮,通过$("#cj").html(str); 这样的形式添加,却不能添加上样式 <div id="btn" c ...
- PKUWC 2018 彻底滚粗记
PKUWC 2018 彻底滚粗记 如果你们有看到我又在颓, 请以这篇文章让我回忆起这不堪回首的往事. day -3 据说我们要参加PKUWC? 谢总要求我们练习面试,写个稿子. 不知道为什么,有一种不 ...
- 【tomacat集群】Linux或 window配置多个Tomcat同时运行-完美解决-未来星开发团队-费元星
Linux系统下怎样配置多个Tomcat同时运行呢,首先修改变量为第一个tomcat,然后修改第二个tomcat启动的脚本 如何在同一系统里同时启动多个Tomcat http://www.cnb ...
- centos使用--防火墙
目录 1 切换到zsh 1.1 查看系统当前的shell 1.2 查看bin下是否有zsh包 1.3 安装zsh包 1.4 切换shell至zsh 2 安装oh-my-zsh 2.1 oh-my-zs ...
- 《Cracking the Coding Interview》——第4章:树和图——题目7
2014-03-19 04:48 题目:最近公共父节点问题. 解法1:Naive算法,先对其高度,然后一层一层往上直到找到结果. 代码: // 4.7 Least Common Ancestor // ...
- Python程序执行时的不同电脑路径不同问题
原因:因代码转移时项目路径发生了变化,导致解释器无法找到对应路径,是的程序无法正常执行 需求: 1.我希望代码能在不同的电脑下,不必修改源代码就能正常执行(所需模块已安装的前提下) 2.我希望代码在命 ...