Day 36:【99天精通Python】综合实战 - 爬虫与数据分析可视化(下) - 让数据"说话"
前言
欢迎来到第36天!
在昨天(Day 35)的课程中,我们化身为"数据采集员",成功编写爬虫抓取了豆瓣 Top250 的电影数据,并将它们整整齐齐地存入了 SQLite 数据库中。
但是,躺在数据库里的冷冰冰的数字是产生不了价值的。今天,我们要转型为数据分析师,将这些数据提取出来,挖掘其中的规律,并用直观的图表展示出来。
本节内容:
- 安装数据可视化库
matplotlib - 从 SQLite 读取数据
- 解决 Matplotlib 中文乱码问题
- 绘制柱状图:评分分布分析
- 绘制条形图:Top 10 电影排名
- 项目总结与复盘
一、环境准备
我们需要一个强大的绘图库。Python 界最老牌、最经典的绘图库是Matplotlib。
pipinstallmatplotlib二、读取数据与中文设置
新建一个文件visualize.py。首先,我们需要连接数据库并配置绘图环境。
2.1 解决中文乱码 (巨坑预警)
Matplotlib 默认不支持中文字体,直接画图中文会显示成方块□□。我们需要手动设置字体。
# visualize.pyimportsqlite3importmatplotlib.pyplotasplt# --- 配置 Matplotlib ---# 设置中文字体 (Windows通常是SimHei, Mac可能需要Arial Unicode MS或Heiti TC)plt.rcParams['font.sans-serif']=['SimHei']# 解决负号显示为方块的问题plt.rcParams['axes.unicode_minus']=False# 设置分辨率 (让图表更清晰)plt.rcParams['figure.dpi']=100defget_data(sql):"""通用函数:执行SQL并返回结果"""conn=sqlite3.connect("movie.db")cursor=conn.cursor()cursor.execute(sql)data=cursor.fetchall()conn.close()returndata三、分析1:评分分布 (柱状图)
问题:这 250 部经典电影中,哪个分数段的电影最多?是 9.0 分以上的封神之作多,还是 8.5 分左右的优秀作品多?
代码实现
defplot_rating_dist():# 1. 获取数据# 我们统计每个分数有多少部电影# SQL: SELECT rating, COUNT(*) FROM movies GROUP BY ratingsql="SELECT rating, COUNT(*) FROM movies GROUP BY rating ORDER BY rating"data=get_data(sql)# 解包数据:x轴是评分,y轴是数量ratings=[row[0]forrowindata]counts=[row[1]forrowindata]# 2. 创建画布plt.figure(figsize=(10,6))# 3. 绘制柱状图 (Bar Chart)# color: 柱子颜色, alpha: 透明度bars=plt.bar(ratings,counts,color='skyblue',width=0.1)# 4. 添加标题和标签plt.title("豆瓣Top250 电影评分分布",fontsize=16)plt.xlabel("评分",fontsize=12)plt.ylabel("电影数量",fontsize=12)# 5. 在柱子上显示具体数值forbarinbars:height=bar.get_height()plt.text(bar.get_x()+bar.get_width()/2,height,f'{int(height)}',ha='center',va='bottom')# 6. 保存并显示plt.grid(axis='y',linestyle='--',alpha=0.5)# 加个虚线网格更好看plt.savefig("rating_dist.png")plt.show()# 运行if__name__=="__main__":plot_rating_dist()分析结果:运行后你会发现,Top250 中大部分电影集中在8.5 到 9.0分之间,能够达到 9.5 分以上的电影凤毛麟角(如《肖申克的救赎》、《霸王别姬》)。
四、分析2:排名最高的10部电影 (条形图)
问题:谁是榜单上的"十大天王"?虽然我们知道 Rank 1-10,但画个图看起来更有气势。
代码实现
defplot_top10():# 1. 获取数据# 取前10名,按排名逆序 (为了让第1名显示在图表最上方)sql="SELECT title, rating FROM movies ORDER BY rank LIMIT 10"data=get_data(sql)# 因为 matplotlib 的 barh 是从下往上画的,所以我们需要把数据反转一下data.reverse()titles=[row[0]forrowindata]ratings=[row[1]forrowindata]# 2. 创建画布plt.figure(figsize=(12,8))# 3. 绘制水平条形图 (Horizontal Bar)plt.barh(titles,ratings,color='orange',height=0.6)# 4. 设置坐标轴范围 (评分都在9分以上,为了差异明显,X轴从9.0开始)plt.xlim(9.0,9.8)# 5. 添加标签plt.title("豆瓣Top250 - 前十名神作",fontsize=16)plt.xlabel("评分",fontsize=12)# 6. 保存并显示plt.tight_layout()# 自动调整布局,防止文字被遮挡plt.savefig("top10.png")plt.show()# 在 main 中加入调用if__name__=="__main__":# plot_rating_dist()plot_top10()五、综合实战项目复盘
至此,我们的豆瓣电影分析项目就全部完成了!让我们回顾一下整个流程:
你学会了什么?
- 全栈流程:体验了从"获取原料"(爬虫)到"加工存储"(数据库)再到"成品展示"(可视化)的完整数据链路。
- 问题解决:解决了反爬虫 User-Agent、数据库去重、Matplotlib 中文乱码等实际问题。
- 模块化思维:将不同功能的代码拆分到不同文件中,而不是写成一坨面条代码。
六、常见问题
Q1:Matplotlib 报错Font family ['SimHei'] not found?
这是因为你的电脑里没有 SimHei 字体(常见于 Linux/Mac)。
解决:
- Mac: 尝试
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']。 - Linux: 需要下载字体文件 (
.ttf) 并配置,或者直接使用英文标签。
Q2:生成的图片里的字叠在一起了?
使用plt.figure(figsize=(宽, 高))调大画布尺寸,或者使用plt.tight_layout()自动调整间距。
Q3:我想做更炫酷的可交互图表(比如鼠标悬停显示数值)?
Matplotlib 生成的是静态图片。如果想要交互式图表(如网页版),推荐学习Pyecharts或Plotly(这属于进阶/项目篇的内容)。
七、小结
恭喜你完成了进阶篇的一半旅程!
通过这两个实战,你已经不再是一个只会写if/else的初学者了。你具备了获取数据和分析数据的初步能力,这在当今"数据驱动"的职场中是非常核心的竞争力。
八、课后作业
- 词云图 (进阶挑战):安装
wordcloud和jieba库,从数据库中读取所有电影的quote(引言),进行分词,生成一张"豆瓣电影关键词"的词云图。 - 年代分析:(需要修改爬虫) 修改之前的爬虫,提取电影的"年份"。然后分析哪个年代(如90年代、00年代)上榜的电影最多。
- Excel 报表:将
visualize.py里的分析结果(如评分统计数据),写入到一个新的 Excel 文件中,作为一个简单的数据分析报告。
下节预告
Day 37:虚拟环境 (Virtualenv/Venv)- 随着项目越来越多,安装的库也越来越杂(A项目要用 Django 2.0,B项目要用 Django 4.0,打架了怎么办?)。明天我们学习如何给每个项目创建独立的"平行宇宙"。
系列导航:
- 上一篇:Day 35 - 综合实战爬虫与可视化上
- 下一篇:Day 37 - 虚拟环境管理(待更新)