Python 环境加载中…

存下来:csv、json 与 sqlite3

3 道练习题·预计 55 分钟·做对一题解锁下一段

完整通读本章 →

教学 01 / 08· 已读

前言

学到上一章,书店的 120 本书已经能完整地取下来了。可是这些数据,只活在程序运行的那一会儿。程序一结束,它们就全没了,下次想用,还得重新抓一遍。

重新抓一遍有什么不好呢?它不光浪费自己的时间,也在浪费别人网站的资源。所以,爬虫的最后一步是存储:把取到的数据存下来,以后要用,直接读文件就行。

那存成什么呢?实战 5 已经学过 csv 和 json,这一章就把它们用在抓下来的数据上。另外,还要再认识一位新朋友:sqlite3,它是 Python 自带的一个小数据库。数据一多,要按条件筛选、要分组统计的时候,它比 csv 文件好用得多。

很多童鞋一听「数据库」,就觉得很高深。其实 sqlite3 就是一个文件,不用安装,也不用启动什么服务。真正要学的,是一种叫 SQL 的查询语言。不过别担心,这一章只用到其中最常用的四五句,多看几遍就熟了。

学这一章之前,需要先学完 爬虫课第 7 章 ,会从接口取回整个书店的数据。另外,还要熟悉 实战 5 里 csv 和 json 的读写。

目录

这一章会学到:

  • 一、为什么要存下来——别让数据跟着程序一起消失
  • 二、存成 csv 和 json——各有各的用处
  • 三、存进数据库——sqlite3 和建表、插入
  • 四、用 SQL 查数据——筛选、排序、分组统计
  • 五、常见坑
  • 六、自己查一次文档——用字典直接插入
  • 七、小结与回看

学完这一章,你能把抓到的数据存成 csv、json 和 sqlite3 数据库,并用 SQL 从数据库里查出想要的结果。

教学 02 / 08· 已读

一、为什么要存下来

要存数据,先得有数据。咱们先用上一章的办法,从接口取回全部图书。后面几节,都从这一步开始:

Python· 可在网页运行
import time
from urllib.parse import urljoin

import requests

url = 'https://learn-py.org/lab/bookstore/api/page-1.json'
books = []
while url:
    data = requests.get(url).json()
    books.extend(data['books'])
    url = urljoin(url, data['next']) if data['next'] else None
    time.sleep(0.2)
print(len(books))
print(list(books[0].keys()))

输出的结果:

文本
120
['id', 'title', 'author', 'category', 'price', 'rating', 'reviews', 'stock', 'pages', 'year']

一共 120 本书,每本有 10 个字段。数据拿到了,为什么还要特意存下来呢?存下来有这么几个好处:

  • 不用重复抓:分析数据的时候,代码可能要改十几遍。要是每改一次,都重新请求一遍网站,既慢,又打扰别人。
  • 留下证据:网站的数据会变,今天的价格,明天可能就改了。存下来的,就是当时的样子。
  • 交给别的程序用:存成 csv,Excel 就能打开。到了数据分析课,pandas 一行就能把它读进来。

那么,存成什么格式好呢?这要看用途:

格式适合
csv一行一条、每条字段都一样的表格数据;要给 Excel、pandas 用
json有嵌套的数据,比如一本书带着好几条评论;要原样保留数字、None
sqlite3 数据库数据多,经常要按条件筛选、排序、分组统计;要一点一点往里加

下一节,先从学过的 csv 和 json 开始。

教学 03 / 08

二、存成 csv 和 json

先说 csv。每本书的字段都一样,排起来正好是一张表,所以用 csv.DictWriter 存最方便。表头的字段名,直接从第一本书的键里拿。存完以后,再读回来看看:

Python· 可在网页运行
import csv

import requests

books = requests.get('https://learn-py.org/lab/bookstore/api/page-1.json').json()['books']
with open('my_books.csv', 'w', encoding='utf-8', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=list(books[0].keys()))
    writer.writeheader()
    writer.writerows(books)

with open('my_books.csv', encoding='utf-8', newline='') as f:
    rows = list(csv.DictReader(f))
print(len(rows))
print(rows[2])

输出的结果:

文本
20
{'id': '3', 'title': '早起养花', 'author': '林子墨', 'category': '生活', 'price': '56.2', 'rating': '', 'reviews': '0', 'stock': '47', 'pages': '310', 'year': '2014'}

这里只存了第一页的 20 本,好让例子短一点。读回来以后,有两件事要留意,实战 5 都说过:

  • 所有的值都变成了字符串,比如 '56.2' 、'47' ,用的时候要自己转换。
  • 没有评分的 None ,存进 csv 以后,变成了空字符串 '' 。

这两件事,换成 json 就都不是问题了。同样存完再读回来看看:

Python· 可在网页运行
import json

import requests

books = requests.get('https://learn-py.org/lab/bookstore/api/page-1.json').json()['books']
with open('my_books.json', 'w', encoding='utf-8') as f:
    json.dump(books, f, ensure_ascii=False, indent=2)

with open('my_books.json', encoding='utf-8') as f:
    loaded = json.load(f)
print(loaded[2])

输出的结果:

文本
{'id': 3, 'title': '早起养花', 'author': '林子墨', 'category': '生活', 'price': 56.2, 'rating': None, 'reviews': 0, 'stock': 47, 'pages': 310, 'year': 2014}

和 csv 读回来的那一行对比一下:这回数字还是数字,None 也还是 None 。

还有两点要说明。在网页里运行时,这些文件存在浏览器临时准备的地方,刷新页面就没了。在自己电脑上运行,它们就存在代码文件的旁边。另外,要是 csv 是给 Excel 打开的,记得把编码换成 'utf-8-sig' 。

下面先做一道练习,把一页书存进 csv,再读回来数一数。

练习 1 / 3存一页书到 csv题目有问题?

取回接口 https://learn-py.org/lab/bookstore/api/page-2.json 里的 20 本书,每本只留 id 、title 、price 、stock 四个字段,用 csv.DictWriter 存进 page2.csv 。再把文件读回来,打印一共几行、缺货(stock 为 0)的有几本。

注意:读回来的值都是字符串。

运行后的输出应该是:

文本
20 行,缺货 2 本
main.py
可编辑
做对当前题解锁下一段 ·03

推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai

学习目录