上一节我们已经知道,pipeline可以拦截我们的Item,故而数据的保存通过pipeline实现。
我们先实现数据的json格式保存,在pipelines.py中:
import codecs
import json
class JsonSavePipeline(object):
"""
json文件的导出
"""
def __init__(self):
self.file = codecs.open('article.json', 'w', encoding="utf-8")
def process_item(self, item, spider):
lines = json.dumps(dict(item), ensure_ascii=False) + "\n"
self.file.write(lines)
return item
def close_spider(self, spider):
self.file.close()
其中,process_item是主要的处理函数,item需要在此return,以供下一个pipeline使用;close_spider是scrapy的一个信号量,当spider停止时会被调用。
在ITEM_PIPELINES中配置这个pipeline:
ITEM_PIPELINES = {
'Spider.pipelines.SpiderPipeline': 300,
# 'scrapy.pipelines.images.ImagesPipeline': 200,
'Spider.pipelines.ArticleImagesPipeline': 200,
'Spider.pipelines.JsonSavePipeline': 210,
}
启动,发现多了一个article.json文件,内容为:
实际上,scrapy为我们提供了多种格式数据的exporter,我们先以JSON格式为例,在pipelines.py中,引入:
from scrapy.exporters import JsonItemExporter
跟踪到exporters.py文件中,发现提供了一下几种格式的Exporter:
__all__ = ['BaseItemExporter', 'PprintItemExporter', 'PickleItemExporter',
'CsvItemExporter', 'XmlItemExporter', 'JsonLinesItemExporter',
'JsonItemExporter', 'MarshalItemExporter']
为了实现使用scrapy提供的Exporter实现数据的导出,在pipelines.py中自定义一个pipeline:
class JsonExporterPipleline(object):
"""
调用scrapy提供的JsonExporter导出json文件
"""
def __init__(self):
self.file = open('article-exporter.json', 'wb')
self.exporter = JsonItemExporter(self.file, encoding="utf-8", ensure_ascii=False)
self.exporter.start_exporting()
def close_spider(self, spider):
self.exporter.finish_exporting()
self.file.close()
def process_item(self, item, spider):
self.exporter.export_item(item)
return item
实际上,都是在调用JsonItemExporter对象的方法。注意,这里不是继承了JsonItemExporter,而是生成它的实例并使用它的方法。
在ITEM_PIPELINES中配置它:
ITEM_PIPELINES = {
'Spider.pipelines.SpiderPipeline': 300,
# 'scrapy.pipelines.images.ImagesPipeline': 200,
'Spider.pipelines.ArticleImagesPipeline': 200,
'Spider.pipelines.JsonSavePipeline': 210,
'Spider.pipelines.JsonExporterPipleline': 220,
}
删除图片和刚刚生成的article.json文件,再次启动项目。
发现都没有问题,只是通过JsonExporter输出的json文件,被放在了一个数组中,这更符合常理,此外每个json对象之间都有一个逗号分隔,这实际上都是我们调用的JsonExporter对象的方法中进行的:
我们可以借鉴着JsonExporter,完善我们自定义的JsonSavePipeline:
class JsonSavePipeline(object):
"""
自定义json文件的导出
"""
def __init__(self):
self.file = codecs.open('article.json', 'w', encoding="utf-8")
self.first_item = True
self.file.write("[")
def process_item(self, item, spider):
if self.first_item:
self.first_item = False
else:
self.file.write(', ')
lines = json.dumps(dict(item), ensure_ascii=False)
self.file.write(lines)
return item
def close_spider(self, spider):
self.file.write("]\n")
self.file.close()
需要说明的是,这是json格式,是很简单的,其他一些格式的数据需要考虑的东西更多,此时使用scrapy提供的JsonExporter的优势就很明显了。