咱们用解析器解析出数据以后,接下来的一步就是对数据进行存储了,保存的形式能够多种多样,最简单的形式能够直接保存为文本文件,如 TXT、Json、CSV 等等,另外还能够保存到数据库中,如关系型数据库 MySQL,非关系型数据库 MongoDB、Redis 等等。那么本章咱们就来统一了解一下数据的保存方式。javascript
文件存储形式能够是多种多样的,好比能够保存成 TXT 纯文本形式,也能够保存为 Json 格式、CSV 格式等,本节咱们来了解下文本文件的存储方式。html
将数据保存到 TXT 文本的操做很是简单,并且 TXT 文本几乎兼容任何平台,可是有个缺点就是不利于检索,因此若是对检索和数据结构要求不高,追求方便第一的话,能够采用 TXT 文本存储,本节咱们来看下利用 Python 保存 TXT 文本文件的方法。java
本节咱们要保存知乎发现页面的热门问题部分,将其问题和答案统一保存成文本形式。数据库
首先能够用 Requests 将网页源代码获取下来,而后使用 PyQuery 解析库进行解析,接下来将提取的标题、回答者、回答保存到文本,代码以下:json
import requests from pyquery import PyQuery as pq url = 'https://www.zhihu.com/explore' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' } html = requests.get(url, headers=headers).text doc = pq(html) items = doc('.explore-tab .feed-item').items() for item in items: question = item.find('h2').text() author = item.find('.author-link-line').text() answer = pq(item.find('.content').html()).text() file = open('explore.txt', 'a', encoding='utf-8') file.write('\n'.join([question, author, answer])) file.write('\n' + '=' * 50 + '\n') file.close() Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的汇集地,零基础,进阶,都欢迎
在这里主要是为了演示文件保存的方式,所以 Requests 异常处理部分在此省去,咱们首先用 Requests 提取了知乎发现页面,而后将热门问题的问题、回答者、答案全文提取出来,而后利用了Python提供的 open() 方法打开一个文本文件,获取一个文件操做对象,这里赋值为 file,而后利用 file 对象的 write() 方法将提取的内容写入文件,最后记得调用一下 close() 方法将其关闭,这样抓取的内容便可成功写入到文本中了。数组
运行程序,能够发如今本地生成了一个 explore.txt 文件.网络
这样热门问答的内容就被保存文文本形式了。数据结构
在这里 open() 方法的第一个参数即为要保存的目标文件名称,第二个参数为 a,表明以追加方式写入到文本,另外咱们还指定了文件的编码为utf-8,最后写入完成以后,咱们还须要调用 close() 方法来关闭文件对象。ide
在刚才的实例中,第二个参数咱们设置成了 a,这样在每次写入文本时不会清空源文件,而是在文件末尾写入新的内容,这是一种文件打开方式。关于文件打开方式,其实还有另外的几种,在此列举以下:函数
另外文件写入还有一种简写方法,那就是使用 with as 语法,在 with 控制块结束时,文件会自动关闭,因此就不须要再调用 close() 方法了。
因此上面的保存方式咱们能够简写以下:
with open('explore.txt', 'a', encoding='utf-8') as file: file.write('\n'.join([question, author, answer])) file.write('\n' + '=' * 50 + '\n')
若是想保存时将原文清空,那么能够将第二个参数改写为 w,代码以下:
with open('explore.txt', 'w', encoding='utf-8') as file: file.write('\n'.join([question, author, answer])) file.write('\n' + '=' * 50 + '\n')
以上即是利用 Python 将结果保存为 TXT 文件的方法,此种方法简单易用,操做高效,是一种最基本的保存数据的方法。
Json,全称为 JavaScript Object Notation, 也就是 JavaScript 对象标记,经过对象和数组的组合来表示数据,构造简洁可是结构化程度很是高,它是一种轻量级的数据交换格式,本节咱们来了解一下利用 Python 保存数据到 Json 文件的方法。
在 JavaScript 语言中,一切都是对象。所以,任何支持的类型均可以经过 Json 来表示,例如字符串、数字、对象、数组等。可是对象和数组是比较特殊且经常使用的两种类型。
对象,对象在 JavaScript 中是使用花括号 {} 包裹起来的内容,数据结构为 {key1:value1, key2:value2, ...} 的键值对结构。在面向对象的语言中,key 为对象的属性,value 为对应的值。键名可使用整数和字符串来表示。值的类型能够是任意类型。数组,数组在 JavaScript 中是方括号 [] 包裹起来的内容,数据结构为 ["java", "javascript", "vb", ...] 的索引结构。在 JavaScript 中,数组是一种比较特殊的数据类型,它也能够像对象那样使用键值对,但仍是索引使用得多。一样,值的类型能够是任意类型。因此一个 Json 对象能够写为以下形式:
[{ "name": "Bob", "gender": "male", "birthday": "1992-10-18" }, { "name": "Selina", "gender": "female", "birthday": "1995-10-18" }]
由中括号包围的就至关于列表类型,列表的每一个元素能够是任意类型,在示例中它是字典类型,由大括号包围。
Json 能够由以上两种形式自由组合而成,能够无限次嵌套,结构清晰,是数据交换的极佳方式。
Python 为咱们提供了简单易用的 json 库来供咱们实现 Json 文件的读写操做,咱们能够调用 json 库的 loads() 方法将 Json 文本字符串转为 Json 对象,能够经过 dumps()方法将 Json 对象转为文本字符串。
例如在这里有一段 Json 形式的字符串,它是 str 类型,咱们用 Python 将可其转换为可操做的数据结构,如列表或字典。
import json str = ''' [{ "name": "Bob", "gender": "male", "birthday": "1992-10-18" }, { "name": "Selina", "gender": "female", "birthday": "1995-10-18" }] ''' print(type(str)) data = json.loads(str) print(data) print(type(data))
运行结果:
<class 'str'> [{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}] <class 'list'>
在这里咱们使用了 loads() 方法将字符串转为 Json 对象,因为最外层是中括号,因此最终的类型是列表类型。
这样一来咱们就能够用索引来取到对应的内容了,例如咱们想取第一个元素里的 name 属性,就可使用以下方式获取:
data[0]['name'] data[0].get('name')
获得的结果都是:
Bob
经过中括号加 0 索引咱们能够拿到第一个字典元素,而后再调用其键名便可获得相应的键值。在获取键值的时候有两种方式,一种是中括号加键名,另外一种是 get() 方法传入键名。推荐使用 get() 方法来获取内容,这样若是键名不存在的话不会报错,会返回None。另外 get() 方法还能够传入第二个参数即默认值,咱们用一个示例感觉一下:
data[0].get('age') data[0].get('age', 25)
运行结果:
None 25
在这里咱们尝试获取年龄 age,其实在原字典中是不存在该键名的,若是不存在,默认会返回 None,若是传入第二个参数即默认值,那么在不存在的状况下则返回该默认值。
值得注意的是 Json 的数据须要用双引号来包围,不能使用单引号。例如若使用以下形式表示则会出现错误:
import json str = ''' [{ 'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18' }] ''' data = json.loads(str)
运行结果:
json.decoder.JSONDecodeError: Expecting property name enclosed indouble quotes: line 3 column 5 (char 8)
在这里会出现 Json 解析错误的提示,是由于在这里数据用了单括号来包围,请千万注意 Json 字符串的表示须要用双引号,不然 loads() 方法会解析失败。
若是咱们是从 Json 文本中读取内容,例如在这里有一个data.json 文本文件,其内容是刚才咱们所定义的 Json 字符串。
咱们能够先将文本文件内容读出,而后再利用 loads() 方法转化。
import json with open('data.json', 'r') as file: str = file.read() data = json.loads(str) print(data)
运行结果:
[{'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18'}, {'name': 'Selina', 'gender': 'female', 'birthday': '1995-10-18'}]
以上是读取 Json 文件的方法。
另外咱们还能够调用 dumps() 方法来将 Json 对象转化为字符串。
例如咱们将刚上例中的列表从新写入到文本。
import json data = [{ 'name': 'Bob', 'gender': 'male', 'birthday': '1992-10-18' }] with open('data.json', 'w') as file: file.write(json.dumps(data))
利用 dumps() 方法咱们能够将 Json 对象转为字符串,而后再调用文件的 write() 方法便可写入到文本,结果如图 5-2 所示:
图 5-2 写入结果
另外若是咱们想保存 Json 的格式,能够再加一个参数 indent,表明缩进字符个数。
with open('data.json', 'w') as file: file.write(json.dumps(data, indent=2))
写入结果如图 5-3 所示:
[图片上传失败...(image-12c649-1564235008434)]
图 5-3 写入结果
这样获得的内容会自动带有缩进,格式会更加清晰。
另外若是 Json 中包含中文字符,例如咱们将以前的 Json 的部分值改成中文,再用以前的方法写入到文本。
import json data = [{ 'name': '王伟', 'gender': '男', 'birthday': '1992-10-18' }] with open('data.json', 'w') as file: file.write(json.dumps(data, indent=2))
写入结果如图 5-4 所示:
[图片上传失败...(image-42cd95-1564235008433)]
图 5-4 写入结果
能够看到中文字符都变成了 Unicode 字符,这并非咱们想要的结果。
为了输出中文,咱们还须要指定一个参数 ensure_ascii 为 False,另外规定文件输出的编码。
with open('data.json', 'w', encoding='utf-8') as file: file.write(json.dumps(data, indent=2, ensure_ascii=False))
写入结果如图 5-5 所示:
[图片上传失败...(image-e8aeec-1564235008433)]
图 5-5 写入结果
这样咱们就能够输出 Json 为中文了,因此若是字典中带有中文的内容咱们须要设置 ensure_ascii 参数为 False 才可正常写入中文。
本节咱们了解了用 Python 进行 Json 文件读写的方法,在后面作数据解析时常常会用到,建议熟练掌握。
CSV,全称叫作 Comma-Separated Values,中文能够叫作逗号分隔值或字符分隔值,其文件以纯文本形式存储表格数据。该文件是一个字符序列,能够由任意数目的记录组成,记录间以某种换行符分隔,每条记录由字段组成,字段间的分隔符是其它字符或字符串,最多见的是逗号或制表符,不过全部记录都有彻底相同的字段序列,至关于一个结构化表的纯文本形式,它相比 Excel 文件更加简介,XLS 文本是电子表格,它包含了文本、数值、公式和格式等内容,而 CSV 中不包含这些内容,就是特定字符分隔的纯文本,结构简单清晰,因此有时候咱们用 CSV 来保存数据是比较方便的,本节咱们来说解下 Python 读取和写入 CSV 文件的过程。
在这里咱们先看一个最简单的例子:
import csv with open('data.csv', 'w') as csvfile: writer = csv.writer(csvfile) writer.writerow(['id', 'name', 'age']) writer.writerow(['10001', 'Mike', 20]) writer.writerow(['10002', 'Bob', 22]) writer.writerow(['10003', 'Jordan', 21])
首先打开了一个 data.csv 文件,而后指定了打开的模式为 w,即写入,得到文件句柄,随后调用 csv 库的 writer() 方法初始化一个写入对象,传入该句柄,而后调用 writerow() 方法传入每行的数据便可完成写入。
运行结束后会生成一个名为 data.csv 的文件,数据就成功写入了,直接文本形式打开的话内容以下:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21 Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的汇集地,零基础,进阶,都欢迎
能够看到写入的文本默认是以逗号分隔的,调用一次 writerow() 方法便可写入一行数据,咱们用 Excel 打开的结果如图 5-6 所示:
[图片上传失败...(image-2ad0f7-1564235008433)]
图 5-6 打开结果
若是咱们想修改列与列之间的分隔符能够传入 delimiter 参数,代码以下:
import csv with open('data.csv', 'w') as csvfile: writer = csv.writer(csvfile, delimiter=' ') writer.writerow(['id', 'name', 'age']) writer.writerow(['10001', 'Mike', 20]) writer.writerow(['10002', 'Bob', 22]) writer.writerow(['10003', 'Jordan', 21])
例如这里在初始化写入对象的时候传入 delimiter 为空格,这样输出的结果的每一列就是以空格分隔的了,内容以下:
id name age 10001 Mike 20 10002 Bob 22 10003 Jordan 21
另外咱们也能够调用 writerows() 方法同时写入多行,此时参数就须要为二维列表,例如:
import csv with open('data.csv', 'w') as csvfile: writer = csv.writer(csvfile) writer.writerow(['id', 'name', 'age']) writer.writerows([['10001', 'Mike', 20], ['10002', 'Bob', 22], ['10003', 'Jordan', 21]])
输出效果是相同的,内容以下:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21
可是通常状况下爬虫爬取的都是结构化数据,咱们通常会用字典来表示,在 csv 库中也提供了字典的写入方式,实例以下:
import csv with open('data.csv', 'w') as csvfile: fieldnames = ['id', 'name', 'age'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerow({'id': '10001', 'name': 'Mike', 'age': 20}) writer.writerow({'id': '10002', 'name': 'Bob', 'age': 22}) writer.writerow({'id': '10003', 'name': 'Jordan', 'age': 21})
在这里咱们先定义了三个字段,用 fieldnames 表示,而后传给 DictWriter 初始化一个字典写入对象,而后能够先调用 writeheader() 方法先写入头信息,而后再调用 writerow() 方法传入相应字典便可,最终写入的结果是彻底相同的,内容以下:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21
这样咱们就能够完成字典到 CSV 文件的写入了。
另外若是咱们想追加写入的话能够修改文件的打开模式,如将 open() 函数的第二个参数改为 a 就能够变成追加写入,代码以下:
import csv with open('data.csv', 'a') as csvfile: fieldnames = ['id', 'name', 'age'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writerow({'id': '10004', 'name': 'Durant', 'age': 22})
这样在上面的基础上再执行这段代码,文件内容便会变成:
id,name,age 10001,Mike,20 10002,Bob,22 10003,Jordan,21 10004,Durant,22
可见数据被追加写入到了文件中。
若是咱们要写入中文内容的话可能会遇到字符编码的问题,此时咱们须要给 open() 参数指定一个编码格式,好比这里再写入一行包含中文的数据,代码须要改写以下:
import csv with open('data.csv', 'a', encoding='utf-8') as csvfile: fieldnames = ['id', 'name', 'age'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writerow({'id': '10005', 'name': '王伟', 'age': 22})
在这里须要给 open() 函数指定编码,不然可能会发生编码错误。
以上即是 CSV 文件的写入方法。
另外若是咱们接触过 Pandas 等库的话,能够调用 DataFrame 对象的 to_csv() 方法也能够很是方便地将数据写入到 CSV 文件中。
咱们一样可使用 csv 库来读取 CSV 文件,例如咱们如今将刚才写入的文件内容读取出来,代码以下:
import csv with open('data.csv', 'r', encoding='utf-8') as csvfile: reader = csv.reader(csvfile) for row in reader: print(row)
运行结果:
['id', 'name', 'age'] ['10001', 'Mike', '20'] ['10002', 'Bob', '22'] ['10003', 'Jordan', '21'] ['10004', 'Durant', '22'] ['10005', '王伟', '22']
在这里咱们构造的是 Reader 对象,经过遍历输出了每行的内容,每一行都是一个列表形式,注意在这里若是 CSV 文件中包含中文的话须要指定文件编码。
另外若是咱们接触过 Pandas 的话,能够利用 read_csv() 方法将数据从 CSV 中读取出来,例如:
import pandas as pd df = pd.read_csv('data.csv') print(df)
运行结果:
id name age 0 10001 Mike 20 1 10002 Bob 22 2 10003 Jordan 21 3 10004 Durant 22 4 10005 王伟 22 Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的汇集地,零基础,进阶,都欢迎
在作数据分析的时候此种方法用的比较多,也是一种比较方便的读取 CSV 文件的方法。
本节咱们了解了 CSV 文件的写入和读取方式,它也是一种经常使用的数据存储方式,须要熟练掌握。