--------------------------------------- | ----------------- | ----------------- |
| 冬酒暖阳 | mailto:1067764354@qq.com | 博客:www.lifepoem.cn |

序言

在 Scrapy 中保存 json 文件有以下 3 种方式:

  1. 直接创建并写入 json 文件,将数据写入其中
  2. 使用 Scrapy.exporters 中自带的 JsonItemExporter进行导出操作
  3. 使用 Scrapy.exporters 中自带的 JsonLinesItemExporter进行导出操作

但,Scrapy 框架提供的这两个 json 导出模块,均 存在各自的问题

  1. JsonItemExporter

    必须先将爬虫爬取下来的 所有数据存放在内存 中,待爬虫完成后,再一次性写入文件。

    这种方式,可以输出标准的 json 格式文件,但是如果数据量巨大,会 大量占用内存

  2. JsonLinesItemExporter

    这种方式,每次拿到数据都直接写入文件,占用内存少,但是输出的结果 并不是标准的 Json 格式文件 ,无法通过 Json 将文件内容解析出来。


于是,下面首先介绍,第一种方式,直接创建并将数据写入 json 文件,

一、直接创建并写入 json 文件

  1. 在 Scrapy 框架的 pipeline 写入如下内容

    import os
    import codecs
    import json
    
    
    class SpiderPipeline(object):
        # 构造方法(初始化对象时执行的方法)
        def __init__(self):
            # 必须使用 w+ 模式打开文件,以便后续进行 读写操作(w+模式,意味既可读,亦可写)
            # 注意:此处打开文件使用的不是 python 的 open 方法,而是 codecs 中的 open 方法
            self.json_file = codecs.open('data.json', 'w+', encoding='UTF-8')
    
        # 爬虫开始时执行的方法
        def open_spider(self, spider):
            # 在爬虫开始时,首先写入一个 '[' 符号,构造一个 json 数组
            # 为使得 Json 文件具有更高的易读性,我们辅助输出了 '\n'(换行符)
            self.json_file.write('[\n')
    
        # 爬虫 pipeline 接收到 Scrapy 引擎发来的 item 数据时,执行的方法
        def process_item(self, item, spider):
            # 将 item 转换为 字典类型,并编码为 json 字符串,写入文件
            # 为使得 Json 文件具有更高的易读性,我们辅助输出了 '\t'(制表符) 与 '\n'(换行符)
            item_json = json.dumps(dict(item), ensure_ascii=False)
            self.json_file.write('\t' + item_json + ',\n')
            return item
    
        # 爬虫结束时执行的方法
        def close_spider(self, spider):
            # 在结束后,需要对 process_item 最后一次执行输出的 “逗号” 去除
            # 当前文件指针处于文件尾,我们需要首先使用 SEEK 方法,定位到文件尾前的两个字符(一个','(逗号), 一个'\n'(换行符))的位置
            self.json_file.seek(-2, os.SEEK_END)
            # 使用 truncate() 方法,将后面的数据清空
            self.json_file.truncate()
            # 重新输出'\n',并输出']',与 open_spider(self, spider) 时输出的 '[' 相对应,构成一个完整的数组格式
            self.json_file.write('\n]')
            # 关闭文件
            self.json_file.close()
    
  2. 输出示例

    [
    	{"title": "用户拒绝授权小程序使用通讯地址API的问题和解决方法", "author_nickName": "KOSS", "content": "小程序中正确使用通讯地址这个开发接口的流程:思路:"},
    	{"title": "房产小程序开发", "author_nickName": "Right Here Waiting", "content": "房产小程序:任何关于楼盘价格问题、户型问题、周边设施问题都可以小程序上直接沟通。房产小程序可以很好的帮助哪些懒人解决看房问题,楼盘价格及周边设施都可以详细的展示,用户也可以直接在小程序上面预约,然后在实地看房。"}
    ]
    

