Scrapy框架(四) 使用Pipeline处理数据(一)
一、Item Pipeline简介
Item Pipeline的主要责任是负责处理爬虫从网页中抽取的Item,它的主要任务是清晰、验证和存储数据。
当页面被爬虫解析后,将被发送到Item管道,并经过几个特定的次序处理数据。
每个初始Item管道的组件都是由一个简单的方法组成的Python类。
如下所示:1
2
3class DemoPipeline(object):
def process_item(self, item, spider):
return item
但是我们没有具体定义,因此执行爬虫并不会输出结果。
他们获取了Item并执行他们的方法,同时他们还需要确定的是是否需要在Item管道中继续执行下一步或是直接丢弃掉不处理。
二、Item管道的通常执行过程
- 清理HTML数据
- 验证解析到的数据(检查Item是否包含必要的字段)
- 检查是否是重复数据(如果重复就删除)
- 将解析到的数据存储到数据库中
三、编写pineline规范
1 | class DemoPipeline(object): |
注意:
在settings.py文件中默认是关闭pipeline管道的。因此如果要使用自定义的管道文件,还需要在settings.py文件中启用pipeline。如果你在pipeline定义了多个管道的类,在settings.py中可以写多个pipeline的类,通过后面的数字的优先级区分哪个先执行。优先级的取值范围为0到1000,数值越小优先级越高。
例如:1
2
3
4
5
6# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'Demo.pipelines.DemoPipeline1': 300,
'Demo.pipelines.DemoPipeline2': 100,
}
上述DemoPipeline2先执行。
四、Item Pipeline例子
4.1 数据清理
1 | # 注:VAT:Value Added Tax(增值税) |
4.2 把Item写入Json文件
还是之前的项目Demo, 我们直接修改 pipelines.py1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 导入Json模块
import json
class DemoPipeline(object):
def __init__(self):
# 生成文件对象
self.fp = open('C:\QzmVc1\Code\PyCharm\Python_Project\Python_Spider\Spider_Test1\Demo\scrapy.json','wb')
def process_item(self,item,spider):
# 将item转换为json格式
data = json.dumps(dict(item),ensure_ascii=False)
# 写入json文件
self.fp.write(data.encode('utf-8'))
return item
def close_spider(self,spider):
# 关闭文件
self.fp.close()
scrapy.json文件内容:
有的时候真的不能只看不练,当自己真正上手写的时候,才会发现自己的基础是那么差,漏洞百出。这里写的时候又碰到N多个坑,慢慢来吧,唉…
我同时也会把这些坑加入到我的这篇博客:Scrapy框架之细数到目前为止我遇到的坑
坑1:json.dumps的参数ensure_ascii=False:
在使用json.dumps时要注意一个问题
1
2
3
4
5
6 import json
print json.dumps('中国')
输出:"\u4e2d\u56fd"
输出的会是
'中国' 中的ascii 字符码,而不是真正的中文。
因为json.dumps 序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False;坑2:中文保存到json文件中产生乱码
如上述代码所示转换为’UTF-8’编码,因为str.encode返回值是一个bytes对象,因此打开文件的方式要写成 ‘wb’ 。
也可以通过在settings.py中添加如下代码:FEED_EXPORT_ENCODING = ‘UTF-8’
4.3 删除重复数据
一个用于去重的过滤器,丢弃那些已经被处理过的item。假设item有一个唯一的id,但是我们spider返回的多个item中包含了相同的id,去重方法如下:这里初始化了一个集合,每次判断id是否在集合中已经存在,从而做到去重的功能。1
2
3
4
5
6
7
8
9
10
11
12
13
14from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
4.4 将数据写入数据库
见下一章
五、激活Item Pipeline组件
在settings.py文件中,往ITEM_PIPELINES中添加项目管道的类名,就可以激活项目管道组件,如:1
2
3
4ITEM_PIPELINES = {
'Demo.pipelines.DemoPipeline1': 300,
'Demo.pipelines.DemoPipeline2': 100,
}
整数值通常设置在0-1000之间,数值越低代表优先级越高。