尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python电影数据分析毕设实战:爬虫、SQLite与ECharts可视化全链路

发布时间:2026/9/28 18:33:38

资讯中心
01
ARTICLE

Python电影数据分析毕设实战:爬虫、SQLite与ECharts可视化全链路

Python电影数据分析毕设实战:爬虫、SQLite与ECharts可视化全链路
简介这是一套面向计算机相关专业学生与项目实战学习者的电影数据分析与可视化毕业设计资料适合正在准备毕设、课程设计或期末大作业的同学直接参考使用。资源包共39个文件约20.87MB包含Python源码、答辩PPT、项目说明文档、数据库文件以及前端静态资源等其中py文件负责数据爬取与分析逻辑db文件存储电影数据html、css、js与png等构成可视化展示页面pdf与md则提供项目说明和答辩参考。项目围绕电影信息的采集、清洗、统计与图表呈现展开目录中可见主程序入口、数据库模块、模板页面与运行脚本结构完整便于理解从数据到图表的整体流程。该资源已经过调试可直接运行已有468人学习下载适合作为毕设模板或数据分析入门实战案例帮助读者快速掌握Python数据处理与可视化的基本方法。1. 电影数据分析毕设包拆解从爬虫到可视化的完整链路很多同学做毕业设计时卡在同一个地方数据从哪来、怎么存、怎么把一堆 CSV 变成答辩 PPT 上能看的图表。这个基于 Python 的电影数据分析及可视化资源包恰好把这条链路走通了——它包含爬虫脚本、SQLite 数据库、Flask 后端、ECharts 前端可视化以及一份答辩 PPT 和说明文档。拿到手之后你不需要从零搭架子而是可以在一套能跑通的代码上做二次开发。适合计算机相关专业正在做毕设的学生也适合想练手 Python 数据分析完整流程的从业者。下面我按实际拆包和复现的顺序把这份资源的技术细节、运行步骤和踩坑点讲清楚。2. 环境搭建与项目结构先让 main.py 跑起来2.1 依赖安装与 Python 版本选择拿到压缩包解压后第一件事不是急着点run.bat而是确认 Python 版本。项目里用到了 Flask、pandas、requests、BeautifulSoup 这几个核心库建议用 Python 3.8 到 3.10 之间的版本太新的 3.12 在某些依赖上会有兼容问题。我一般会先建一个虚拟环境避免和系统里的包打架# 创建虚拟环境python3 -m venv 是标准做法 python -m venv venv # Windows 激活 venv\Scripts\activate # macOS/Linux 激活 source venv/bin/activate # 安装核心依赖版本号按项目实际能跑通的来 pip install flask pandas requests beautifulsoup4 lxml这里有个细节lxml是 BeautifulSoup 的解析器后端不装的话爬虫部分会报FeatureNotFound错误。很多同学只装beautifulsoup4就以为够了结果一跑就翻车。另外data.db是 SQLite 数据库文件不需要额外安装数据库服务Python 内置的sqlite3模块直接能读写这也是这个项目对新手友好的地方。2.2 目录结构与各文件职责解压后的目录大致是这样的文件/目录作用main.pyFlask 应用入口启动 Web 服务和路由DataBase.py数据库操作封装建表、插入、查询data.dbSQLite 数据库文件存电影数据MovieName.txt待爬取的电影名称列表templates/HTML 模板前端页面static/静态资源JS、CSS、图片app.log运行日志排查错误时看这个run.batWindows 一键启动脚本README.md项目说明文档答辩PPT.pdf答辩用的演示文稿基于python的春节电影信息爬取与数据可视化分析.pdf项目技术文档main.py是入口里面定义了 Flask 的路由比如/返回首页/api/movie_data返回 JSON 格式的电影数据供前端 ECharts 调用。DataBase.py负责和data.db交互通常会有create_table、insert_movie、get_all_movies这类函数。MovieName.txt里是一行一个电影名爬虫会读这个文件逐个去抓取信息。2.3 启动项目与验证运行确认依赖装好后直接运行# 方式一直接跑 main.py python main.py # 方式二Windows 下双击 run.bat # run.bat 内容通常是 python main.py pause启动后终端会输出类似Running on http://127.0.0.1:5000的信息浏览器打开这个地址就能看到可视化页面。如果页面空白或者报 500 错误先去app.log里看堆栈信息。常见的情况是data.db是空的前端拿不到数据这时候需要先跑爬虫脚本把数据灌进去。爬虫脚本可能在main.py里作为一个路由触发也可能是一个独立函数具体看代码里的app.route(/crawl)或者if __name__ __main__下面的调用逻辑。提示第一次运行前建议先备份data.db万一爬虫写入了脏数据可以直接还原不用重新爬。3. 爬虫与数据入库MovieName.txt 到 data.db 的完整链路3.1 爬虫逻辑拆解与请求头设置这个项目的爬虫部分核心逻辑是读MovieName.txt里的电影名拼接成搜索 URL发请求拿 HTML用 BeautifulSoup 解析出导演、主演、评分、上映时间等字段最后写入data.db。我一般会这样组织爬虫代码import requests from bs4 import BeautifulSoup import sqlite3 import time # 请求头必须带 User-Agent否则很多站点直接返回 403 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 } def crawl_movie(movie_name): 根据电影名爬取详情返回字典 # 这里以某电影信息站点为例实际 URL 看项目代码 search_url fhttps://example.com/search?q{movie_name} resp requests.get(search_url, headersheaders, timeout10) resp.encoding utf-8 # 防止中文乱码 soup BeautifulSoup(resp.text, lxml) # 解析字段选择器根据实际页面结构调整 movie { name: movie_name, director: soup.select_one(.director).text.strip() if soup.select_one(.director) else , rating: soup.select_one(.rating).text.strip() if soup.select_one(.rating) else , release_date: soup.select_one(.release-date).text.strip() if soup.select_one(.release-date) else } return movie def save_to_db(movie): 写入 SQLite conn sqlite3.connect(data.db) cursor conn.cursor() cursor.execute( INSERT INTO movies (name, director, rating, release_date) VALUES (?, ?, ?, ?) , (movie[name], movie[director], movie[rating], movie[release_date])) conn.commit() conn.close() # 主循环 with open(MovieName.txt, r, encodingutf-8) as f: names [line.strip() for line in f if line.strip()] for name in names: try: m crawl_movie(name) save_to_db(m) print(f成功入库{name}) except Exception as e: print(f抓取失败{name}原因{e}) time.sleep(1) # 控制频率别把人家站点打挂了这段代码里几个关键点headers里的 User-Agent 是必须的不带的话大概率被拒resp.encoding utf-8解决中文乱码不设的话可能拿到ISO-8859-1解码的乱码time.sleep(1)是礼貌爬取也避免触发频率限制。sqlite3的?占位符是参数化查询防止 SQL 注入也是标准写法。3.2 数据库表结构与字段设计DataBase.py里通常会有建表语句结构大概是import sqlite3 def init_db(): conn sqlite3.connect(data.db) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS movies ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, director TEXT, rating REAL, release_date TEXT, box_office REAL ) ) conn.commit() conn.close()字段设计上rating用 REAL 存浮点数方便后面做评分分布直方图release_date用 TEXT 存日期字符串SQLite 没有原生日期类型用 TEXT 存YYYY-MM-DD格式最省事box_office存票房单位统一成万元或亿元前端展示时再格式化。如果项目里还有类型、地区、时长这些字段按同样方式加列就行。3.3 数据清洗与异常处理爬下来的数据不可能直接能用常见问题有评分字段带「分」字后缀、日期格式不统一、导演字段混入了「主演」信息。我一般会在入库前加一层清洗import re def clean_rating(raw): 从 8.5分 这类字符串里提取浮点数 if not raw: return 0.0 match re.search(r(\d\.?\d*), raw) return float(match.group(1)) if match else 0.0 def clean_date(raw): 统一成 YYYY-MM-DD if not raw: return # 把 2024年1月1日 转成 2024-01-01 raw raw.replace(年, -).replace(月, -).replace(日, ) return raw.strip(-)清洗这一步不做的话后面 pandas 做聚合分析时rating列是 object 类型mean()直接报错。这是血泪经验数据类型不对后面所有分析都是空中楼阁。4. Flask 后端与 ECharts 前端可视化页面怎么串起来4.1 Flask 路由设计与 JSON 接口main.py里的 Flask 应用负责两件事渲染 HTML 页面以及提供数据接口。典型写法from flask import Flask, render_template, jsonify import sqlite3 app Flask(__name__) def query_db(sql, args()): conn sqlite3.connect(data.db) conn.row_factory sqlite3.Row # 让结果可以按列名访问 cursor conn.cursor() cursor.execute(sql, args) rows cursor.fetchall() conn.close() return [dict(row) for row in rows] app.route(/) def index(): return render_template(index.html) app.route(/api/rating_distribution) def rating_distribution(): 返回评分分布数据供 ECharts 柱状图使用 sql SELECT CAST(rating AS INT) AS score_bucket, COUNT(*) AS cnt FROM movies WHERE rating 0 GROUP BY score_bucket ORDER BY score_bucket data query_db(sql) return jsonify({ x: [str(d[score_bucket]) for d in data], y: [d[cnt] for d in data] }) if __name__ __main__: app.run(debugTrue, host0.0.0.0, port5000)conn.row_factory sqlite3.Row这行很关键不设的话fetchall()返回的是元组你得用下标访问容易搞错顺序。设了之后可以row[rating]这样按列名取代码可读性好很多。jsonify把字典转成 JSON 响应前端fetch拿到后直接喂给 ECharts。4.2 ECharts 图表配置与数据绑定前端templates/index.html里通常这样写// 初始化 ECharts 实例 var chart echarts.init(document.getElementById(ratingChart)); // 从后端接口拿数据 fetch(/api/rating_distribution) .then(response response.json()) .then(data { var option { title: { text: 电影评分分布 }, tooltip: {}, xAxis: { type: category, data: data.x // 后端返回的评分区间 }, yAxis: { type: value }, series: [{ name: 数量, type: bar, data: data.y // 后端返回的计数 }] }; chart.setOption(option); }); // 窗口大小变化时自适应 window.addEventListener(resize, function() { chart.resize(); });chart.resize()这行不加的话浏览器窗口缩放后图表会变形或者留白答辩演示时全屏切换很容易翻车。ECharts 的setOption是增量合并重复调用不会覆盖已有配置但如果你想彻底刷新数据可以先chart.clear()再setOption。4.3 多图表联动与页面布局项目里通常不止一个图表可能有评分分布、票房 Top10、类型占比饼图、年度趋势折线图。多个 ECharts 实例之间可以通过echarts.connect做联动比如点击柱状图的某个柱子饼图跟着高亮对应类型。布局上用 CSS Grid 或 Flexbox 把图表容器排成两列或三列每个容器给固定高度不然 ECharts 初始化时拿不到高度会渲染成 0 像素。我一般会在 CSS 里写.chart-box { width: 100%; height: 400px; }确保容器有明确尺寸。注意如果页面加载后图表不显示先打开浏览器控制台看有没有echarts is not defined这通常是echarts.min.js没引入或者路径写错了。5. 避坑与常见问题排查5.1 爬虫返回 403 或空数据现象运行爬虫脚本后终端大量输出「抓取失败」或者入库的字段全是空字符串。原因目标站点做了反爬检测到请求头里没有 User-Agent 或者请求频率过高直接返回 403也可能是页面结构变了原来的 CSS 选择器匹配不到元素。解决先补全请求头除了 User-Agent有些站点还检查Referer和Accept-Language。然后在浏览器里手动打开目标页面右键检查元素确认选择器路径是否还对。如果站点结构大改选择器要跟着调。频率方面把time.sleep(1)改成time.sleep(2)或更长别贪快。5.2 SQLite 数据库锁定现象爬虫跑着跑着报sqlite3.OperationalError: database is locked。原因SQLite 默认是文件级锁同一个数据库文件同时被多个连接写入时会冲突。Flask 的 debug 模式会启动两个进程一个跑爬虫一个跑 Web 服务两边同时写就锁了。解决爬虫和 Web 服务不要同时写库。先把爬虫跑完确认数据入库了再启动 Flask。或者把app.run(debugTrue)改成debugFalse减少进程数。如果确实需要并发写考虑换成 PostgreSQL 或 MySQL但毕设场景下没必要。5.3 中文乱码现象页面上电影名显示成「春节」这类乱码。原因爬虫请求返回的编码和实际编码不一致requests默认按 HTTP 头里的Content-Type猜编码猜错了就乱码。解决在requests.get之后手动指定resp.encoding utf-8或resp.encoding resp.apparent_encoding。apparent_encoding是chardet库猜出来的编码更准但慢一点。数据库连接时也加conn.text_factory str确保读出的是 Unicode。5.4 Flask 端口被占用现象启动时报OSError: [Errno 98] Address already in use。原因5000 端口被其他程序占了常见的是之前没关干净的 Flask 进程或者 macOS 的 AirPlay 接收器。解决换端口app.run(port5001)。或者找到占用进程杀掉Windows 下netstat -ano | findstr :5000找到 PID然后taskkill /PID xxx /FmacOS/Linux 下lsof -i :5000然后kill -9 xxx。5.5 答辩 PPT 与代码不一致现象PPT 里写的功能代码里没有或者代码里的图表 PPT 里没体现。原因PPT 是单独做的没有和最终代码同步。解决答辩前把 PPT 里的每个图表截图和代码实际运行结果对一遍不一致的地方要么改 PPT 要么改代码。导师最常问的就是「这个图的数据怎么来的」你得能指着代码说出 SQL 或者 pandas 的哪一行。6. 二次开发与答辩加分技巧6.1 用 pandas 做更深的统计分析项目自带的 SQL 聚合能出基础图表但如果你想在答辩时展示「相关性分析」或「年度趋势预测」pandas 会更顺手。比如分析评分和票房的关系import pandas as pd import sqlite3 conn sqlite3.connect(data.db) df pd.read_sql(SELECT name, rating, box_office, release_date FROM movies, conn) conn.close() # 提取年份 df[year] pd.to_datetime(df[release_date], errorscoerce).dt.year # 按年份统计平均评分和总票房 yearly df.groupby(year).agg( avg_rating(rating, mean), total_box(box_office, sum), count(name, count) ).reset_index() # 算评分和票房的皮尔逊相关系数 corr df[rating].corr(df[box_office]) print(f评分与票房相关系数{corr:.3f})pd.to_datetime的errorscoerce参数把解析不了的日期变成NaT避免整列报错。groupby之后agg可以一次性算多个统计量比写多个 SQL 简洁。相关系数如果接近 0说明评分高不一定票房高这个结论放到答辩里就是一个可以展开讨论的点。6.2 用 pyecharts 替换 ECharts 前端如果你对 JavaScript 不熟可以用pyecharts直接在 Python 里生成图表 HTMLFlask 只负责渲染from pyecharts.charts import Bar from pyecharts import options as opts def make_rating_chart(data): bar ( Bar() .add_xaxis(data[x]) .add_yaxis(电影数量, data[y]) .set_global_opts( title_optsopts.TitleOpts(title评分分布), xaxis_optsopts.AxisOpts(name评分区间), yaxis_optsopts.AxisOpts(name数量) ) ) return bar.render_embed() # 返回 HTML 字符串render_embed()返回的是完整的 HTML 片段直接塞进 Jinja2 模板就行。这样你不需要写fetch和setOption所有逻辑都在 Python 里对不熟悉前端的同学更友好。缺点是灵活性不如原生 ECharts复杂交互做不了。6.3 答辩演示的检查清单答辩前我一般会强制走一遍这个流程先确认data.db里有数据SELECT COUNT(*) FROM movies至少几十条然后python main.py启动浏览器打开每个页面确认图表都渲染出来再点一遍所有交互按钮看有没有报错。PPT 里的截图全部换成最新运行结果别用旧的。最后把app.log清空免得答辩时弹出一堆历史错误日志。从那以后我每次交付带可视化页面的项目都会在答辩前一天晚上把整个流程从零跑一遍——删掉data.db、重新爬、重新启动、重新截图。这个习惯帮我避开了好几次「本地能跑、换台电脑就崩」的尴尬。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。