Python+Vue实战:从零搭建中国电影票房数据可视化分析系统(附完整源码)
本文将带你从零开始,使用 Python Flask + Vue3 + ECharts 搭建一个完整的中国电影票房数据可视化分析系统。包含数据清洗、后端API开发、前端可视化大屏等全流程实现,适合作为全栈学习项目或技术作品集展示。
一、项目效果预览
1. 数据总览大屏
首页采用仪表盘布局,核心指标一目了然:
同时集成了年度票房趋势折线图、电影类型分布饼图、地区影片分布柱状图等多维度可视化。
2. 原始数据处理
项目基于真实的中国电影票房Excel数据进行处理,包含以下字段:
3. 电影信息管理
完整的CRUD功能:
- 实时统计卡片:总片数、高评分占比、高票房占比、平均票房
4. 票房深度分析
四大分析维度:
- 票房TOP10排行
- 首日/首周/累计对比
- 预测vs实际偏差
- 关键指标卡片
5. 电影详情页
以《哪吒之魔童闹海》为例,详情页包含:
- 基础信息卡片
- 票房数据面板:累计票房、首日票房、首周票房、最高单日、分账票房
- 星级评分占比
- 票房构成柱状图
6. 类型多维度分析
三种可视化视角:
| |
|---|
| 类型数量分布饼图 | |
| 各类型平均票房柱状图 | |
| 类型综合雷达图 | |
下方附带详细数据表格,支持排序查看。
7. 地区分析
- 各地区影片数量分布
- 各地区票房与评分双轴图
- 详细统计表
8. 年度趋势分析
综合趋势折线图 + 五维小图表矩阵:
二、技术架构
技术栈明细
| | | |
|---|
| 前端框架 | | | |
| UI组件库 | | | |
| 状态管理 | | | |
| 图表库 | | | |
| HTTP客户端 | | | |
| 后端框架 | | | |
| ORM | | | |
| 数据库 | | | |
| 认证 | | | |
| 跨域 | | | |
三、核心功能模块
3.1 数据层设计
# Movie模型 (核心字段)class Movie(db.Model): id = db.Column(db.Integer, primary_key=True) movie_id = db.Column(db.String(50)) # 电影唯一标识 name = db.Column(db.String(200)) # 片名 english_name = db.Column(db.String(300)) # 英文名 genre = db.Column(db.String(100)) # 类型 region = db.Column(db.String(50)) # 地区 release_date = db.Column(db.String(100)) # 上映日期 total_box_office = db.Float) # 累计票房(万) opening_day_box_office = db.Float) # 首日票房(万) opening_week_box_office = db.Float) # 首周票房(万) predicted_box_office = db.Float) # 预测票房(万) rating = db.Float) # 评分 rating_count = db.Integer) # 评分人数 want_to_see_count = db.Integer) # 想看人数 release_year = db.Integer) # 上映年份 list_year = db.Integer) # 统计年份
3.2 API接口设计
/api/movies/ GET /list 获取电影列表(分页+筛选) GET /:id 获取电影详情 PUT /:id 更新电影信息 DELETE /:id 删除电影/api/box-office/ GET /overview 票房概览统计 GET /top10 票房TOP10 GET /comparison 首日/首周/累计对比 GET /ranking 票房排行榜/api/rating/ GET /top10 评分TOP10 GET /distribution 评分分布 GET /vs-box-office 评分vs票房散点图 GET /want-to-see/top10 想看人数TOP10/api/analysis/ GET /genre 类型分析 GET /region 地区分析 GET /yearly-trend 年度趋势/api/auth/ POST /register 用户注册 POST /login 用户登录 GET /me 获取当前用户 PUT /profile 更新个人信息 POST /avatar 上传头像 POST /change-password 修改密码
3.3 数据去重策略
针对同一电影可能多次上榜的问题,实现了智能去重:
def get_deduped_query(): """获取去重后的查询,同一movie_id只保留最新记录""" subq = db.session.query( func.max(Movie.id).label('max_id') ).group_by(Movie.movie_id).subquery() return Movie.query.join(subq, Movie.id == subq.c.max_id)
3.4 单位转换处理
后端统一进行单位转换,前端直接展示:
# 后端转换逻辑'avg_total_box_office': round((stats.avg_total or 0) / 10000, 2) # 万元→亿元'rating_count': round((d['rating_count'] or 0) / 10000, 2) # 人→万人'want_to_see_count': round((d['want_to_see_count'] or 0) / 10000, 2) # 人→万人
四、项目目录结构
flask_project/├── backend/ # 后端代码│ ├── app/│ │ ├── __init__.py # Flask应用工厂│ │ ├── app.py # 入口文件│ │ ├── models/│ │ │ ├── movie.py # 电影模型│ │ │ └── user.py # 用户模型│ │ ├── routes/│ │ │ ├── auth_routes.py # 认证路由│ │ │ ├── dashboard_routes.py # 仪表盘│ │ │ ├── movie_routes.py # 电影CRUD│ │ │ ├── box_office_routes.py # 票房分析│ │ │ ├── rating_routes.py # 评分分析│ │ │ ├── analysis_routes.py # 分析接口│ │ │ └── yearly_trend_routes.py # 年度趋势│ │ └── utils/│ │ └── data_cleaner.py # 数据清洗工具│ ├── uploads/│ │ └── avatars/ # 头像上传目录│ ├── requirements.txt│ └── data/│ └── movies.db # SQLite数据库│├── frontend/ # 前端代码│ ├── src/│ │ ├── api/index.js # API封装│ │ ├── components/ # 公共组件│ │ │ └── Header.vue # 顶部导航│ │ ├── views/ # 页面组件│ │ │ ├── Dashboard.vue # 数据总览│ │ │ ├── MovieList.vue # 电影列表│ │ │ ├── MovieDetail.vue # 电影详情│ │ │ ├── BoxOfficeAnalysis.vue # 票房分析│ │ │ ├── RatingAnalysis.vue # 评分分析│ │ │ ├── GenreAnalysis.vue # 类型分析│ │ │ ├── RegionAnalysis.vue # 地区分析│ │ │ ├── YearlyTrendAnalysis.vue# 年度趋势│ │ │ ├── Login.vue # 登录注册│ │ │ └── Profile.vue # 个人设置│ │ ├── stores/auth.js # 认证状态│ │ ├── router/index.js # 路由配置│ │ └── main.js # 入口文件│ ├── package.json│ └── vite.config.js│├── data/│ └── 电影票房完整数据v1.0.xlsx # 原始数据└── 发布文案.md
五、快速开始
5.1 环境要求
5.2 后端启动
cd backend# 创建虚拟环境python -m venv venvvenv\Scripts\activate# 安装依赖pip install -r requirements.txt# 导入数据(首次运行)flask import-data# 启动服务python app.py
访问:http://localhost:5000
5.3 前端启动
cd frontend# 安装依赖npm install# 启动开发服务器npm run dev
访问:http://localhost:3000
5.4 默认账号
六、关键技术点解析
6.1 ECharts图表优化
滚动条初始位置修复:
dataZoom: [ { type: 'slider', show: true, start: 0, // 关键:从0开始,不是计算值 end: data.length > 15 ? Math.ceil(15 / data.length * 100) : 100 }]
Tooltip格式化:
tooltip: { formatter: function(params) { return `{params[0].value}</b> 亿元` }}
6.2 前端状态管理
使用Pinia管理全局认证状态:
// stores/auth.jsexport const useAuthStore = defineStore('auth', () => { const token = ref(localStorage.getItem('token') || '') const user = ref(JSON.parse(localStorage.getItem('user') || 'null')) const isAdmin = computed(() => user.value?.role === 'admin') return { token, user, isAdmin, logout, fetchUser }})
6.3 文件上传处理
@auth_bp.route('/avatar', methods=['POST'])@jwt_required()def upload_avatar(): file = request.files['avatar'] # 格式校验 allowed_extensions = {'png', 'jpg', 'jpeg', 'gif', 'webp'} # 大小限制 2MB # UUID命名防冲突 filename = f"{uuid4().hex}.{ext}" return jsonify({'code': 200, 'data': {'avatar': f"/uploads/avatars/{filename}"}})
七、扩展方向
本项目还可以进一步扩展:
- 实时数据接入
- 数据导出功能
- 权限细化
- 数据预警
- 移动端适配
- 国际化
八、总结
通过这个项目,你可以学到:
| |
|---|
| Python后端 | Flask RESTful API设计、ORM操作、JWT认证 |
| Vue前端 | Composition API、Pinia状态管理、ECharts可视化 |
| 数据处理 | |
| 工程实践 | |
源码已整理完毕,如有需要可扫码关注私信获取~
如果觉得有帮助,欢迎点赞收藏关注!有问题评论区交流~