在前面的章节我们学习了使用Selector提取数据,那么接下来要做的就是如何封装这些数据。以提取简书文章信息为例,我们需要获取文章标题,文章URL和文章的作者名称信息字段。应该用怎样的数据结构来封装这些零散的信息字段呢?最简单的方式就是使用Python字典(dict),如下。
jianshu =
----{
--------'title': '文章标题',
--------'url': '文章URL',
--------'author_name':'文章的作者'
----}
但是使用Python字典存储字段信息有如下缺点:
- 无法一目了然地了解数据中包含哪些字段,影响代码可读性。
- 缺乏对字段名字的检测,容易因程序员的笔误而出错。
- 不便于携带元数据(传递给其他组件的信息)。
为解决上述问题,在Scrapy中可以使用自定义的Item来封装数据。Item是保存结构数据的地方,Scrapy可以将解析结果以字典形式返回,但是Python中字典缺少结构,在大型爬虫系统中很不方便。Item提供了类字典的API,并且可以很方便的声明字段,很多Scrapy组件可以利用Item的其他信息。
一、Item和Field介绍
Scrapy提供了两个类用来封装数据:
- Item基类
自定义数据类的基类。 - Field类
用来描述自定义数据类包含哪些字段。
定义Item非常简单,只需要继承scrapy.Item
类,并将所有字段都定义为scrapy.Field
类型即可。
以获取简书文章信息为例,我们要获取文章标题,文章URL和文章的作者名称。对此,在Item中定义相应的字段。
import scrapy
class JianshuItem(scrapy.Item):
----title = scrapy.Field()
----url = scrapy.Field()
----author_name = scrapy.Field()
二、Item字段(Item Fields)
Field对象指明了每个字段的元数据(metadata)。例如下面例子中 author_name 中指明了该字段的序列化函数。
import scrapy
class JianshuItem(scrapy.Item):
----title = scrapy.Field()
----url = scrapy.Field()
----author_name = scrapy.Field(serializer=str)
可以为每个字段指明任何类型的元数据, Field 对象对接受的值没有任何限制。Field 对象中保存的每个键可以由多个组件使用,并且只有这些组件知道这个键的存在。设置 Field 对象的主要目的就是在一个地方定义好所有的元数据。一般来说,那些依赖某个字段的组件肯定使用了特定的键(key)。如下例子,元数据的种类非常多。
import scrapy
class ExampleItem(scrapy.Item):
# field_1有两个元数据,a是一个字符串,b是列表
----field_1 = scrapy.Field(a='hello', b=[1,2,3])
# field_2有一个元数据,a是一个函数
----field_2 = scrapy.Field(a=num(1:n))
至于它们在实战上是如何使用的,将在实战章节做详细讲解,目前只要了解有这些内容即可。
三、Item Loader
Item Loader为我们提供了生成Item的相当便利的方法。Item为抓取的数据提供了容器,而Item Loader可以让我们非常方便的将输入填充到容器中。
下面通过一个例子来展示一般使用方法:
from scrapy.loader import ItemLoader
from myproject.items import JianshuItem
def parse(self, response):
----jianshu_item = ItemLoader(item=JianshuItem(), response=response)
----jianshu_item.add_xpath('title', '获取对应元素的XPath表达式')
----jianshu_item.add_xpath('url', '获取对应元素的XPath表达式')
----jianshu_item.add_xpath('author_name', '获取对应元素的XPath表达式')
----return jianshu_item.load_item()
四、扩展Item
可以通过继承原始的Item来扩展Item(添加更多的字段或者修改某些字段的元数据)。有些时候,我们会根据需求对已有的Item进行扩展。比如我们有一个特定的爬虫需要采集这篇文章的发布时间,那么可以继承JianshuItem定义一个ParticularJianshuItem类,在其中添加一个时间的字段,代码如下:
import scrapy
class JianshuItem(scrapy.Item):
----title = scrapy.Field()
----url = scrapy.Field()
----author_name = scrapy.Field()
class ParticularJianshuItem(JianshuItem):
----time = Field()
网友评论