scrapy深入
一、Item数据结构
Item是保存爬取数据的容器,它的使用方法和字典类似。不过,相比字典, Item提供了额外的保护机制,可以避免拼写错误或者定义
字段错误。
创建Item需要继承scrapy.Item类,并且定义类型为scrapy.Field的字段。在创建项目开始的时候Item文件是这样的。
import scrapy
class TutorialItem(scrapy.Item):
# define the fields for your item here like:
# 参照下面这个参数定义你的字段
# name = scrapy.Field()
pass
在保存数据的时候可以每次初始化一个字典等格式,但是最方便,最好的保存方式就是使用 Scrapy 自带的 Item 数据结构了。
我们学习了从页面中提取数据的方法,接下来学习如何封装爬取到的数据。应该用怎样的数据结构来维护这些零散的信息字段呢?最容易想到是使用Python字典(dict)。
回顾之前的代码
class QuotesSpider(scrapy.Spider):
name = 'quotes'
allowed_domains = ['toscrape.com']
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
quotes = response.css('.quote')
for quote in quotes:
text = quote.css('.text::text').get()
author = quote.css('.author::text').get()
tags = quote.css('.tag::text').getall()
yield {
'text': text,
'author': author,
'tags': tags,
}
在该案例中,我们便使用了Python字典存储一条数据的信息,但字典可能有以下缺点:
(1)无法一目了然地了解数据中包含哪些字段,影响代码可读性。
(2)缺乏对字段名字的检测,容易因程序员的笔误而出错。
(3)不便于携带元数据(传递给其他组件的信息)。
为解决上述问题,在Scrapy中可以使用自定义的Item类封装爬取到的数据。
1. Item和Field
Scrapy提供了以下两个类,用户可以使用它们自定义数据类(如书籍信息),封装爬取到的数据:
1. Item基类
数据结构的基类,在items.py中定义数据结构时,需要继承自该基类。
2. Field类
用来描述自定义数据类包含哪些字段(如name、price等)。
自定义一个数据类,只需继承Item,并创建一系列Field对象的类属性即可。
以定义书籍信息 quote 为例,它包含个字段,分别为书的名字text、author和tags,代码如下:
# 特殊的字典结构 可以在scrapy中传递数据
class TutorialItem(scrapy.Item):
# Field 字段
# 就是类似于产生一个类似字典格式的数据 拥有字典的一些属性
# 字段默认为空
# 我们可以通过实例化 像着键赋值 但是如果没有写这个键 就不能赋值 但是字典可以
text = scrapy.Field()
author = scrapy.Field()
tags = scrapy.Field()
Item支持字典接口,因此 TutorialItem 在使用上和Python字典类似。
对字段进行赋值时,TutorialItem 内部会对字段名进行检测,如果赋值一个没有定义的字段,就会抛出异常(防止因用户粗心而导致错误)
2. 多个item处理
from NcepuSpider.items import ArticleViewsCountItem
from NcepuSpider.items import ArticleBodyItem
from NcepuSpider.items import NcepuNewsSpiderItem
def process_item(self, item, spider):
# 使用isinstance然后通过if判断方式进行items类别筛选
# 写入json文件
if isinstance(item, ArticleViewsCountItem):
pass
elif isinstance(item, ArticleBodyItem):
pass
elif isinstance(item, NcepuNewsSpiderItem):
pass
return item
二、Item Pipeline
当 spider 获取到数据(item)之后,就会将数据发送到 ItemPipeline,Item Pipeline 通过顺序执行的几个组件处理它。
在Scrapy中,Item Pipeline是处理数据的组件,一个Item Pipeline就是一个包含特定接口的类,通常只负责一种功能的数据
处理,在一个项目中可以同时启用多个Item Pipeline,它们按指定次序级联起来,形成一条数据处理流水线。
Item Pipeline 的典型用途是:
- 清理HTML数据
- 验证的数据(检查项目是否包含某些字段)
- 进行数据的保存
1. Item Pipeline 使用
Scrapy 提供了 pipeline 模块来执行保存数据的操作。在创建的 Scrapy 项目中自动创建了一个 pipeline.py 文件,同时创建了一个默认的 Pipeline 类:
class TutorialPipeline(object):
def process_item(self, item, spider):
return item
在这个类中,有个方法叫 process_item() 方法,每个 Pipeline 都需要调用该方法。
process_item() 方法必须返回一个字典数据。默认有两个参数。如果把 Item 删除了那就不会再调用其他 Pipeline 方法了。
参数:
- item ( Item 对象 dict)
- spider (Spider 对象)
既然有了数据,那么就可以保存了:
class Qd03EnglishPipeline:
def process_item(self, item, spider):
print('item_info_2', item)
with open('english.csv', mode='a', encoding='utf-8') as f:
f.write(item['title'] + ',' + item['info'] + ',' + item['img_url'])
f.write('\n')
return item
2. 启用 Item Pipeline组件
只是上面定义方法还不行,还要激活该组件,也就是激活管道文件才能保存数据。激活是在配置文件setteings.py文件中激活,在
配置文件中找到如下变量值取消注释:
ITEM_PIPELINES = {
'qd_03_english.pipelines.Qd03EnglishPipeline':300,
}
重点:
在上图中的字典结构的配置中,键是管道文件所在的路径,值是该管道文件的激活顺序,数字越小代表越早激活 。因为有时候会有多个管道文件。
完整的 item pipeline
import something
class SomethingPipeline(object):
def __init__(self):
## 可选实现,做参数初始化等
## doing something
pass
def open_spider(self, spider):
## spider (Spider 对象) – 被开启的spider
## 可选实现,当spider被开启时,这个方法被调用。
pass
def process_item(self, item, spider):
## item (Item 对象) – 被爬取的item
## spider (Spider 对象) – 爬取该item的spider
## 这个方法必须实现,每个item pipeline 组件都需要调用该方法,
## 这个方法必须返回一个 Item 对象,被丢弃的item将不会被之后的pipeline组件所处理。
return item
def close_spider(self, spider):
## spider (Spider 对象) – 被关闭的spider
## 可选实现,当spider被关闭时,这个方法被调用
pass
写入JSON文件
class JSONPipeline:
def __init__(self):
self.f = open('data.json'