数据分析4 -- 将爬取的数据保存成CSV格式

什么是 CSV 文件

CSV(Comma-Separated Values) 是一种使用逗号分隔来实现存储表格数据的文本文件。

我们都知道表格有多种形式的存储,比如 Excel 的格式或者数据库的格式。CSV 文件也可以存储表格数据,并且能够被多种软件兼容,比如 Excel 就能直接打开 CSV 文件的表格,很多数据库软件也支持导入 CSV 文件。除了兼容性好之外,CSV 格式还是所有能存储表格的格式中最简单的一种。

下面,我们以一个例子来讲解 CSV 存储表格的原理。

假设有如下员工信息的表格。

数据分析4 -- 将爬取的数据保存成CSV格式_第1张图片

 要存储类似上面的表格,以往我们只能将其输入到 Excel 中并保存为 xlsx 格式,现在我们来尝试将其以 CSV 的格式保存。

打开文本编辑器,如 Windows 下的记事本,新建空白文件。

输入以下内容,并保存为 info.csv (编码选择 ANSI)

姓名,年龄,籍贯,部门
小明,22,河北,IT部
小亮,25,广东,IT部
小E,23,四川,财务部

保存成功后,用 Excel 打开这个文件,可以看到 CSV 文件成功地在 Excel 中展示为表格。

数据分析4 -- 将爬取的数据保存成CSV格式_第2张图片

  • 表格中的一行,对应 CSV 文件中的一行;

  • 一行中不同单元格的内容,在 CSV 文件中用逗号分隔;

  • 务必保证每行的逗号数量是一致的(对应表格中每行的单元格一致)。

在我们后续的数据分析任务中,CSV 文件将会是我们存储数据的主要格式。

Python 的 CSV 模块

熟悉了 CSV 文件的基本概念,今天我们来学习如何使用 Python 来操作 CSV 文件。因为对于数据分析场景而言,最常见的操作就是读取和写入。

从 CSV 文件读取内容

要读取 CSV 文件,就要用到 csv 模块中的 DictReader 类,DictReader 可以将每一行以字典的形式读出来,key 就是表头,value 就是对应单元格的内容。

例如:

1. 通过DictReader 对象的创建以及通过 fileldnames 属性获取了 CSV 表格的表头

import csv

# 通过 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)

输出:

['姓名', '年龄', '籍贯', '部门']

2. 获取表格实际内容

import csv

# 打开 info.csv ,并将文件对象保存在 f 中
with open("info.csv","r",encoding="utf-8") as f:
    # 通过打开 CSV 文件的文件对象作为参数来创建 DictReader 类的对象,存在 reader 变量中
    reader = csv.DictReader(f)
    # 调用 reader 对象的 fieldnames 属性,获取 CSV 文件中表格的表头
    headers = reader.fieldnames

    # 创建列表,用于存储读到的行
    row_list = []
    # 使用遍历循环,直接对 reader 对象进行遍历
    # 每次执行循环时,row 变量都存储了当前行的内容
    for row in reader:
        # 直接将 row 变量添加到行列表中
        row_list.append(row)

# 打印表头的信息
# print(headers)
# 打印第一行的表格数据
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
籍贯: 四川
部门: 财务部

写入 CSV 文件

在之前的例子中,我们写入 CSV 文件是手动写入的,现在我们来试着通过 Python 写入 CSV 文件。

与读取类似,Python 的 csv 模块提供了 DictWriter 方法,使得我们可以将表格数据以字典的形式存在到 CSV 文件中。

import csv

# 打开一个文件,假设是 info2.CSV,因为是写入,所以需要指定模式 "w"
# newline='',在写入 CSV 时,需要指定这个参数,这个记住即可。

with open("info2.CSV", "w", newline='') as f:
    # 将表头存储在一个列表中
    header = ["姓名", "年龄", "籍贯", "部门"]
    # 创建一个 DictWriter 对象,第二个参数就是上面创建的表头
    writer = csv.DictWriter(f, header)
    # 写入表头
    writer.writeheader()
    # 写入一行记录,以字典的形式,key 需要和表头对应。
    writer.writerow({"姓名": "小刚", "年龄":"28", "籍贯":"福建", "部门":"行政部"})

上述代码的关键点就在于,创建了 DictWriter 后,需要首先调用 writeheader 来写入表头,然后再调用 writerow 来写入行。

执行上述代码之后,并不会有内容输出,但是文件夹下会多出一个 Info2.csv, 用Excel 打开后,如下图所示。

数据分析4 -- 将爬取的数据保存成CSV格式_第3张图片

可以看到,我们的表头和记录已经成功写入 CSV 文件中。

DictWriter 除了提供 writerow 方法来将单个字典保存为 CSV 表格中的一行,还提供了 writerows 方法来一次性地保存多行的内容。

import csv

# 打开一个文件,假设是 info2.CSV,因为是写入,所以需要指定模式 "w"
# newline='',在写入 CSV 时,需要指定这个参数,这个记住即可。

with open("info2.CSV", "w", newline='') as f:
    # 将表头存储在一个列表中
    header = ["姓名", "年龄", "籍贯", "部门"]
    # 创建一个 DictWriter 对象,第二个参数就是上面创建的表头
    writer = csv.DictWriter(f, header)
    # 写入表头
    writer.writeheader()
    # 写入一行记录,以字典的形式,key 需要和表头对应。
    writer.writerow({"姓名": "小刚", "年龄":"28", "籍贯":"福建", "部门":"行政部"})

    row_list = [{"姓名": "小hong", "年龄": "26", "籍贯": "山西", "部门": "开发"}]
    # 将小明的记录插入到row_list 中
    row_list.append({"姓名": "小明", "年龄": "26", "籍贯": "香港", "部门": "运维"})
    # 调用 writerows 方法,一次性写多个字典(一个字典列表)到 CSV 文件中
    writer.writerows(row_list)

实现煎蛋新闻列表保存到 CSV 文件中

接下来,我们来将上一篇中过滤出来的新闻列表写入 CSV 文件中。在上一篇中,我们在课程内容中获取了煎蛋的新闻标题。

我们今天的内容就是将每篇新闻的这两个内容保存到 CSV 中,相当于一个新闻就是一行,每一行有两列,一个是新闻标题,一列是发布时间。对应的表头就是:标题、发布时间。

将上一篇中抽取标题的代码整理成四个函数,方便后续调用:

(1)数据准备

第一步,将上一篇中的抽取标题的代码整理成几个函数,方便后续调用:

  1. 打开文件网页,读出内容,并创建对应的 BeautifulSoup 对象;
  2. 找到所有包含新闻的 div 元素列表(class=indexs 的 div);
  3. 从 2 中的 div 元素中抽取出标题;
  4. 从 2 中的 div 元素中抽取出时间。

我们把上述四个操作整理为四个函数。

1. 首先实现创建 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

2. 实现定位包含新闻的 div 元素的列表函数。

# 输入参数是 BeautifulSoup 对象,返回包含新闻的 div 元素列表
def find_index_labels(doc):
    index_labels = doc.find_all("div", class_="indexs")
    return index_labels

3. 实现新闻标题的抽取函数。

# 从第一次 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()

4. 实现获取新闻发布时间的函数。

# 和 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"]

(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()

至此,数据已经成功保存到了csv文件中。

你可能感兴趣的:(玩转Python数据分析,数据分析,python,数据挖掘)