二、使用 JsonItemExporter 写入 Json 文件

  1. 在 Scrapy 框架的 pipeline 写入如下内容

    # 导入 JsonItemExporter
    from scrapy.exporters import JsonItemExporter
    
    
    class SpiderPipeline(object):
        # 构造方法(初始化对象时执行的方法)
        def __init__(self):
            # 使用 'wb' (二进制写模式)模式打开文件
            self.json_file = open('data.json', 'wb')
            # 构建 JsonItemExporter 对象,设定不使用 ASCII 编码,并指定编码格式为 'UTF-8'
            self.json_exporter = JsonItemExporter(self.json_file, ensure_ascii=False, encoding='UTF-8')
            # 声明 exporting 过程 开始,这一句也可以放在 open_spider() 方法中执行。
            self.json_exporter.start_exporting()
    
        # 爬虫 pipeline 接收到 Scrapy 引擎发来的 item 数据时,执行的方法
        def process_item(self, item, spider):
            # 将 item 存储到内存中
            self.json_exporter.export_item(item)
            return item
    
        def close_spider(self, spider):
            # 声明 exporting 过程 结束,结束后,JsonItemExporter 会将收集存放在内存中的所有数据统一写入文件中
            self.json_exporter.finish_exporting()
            # 关闭文件
            self.json_file.close()
    
  2. 输出示例

    [{"title": "用户拒绝授权小程序使用通讯地址API的问题和解决方法", "author_nickName": "KOSS", "content": "小程序中正确使用通讯地址这个开发接口的流程:思路:"},{"title": "房产小程序开发", "author_nickName": "Right Here Waiting", "content": "房产小程序:任何关于楼盘价格问题、户型问题、周边设施问题都可以小程序上直接沟通。房产小程序可以很好的帮助哪些懒人解决看房问题,楼盘价格及周边设施都可以详细的展示,用户也可以直接在小程序上面预约,然后在实地看房。"}]
    

二、使用 JsonLinesItemExporter 写入 json 文件

  1. 在 Scrapy 框架的 pipeline 写入如下内容

    # 导入 JsonLinesItemExporter
    from scrapy.exporters import JsonLinesItemExporter
    
    
    class SpiderPipeline(object):
        # 构造方法(初始化对象时执行的方法)
        def __init__(self):
            # 使用 'wb' (二进制写模式)模式打开文件
            self.json_file = open('data.json', 'wb')
            # 构建 JsonLinesItemExporter 对象,设定不使用 ASCII 编码,并指定编码格式为 'UTF-8'
            self.json_exporter = JsonLinesItemExporter(self.json_file, ensure_ascii=False, encoding='UTF-8')
            # 声明 exporting 过程 开始,这一句也可以放在 open_spider() 方法中执行。
            self.json_exporter.start_exporting()
    
        # 爬虫 pipeline 接收到 Scrapy 引擎发来的 item 数据时,执行的方法
        def process_item(self, item, spider):
            # 将 item 直接写入文件中
            self.json_exporter.export_item(item)
            return item
    
        def close_spider(self, spider):
            # 声明 exporting 过程 结束,结束后,JsonItemExporter 会将收集存放在内存中的所有数据统一写入文件中
            self.json_exporter.finish_exporting()
            # 关闭文件
            self.json_file.close()
    
  2. 输出示例

    {"title": "用户拒绝授权小程序使用通讯地址API的问题和解决方法", "author_nickName": "KOSS", "content": "小程序中正确使用通讯地址这个开发接口的流程:思路:"}
    {"title": "房产小程序开发", "author_nickName": "Right Here Waiting", "content": "房产小程序:任何关于楼盘价格问题、户型问题、周边设施问题都可以小程序上直接沟通。房产小程序可以很好的帮助哪些懒人解决看房问题,楼盘价格及周边设施都可以详细的展示,用户也可以直接在小程序上面预约,然后在实地看房。"}
    

三、三种方式对比

序号方式内存占用情况是否为标准 json 格式易读性
1直接创建并写入文件
2JsonItemExporter
3JsonLinesItemExporter较低