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. 笔记-python-lib-lxml

    笔记-python-lib-lxml 1.      lxml简介 lxml是一个实现解析网页文件的库,python中自带有解析库,但没有lxml方便好用. The lxml XML toolkit ...

  2. Alter the structure of web pages with JavaScript

    Most of the DOM methods you've seen so far are useful for identifying elements. Both getElementById ...

  3. 发布“豪情”设计的新博客皮肤-darkgreentrip

    豪情 (http://www.cnblogs.com/jikey/)是一名在上海的前端开发人员,长期驻扎在园子里.他为大家设计了一款新的博客皮肤——darkgreentrip. 以下是该博客皮肤的介绍 ...

  4. typeAliasesPackage 配置

    mybatis 的 xml 文件中需要写类的全限定名,较繁琐,可以配置自动扫描包路径给类配置别名,有两种配置方式. 方式一: mybatis-config.xml 中配置 <typeAliase ...

  5. python2.7写入文件时指定编码为utf-8

    python3.0可以这样写 f = open('ufile.log', 'w', 'utf-8')   但在python2.7中open()没有编码参数,如上那样写会报错,可以使用如下模块 impo ...

  6. Pytest+allure+jenkins生成测试报告

    allure集成jenkins下载地址.下载相关版本的allure包 http://updates.jenkins-ci.org/download/plugins/allure-jenkins-plu ...

  7. NGUI-使用UILabel呈现图片和不同格式的文字

    1.可以使用BBCode标记 [b]Bold[/b]                      粗体[i]italic[/i]                         斜体[u]underli ...

  8. [python] 网络数据采集 操作清单 BeautifulSoup、Selenium、Tesseract、CSV等

    Python网络数据采集操作清单 BeautifulSoup.Selenium.Tesseract.CSV等 Python网络数据采集操作清单 BeautifulSoup.Selenium.Tesse ...

  9. oom 和 jvm crash的问题

    很多次生产环境jvm进程无故消失的时候都留下了hs_err[pid].log文件  然后通过mat分析大多数情况是oom导致的  所以以前一直认为OOM一定会导致jvm crash  也就是说java ...

  10. Java Web Action DAO Service层次理解

    参考来源:http://blog.csdn.net/inter_peng/article/details/41021727 1. Action/Service/DAO简介: Action是管理业务(S ...