今天我们来了解一下在数据分析领域最为常见一种文件格式:CSV 文件,然后我们再将上一篇文章案例中抓取到的数据保存到 CSV 文件中。
1、什么是CSV文件?
CSV(Comma-Separated Values) 是一种使用逗号分隔来实现存储表格数据的文本文件。
我们都知道表格有多种形式的存储,比如 Excel 的格式或者数据库的格式。CSV 文件也可以存储表格数据,并且能够被多种软件兼容,比如 Excel 就能直接打开 CSV 文件的表格,很多数据库软件也支持导入 CSV 文件。除了兼容性好之外,CSV 格式还是所有能存储表格的格式中最简单的一种。
比如我们新建一个文件,名称改为:info.csv,在文件中输入以下数据:
姓名,年龄,籍贯,部门
小明,22,河北,IT部
小亮,25,广东,IT部
小E,23,四川,财务部
保存成功后,我们使用excel打开这个csv文件,可以看到:
打开后的展示样式与excel基本一样,在这里,我们需要注意csv文件的一些事项:
- 表格中的一行,对应 CSV 文件中的一行;
- 一行中不同单元格的内容,在 CSV 文件中用逗号分隔;
- 务必保证每行的逗号数量是一致的(对应表格中每行的单元格一致)。
在了解csv的格式后,下面我们再来看一下Python中关于csv的模块。
2、Python中的csv模块
了解了 CSV 文件的基本概念,今天我们来看如何使用 Python 来操作 CSV 文件。因为对于数据分析场景而言,最常见的操作就是读取和写入。
(1)从csv文件中读取内容
现在我们来读取上面的info.csv文件内容。
现在VS CODE 中新建一个cell,导入csv模块
import csv
要读取 CSV 文件,我们需要用到 CSV 模块中的 DictReader 类,DictReader 可以将每一行以字典的形式读出来,key 就是表头,value 就是对应单元格的内容。代码如下:
# 通过 open 函数打开 info.csv ,并将文件对象保存在 fo 中
fo = open("info.csv ")
# 通过打开 CSV 文件的文件对象作为参数来创建 DictReader 类的对象,存在 reader 变量中
reader = CSV.DictReader(fo)
# 调用 reader 对象的 fieldnames 属性,获取 CSV 文件中表格的表头
headers = reader.fieldnames
# 关闭文件
fo.close()
# 打印表头的信息
print(headers)
输出如下:
['姓名', '年龄', '籍贯', '部门']
接下来,我们尝试获取表格的实际内容。
# 打开 info.csv
fo = open("info.csv ")
# 创建 DictReader 对象
reader = CSV.DictReader(fo)
# 创建列表,用于存储读到的行
row_list = []
# 使用遍历循环,直接对 reader 对象进行遍历
# 每次执行循环时,row 变量都存储了当前行的内容
for row in reader:
# 直接将 row 变量添加到行列表中
row_list.append(row)
# 关闭文件
fo.close()
# 打印第一行的表格数据
print(row_list[0])
打印的结果显示:
{'姓名': '小明', '年龄': '22', '籍贯': '河北', '部门': 'IT部'}
可以看到,我们拿到了第一行的内容,并且是以字典的形式,字典把每个单元格的内容和表头联系了起来,表头是 key,而具体内容就是 value。每行都是这样的一个字典,所有字典都存储在 row_list 列表中。
接下来,我们来演示对于 row_list 列表的常见操作:打印某一行、某一列的值。
print("打印年龄一列的内容:")
# 遍历循环 row_list,d 为循环变量
for d in row_list:
# 因为 d 是字典,直接打印 key 为 年龄的值即可。
print(d["年龄"])
# 打印一个换行
print("")
print("打印第三行的内容:")
d = row_list[2]
print("姓名:", d["姓名"])
print("年龄:",d["年龄"])
print("籍贯:",d["籍贯"])
print("部门:",d["部门"])
输出如下:
打印年龄一列的内容
22
25
23
打印第三行的内容
姓名: 小E
年龄: 23
籍贯: 四川
部门: 财务部
(2)写入csv文件
与读取类似,Python 的 CSV 模块提供了 DictWriter 方法,使得我们可以将表格数据以字典的形式存在到 CSV 文件中。
具体用法如下:
# 打开一个文件,假设是 info2.CSV,因为是写入,所以需要指定模式 "w"
# newline='',在写入 CSV 时,需要指定这个参数,这个记住即可。
fo = open("info2.CSV", "w", newline='')
# 将表头存储在一个列表中
header = ["姓名", "年龄", "籍贯", "部门"]
# 创建一个 DictWriter 对象,第二个参数就是上面创建的表头
writer = CSV.DictWriter(fo, header)
# 写入表头
writer.writeheader()
# 写入一行记录,以字典的形式,key 需要和表头对应。
writer.writerow({"姓名": "小刚", "年龄":"28", "籍贯":"福建", "部门":"行政部"})
# 关闭写入的文件
fo.close()
上述代码的关键点就在于,创建了 DictWriter 后,需要首先调用 writeheader 来写入表头,然后再调用 writerow 来写入行。
执行上述代码之后,并不会有内容输出,但是 源代码文件夹下会多出一个 Info2.csv, 用Excel 打开后,如下图所示。
可以看到,我们的表头和记录已经成功写入 CSV 文件中。
DictWriter 除了提供 writerow 方法来将单个字典保存为 CSV 表格中的一行,还提供了 writerows 方法来一次性地保存多行的内容。
现在我们尝试使用 writerow 方法来一次性写入多条记录。将我们手工建的 CSV 表格的内容存储在 row_list 变量中的数据一起写入新文件中。代码如下:
# 新打开一个 info3.CSV 文件
fo = open("info3.CSV", "w", newline='')
# 将表头存储在一个列表中
header = ["姓名", "年龄", "籍贯", "部门"]
# 创建一个 DictWriter 对象,第二个参数就是上面创建的表头
writer = CSV.DictWriter(fo, header)
# 将小刚的记录插入到row_list 中
row_list.append({"姓名": "小刚", "年龄":"28", "籍贯":"福建", "部门":"行政部"})
# 写表头
writer.writeheader()
# 调用 writerows 方法,一次性写多个字典(一个字典列表)到 CSV 文件中
writer.writerows(row_list)
# 关闭文件
fo.close()
执行完毕后,源代码文件夹下生成了新的 info3.csv,打开后如下图所示,包含了一开始的三条记录,以及我们插入的“小刚”的记录。
3、实现新闻标题保存到csv中
接下来,我们来将上一讲中过滤出来的新闻列表写入 CSV 文件中。
(1)数据准备
我们将前面下载的jandan.html文件复制到本源码文件夹下,再将之前获取新闻标题的代码整理成几个函数,方便调用。
①创建 BeautifulSoup 对象的函数。
from bs4 import BeautifulSoup
# 输入参数为要分析的 html 文件名,返回值为对应的 BeautifulSoup 对象
def create_doc_from_filename(filename):
fo = open(filename, "r", encoding='utf-8')
html_content = fo.read()
fo.close()
doc = BeautifulSoup(html_content)
return doc
②实现定位包含新闻的 div 元素的列表函数。
# 输入参数是 BeautifulSoup 对象,返回包含新闻的 div 元素列表
def find_index_labels(doc):
index_labels = doc.find_all("div", class_="indexs")
return index_labels
③实现新闻标题的抽取函数。
# 从第一次 find_all 获取的标签对象中抽取标题
def get_title(label_object):
# 从刚才的参数传入的标签对象中过滤出所有 target=_blank 的 a 标签
a_labels = label_object.find_all("a",target="_blank")
# 取第一个标签对象
my_label = a_labels[0]
# 将标签的文字内容作为返回值返回
return my_label.get_text()
④实现获取新闻发布时间的函数
# 和 get_title 函数一样,传入 label_object, 返回发布时间
def get_pub_time(label_object):
# 找到 class=comment-link 的 span 标签
spans = label_object.find_all("span", class_="comment-link")
# 取第一个
span = spans[0]
# 返回标题属性
return span["title"]
至此,我们四个基础函数已经准备好了,以上的 Cell 都需要注意执行,这样我们接下来才可以使用这些函数。
(2)获取文章标题
接下来,我们开始使用上面的函数来获得新闻的标题与新闻列表。
# 调用 create_doc_from_filename 函数,创建 BeautifulSoup 对象
doc = create_doc_from_filename("jiandan.html")
# 调用find_index_labels 函数,传入 BeautifulSoup 对象
# 将返回的 div 列表存储在 index_labels 中
index_labels = find_index_labels(doc)
# 使用遍历循环遍历 index_labels 列表,循环变量为 label_object
for label_object in index_labels:
# 调用 get_title, 传入当前处理的 div 元素对象,获取标题
title = get_title(label_object)
# 调用 get_pub_time,传入当前处理的 div 元素对象,获取发布时间
pub_time = get_pub_time(label_object)
# 将标题和发布时间打印出来
print("标题:", title)
print("发布时间:", pub_time)
上述代码把我们刚才准备的四个函数都串了起来。大概的思路就是首先创建 BeautifulSoup 对象,之后针对该对象查询 class = indexs 的列表,然后使用遍历循环遍历该列表,对于每一个 div 元素,分别调用 get_title 以及 get_pub_time 函数来获得标题与发布时间。
执行上述代码后,输出如下所示。可以看到,我们的新闻标题和时间都已经被成功打印了出来。
标题: 引发普通感冒的鼻病毒会将新冠病毒排挤出细胞!
发布时间: 1小时 ago
标题: 无厘头研究:植入虚假的记忆再抹去它们
发布时间: 4小时 ago
标题: 什么是仇恨犯罪?
发布时间: 8小时 ago
标题: 突发:LHCb发现了违背标准模型的现象
发布时间: 12小时 ago
标题: 今日带货 20210324
发布时间: 14小时 ago
标题: 舌战裸猿:IBM搞出了可以打辩论赛的AI
发布时间: 23小时 ago
标题: 大吐槽:「我没醉,醉的是世界」
发布时间: 1天 ago
标题: 今年世界总发电量的0.6%被用于挖比特币
发布时间: 1天 ago
标题: 接种疫苗后还是感染新冠?不要为此惊讶
发布时间: 1天 ago
标题: 今日带货:蛋友家的血橙
发布时间: 2天 ago
标题: 科学家首次在野外检测到抗多药的超级真菌
发布时间: 2天 ago
标题: 未在iPhone12盒中搭配充电器,苹果被巴西消协罚200万美元
发布时间: 2天 ago
标题: 工程师将解决城市陷坑的问题
发布时间: 2天 ago
标题: 今日带货:粉面专场
发布时间: 3天 ago
标题: 科学家在碟子里培育出了泪腺,并让它哭泣
发布时间: 3天 ago
标题: 疯狂实验进行时:把志愿者禁闭在黑暗的空间里40天
发布时间: 3天 ago
标题: 今日带货 20210321
发布时间: 4天 ago
标题: 我们已向外星人发送了哪些消息?
发布时间: 4天 ago
标题: 脑力小体操:石头+剪刀 VS 石头+布
发布时间: 4天 ago
标题: 发霉啦:今天,我终于向母亲摊牌了
发布时间: 5天 ago
标题: 普渡大学的经济学家计算出世界各地幸福的价格
发布时间: 5天 ago
标题: 人类首次观察到木星上极光黎明风暴的成形过程
发布时间: 5天 ago
标题: 为女儿出头,母亲编辑假裸照败坏高中啦啦队队员的名誉
发布时间: 5天 ago
标题: 今日带货:淘宝京东蛋友推荐
发布时间: 6天 ago
(3)将数据存储为字典形式
要存储到 CSV,首先我们需要将我们的数据创建为字典的形式,我们可以在(2)的循环中将标题和时间存储为字典,然后使用一个字典列表来存储每个新闻对应的字典。最后直接使用 DictWriter 的 writerows 方法来将字典列表写入 CSV 文件即可。
我们直接修改刚才打印标题和发布时间的 Cell,删除原本的打印代码,并添加字典相关操作的代码。
# 调用 create_doc_from_filename 函数,创建 BeautifulSoup 对象
doc = create_doc_from_filename("jiandan.html")
# 调用find_index_labels 函数,传入 BeautifulSoup 对象
# 将返回的 div 列表存储在 index_labels 中
index_labels = find_index_labels(doc)
# 【新增代码】存储新闻的字典列表
news_dict_list = []
# 使用遍历循环遍历 index_labels 列表,循环变量为 label_object
for label_object in index_labels:
# 调用 get_title, 传入当前处理的 div 元素对象,获取标题
title = get_title(label_object)
# 调用 get_pub_time,传入当前处理的 div 元素对象,获取发布时间
pub_time = get_pub_time(label_object)
# 【新增代码】创建单条新闻的字典
news = {"标题": title, "发布时间": pub_time}
# 【新增代码】将新闻字典添加到字典列表
news_dict_list.append(news)
# 【新增代码】打印出字典列表
print(news_dict_list)
通过循环,我们将新闻以字典的形式逐个添加到了字典列表中,然后在最后打印出列表,输出如下所示。
[{'标题': '引发普通感冒的鼻病毒会将新冠病毒排挤出细胞!', '发布时间': '1小时 ago'}, {'标题': '无厘头研究:植入虚假的记忆再抹去它们', '发布时间': '4小时 ago'}, {'标题': '什么是仇恨犯罪?', '发布时间': '8小时 ago'}, {'标题': '突发:LHCb发现了违背标准模型的现象', '发布时间': '12小时 ago'}, {'标题': '今日带货 20210324', '发布时间': '14小时 ago'}, {'标题': '舌战裸猿:IBM搞出了可以打辩论赛的AI', '发布时间': '23小时 ago'}, {'标题': '大吐槽:「我没醉,醉的是世界」', '发布时间': '1天 ago'}, {'标题': '今年世界总发电量的0.6%被用于挖比特币', '发布时间': '1天 ago'}, {'标题': '接种疫苗后还是感染新冠?不要为此惊讶', '发布时间': '1天 ago'}, {'标题': '今日带货:蛋友家的血橙', '发布时间': '2天 ago'}, {'标题': '科学家首次在野外检测到抗多药的超级真菌', '发布时间': '2天 ago'}, {'标题': '未在iPhone12盒中搭配充电器,苹果被巴西消协罚200万美元', '发布时间': '2天 ago'}, {'标题': '工程师将解决城市陷坑的问题', '发布时间': '2天 ago'}, {'标题': '今日带货:粉面专场', '发布时间': '3天 ago'}, {'标题': '科学家在碟子里培育出了泪腺,并让它哭泣', '发布时间': '3天 ago'}, {'标题': '疯狂实验进行时:把志愿者禁闭在黑暗的空间里40天', '发布时间': '3天 ago'}, {'标题': '今日带货 20210321', '发布时间': '4天 ago'}, {'标题': '我们已向外星人发送了哪些消息?', '发布时间': '4天 ago'}, {'标题': '脑力小体操:石头+剪刀 VS 石头+布', '发布时间': '4天 ago'}, {'标题': '发霉啦:今天,我终于向母亲摊牌了', '发布时间': '5天 ago'}, {'标题': '普渡大学的经济学家计算出世界各地幸福的价格', '发布时间': '5天 ago'}, {'标题': '人类首次观察到木星上极光黎明风暴的成形过程', '发布时间': '5天 ago'}, {'标题': '为女儿出头,母亲编辑假裸照败坏高中啦啦队队员的名誉', '发布时间': '5天 ago'}, {'标题': '今日带货:淘宝京东蛋友推荐', '发布时间': '6天 ago'}]
(4)存储到csv文件中
现在,我们已经将网页中抓取到的数据都保存在一个字典列表中:news_dict_list ,接下来就是将这个列表写入到 CSV 文件中即可。 代码如下:
# 创建 news.CSV 文件
fo = open("news.CSV", "w", newline='', encoding='utf_8_sig')
# 这一次的表头
header = ["标题", "发布时间"]
# 使用文件对象和表头初始化 DictWriter 对象
writer = CSV.DictWriter(fo, header)
# 写入表头
writer.writeheader()
# 将上一步计算的字典列表写入 CSV 文件中
writer.writerows(news_dict_list)
# 关闭文件对象
fo.close()
执行之后,在源代码文件夹下会生成 news.CSV 文件,用 Excel 打开后如下图所示。可以看到,我们的数据已经成功以表格的形式呈现了。