news 2026/9/23 12:43:04

Python爬虫+pyecharts:电影票房与评分数据可视化实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python爬虫+pyecharts:电影票房与评分数据可视化实战

简介:一套基于Python+pyecharts的国内上映电影票房与评分可视化分析项目,面向Python初学者及需要完成期末大作业、课程设计的学生,覆盖数据采集、清洗、可视化到报告生成的全流程,能够帮助快速搭建一个功能完整的电影数据分析系统。压缩包共33个文件,主要有6个Python脚本、10个HTML可视化页面、9张PNG图表、3个CSV数据文件以及1个Jupyter Notebook,脚本负责抓取豆瓣、猫眼、时光网等平台数据并生成图表,HTML页面可直接查看分析结果,整包约2.74MB。目前已有138人学习。项目代码含有详细注释,结构清晰,按步骤即可部署运行,即使新手也能看懂;功能上涵盖票房排行、评分分布、类型对比、演员票房等多个维度,输出结果包含交互式图表和静态图片,美观且实用。文档说明帮助使用者理解项目思路与扩展方向,可直接作为高分大作业或课程设计提交。

1. 这个项目到底解决什么问题:把“票房直觉”变成能验证的图表

“票房高的电影评分一定高”这个直觉,放到真实数据里经常翻车。春节档某部科幻片累计票房排进前三,豆瓣评分却没过及格线;另一部小成本文艺片评分逼近9分,票房连前二十都没进。票房和口碑之间到底是什么关系,靠体感说不清,把国内上映电影的票房、评分、上映天数拉到同一张图上,规律自然浮现。这个项目就是用 Python 写爬虫采集国内上映电影的数据,用 pyecharts 把榜单、走势、评分分布画成图表,最终产出一份能放进汇报页或课程设计文档的可视化报告。适合两类人:一是手里有 Python 基础但缺一个完整实战项目的学习者,二是想快速读档期市场表现的运营和影迷。先给你交个底:真正花时间的是画图之前的数据清洗,pyecharts 本身只是最后一步。

2. 用 Python 爬虫拿数据:把国内上映电影的票房与评分落成 CSV

2.1 数据源选型:为什么优先选公开接口而不是手工整理

做这个项目最先要回答的问题不是“用什么图表”,而是“数据从哪来”。我试过三条路:手工在票房平台逐部抄写、下载别人整理好的 Excel、用 Python 爬虫请求公开接口。三条路都跑过之后,结论很明确:公开接口是最划算的选择,实时性好、字段全、无需登录和验证码,唯一成本是写一个 requests 脚本。

对比下来大致是这样:

方案数据时效字段覆盖成本适合场景
手工抄写准实时可自定义高,几十部就累数据量小于 30 条的临时分析
下载现成 Excel滞后取决于整理者低,但口径不明练手、验证图表 API
爬虫请求公开接口准实时片名、票房、评分、类型、上映天数等中,需处理反爬课程设计、持续跟踪档期

选型标准其实就三条:数据能否按天更新、字段是否覆盖票房和评分两套口径、接口返回是否是干净的 JSON。满足这三条,就值得在它上面花时间。接口返回的 JSON 里一般会带list数组,每个元素是一部电影的详情,解析起来比 HTML 页面省太多事。

这里顺带说一句,很多初学者卡在第一步:python 环境配置没做好,requests 装不上。我一般建议直接用 Anaconda 建一个独立环境,Python 3.9 以上就够了,pycharm 里解释器选到 conda 环境,后面所有依赖都装在环境里,不污染系统 Python。

2.2 用 requests 拿数据的最小脚本:先保证能跑通再谈封装

写爬虫最忌讳一上来就搞多线程、代理池、断点续传,第一版能跑通、能拿到 20 部电影的数据就算成功。下面这个脚本是我不论项目大小都会先写的最小版本:

import requests import json import time # 公开榜单接口,实际使用时换成你对接的数据源 url = "https://api.example.com/v1/boxoffice/daily" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Accept": "application/json", } def fetch_daily_rank(page=1): """拉取单页票房榜单数据""" params = {"date": "2025-01-01", "page": page, "page_size": 20} resp = requests.get(url, headers=headers, params=params, timeout=10) resp.raise_for_status() # 非 2xx 状态码直接抛异常,便于排查 data = resp.json() return data.get("list", []) if __name__ == "__main__": movies = fetch_daily_rank(page=1) print(f"拿到 {len(movies)} 条记录") if movies: # 先打印第一条,确认字段名再写解析逻辑 print(json.dumps(movies[0], ensure_ascii=False, indent=2))

这段代码有三个值得注意的地方。第一是timeout=10,不加超时的话,接口挂掉时脚本会一直卡住,这在批量抓取时非常致命。第二是resp.raise_for_status(),它把 HTTP 错误变成异常直接抛出,省去自己判断状态码。第三是先打印第一条原始 JSON,很多新人上来就写解析,结果字段名拼错,回头排错半天。

拿到样例数据后,再看它有哪些字段。一般会包含movie_namerelease_dateboxoffice(单日票房)、total_boxoffice(累计票房)、douban_scorerating_peoplegenre等。字段名因数据源而异,我习惯先转成字典看 key,再定后续的清洗规则,不要凭记忆猜。

2.3 数据落地:CSV 还是 SQLite,看数据量和查询方式

第一版数据量通常只有几百条,CSV 完全够用,而且有个天然好处:pandas 读 CSV 不需要任何额外配置,Excel 也能直接打开查看。缺点是文件一多就乱,比如我今天拉一份、明天拉一份,全堆在目录里。我一般的做法是文件名带日期,比如boxoffice_20250101.csv,按天归档。

import pandas as pd def save_to_csv(movies, filename="movies_raw.csv"): """把接口返回的 JSON 数组转成 DataFrame 再落盘""" df = pd.DataFrame(movies) # 统一列名,去掉冗余字段 columns = ["movie_name", "release_date", "total_boxoffice", "daily_boxoffice", "douban_score", "genre", "director"] df = df[[c for c in columns if c in df.columns]] df.to_csv(filename, index=False, encoding="utf-8-sig") print(f"已保存 {len(df)} 条到 {filename}")

这里有一个容易翻车的细节:encoding必须用utf-8-sig,不要用utf-8。原因在于 Excel 打开 UTF-8 无 BOM 的文件时,中文列名会全部乱码成“锟斤拷”,这个坑我至少踩过三次。加-sig后缀后文件自带 BOM 标记,Excel 和 pandas 都能正确识别。另外index=False一定别漏,否则每行前面多出一列无意义的序号,后续读取时会多一个Unnamed: 0列。

什么情况用 SQLite?当你要跨日期做对比,比如查“最近 30 天每天票房 TOP10 的排名变化”,CSV 就吃力了,因为每部电影在不同日期有不同排名,需要频繁 join。那时候建议用sqlite3建一张表,把日期、片名、票房、排名作为字段,靠 SQL 聚合。课程设计阶段,CSV 是性价比最高的选择,不要过度设计。

2.4 频率控制与反爬边界:别为了跑数据把接口搞挂

这一节是很多教程不会细写、但实际做项目一定会遇到的部分。公开接口不等于可以随便打,控制不好频率,轻则 IP 被临时限流,重则整个网段被拉黑。

import random import time for page in range(1, 5): movies = fetch_daily_rank(page=page) if not movies: break save_to_csv(movies, filename=f"movies_page{page}.csv") # 随机延时 1-3 秒,避免固定间隔被识别 time.sleep(random.uniform(1, 3))

random.uniform(1, 3)比固定time.sleep(2)更稳妥,原因不是玄学:固定间隔的模式在服务器日志里非常明显,一眼就能看出是脚本在跑。随机延时打乱节奏,服务器的压力也小。另外我习惯每页抓完看一眼返回条数,如果某页返回空,说明数据到底了,直接 break,省得浪费时间。

还有几个实战里总结的底线。第一,单次运行只抓必要的数据量,比如做近一个月的票房分析,每天拉一次就够了,没必要拉全年;第二,绝不并发请求,ThreadPoolExecutor再配requests确实快,但请求频率骤然升高最容易触发风控;第三,不碰需要登录或者加密参数的接口,那不是这个项目该碰的范畴,风险也不可控。记住一个原则:让数据源感觉你是个普通用户在翻页,而不是抓取机器。

3. 数据清洗与特征构建:票房分析的 80% 功夫在画图之前

3.1 字段口径统一:票房单位、评分空值、日期格式必须一次理清

拿到的原始数据基本不能直接用。最常见的三个问题:票房字段有的是字符串“1.2亿”有的是数字 120000000;评分字段大量 NaN,因为新片上映前三天评分人数不足,平台不展示;日期字段有的是2025-01-01有的是20250101。这些问题不解决,pyecharts 画图时轻则 X 轴乱序,重则直接报TypeError

import pandas as pd df = pd.read_csv("movies_raw.csv") def parse_amount(v): """把 '1.2亿' / '3500万' 转成整数(单位:元)""" if pd.isna(v): return None s = str(v) if "亿" in s: return int(float(s.replace("亿", "")) * 1e8) if "万" in s: return int(float(s.replace("万", "")) * 1e4) try: return int(float(s)) except ValueError: return None df["total_boxoffice"] = df["total_boxoffice"].apply(parse_amount) df["release_date"] = pd.to_datetime(df["release_date"], format="%Y-%m-%d") df["douban_score"] = pd.to_numeric(df["douban_score"], errors="coerce")

这段做完,票房变成统一的整数,日期变成datetime64类型,评分变成float64errors="coerce"的意思是解析失败的字符串一律转成NaN,这样后面就能统一处理缺失值。为什么非要统一成数值?因为 pyecharts 画柱状图时如果数值列里混着字符串,图表会按字符串处理,排序和刻度全乱。

这里有个经验:先做一轮口径清洗再做任何聚合,顺序不能反。我有一次图省事,先groupby("genre")求平均票房,结果混着“万”和“亿”的平均值完全没意义,白白返工。做项目别怕慢,清洗这步慢才是对的。

3.2 构建三个核心分析特征:累计票房排名、上映天数和口碑热度

清洗只是第一步,要分析票房和评分的关系,还得造出一些原始接口里没有的特征。我每次做电影数据分析都会算三样东西:票房排名、上映天数、单日票房占比。

# 按累计票房排名 df["boxoffice_rank"] = df["total_boxoffice"].rank(ascending=False, method="min") # 计算上映天数(假设以 2025-01-31 为分析截止日) cutoff = pd.Timestamp("2025-01-31") df["days_since_release"] = (cutoff - df["release_date"]).dt.days # 单日票房占累计票房的比例 df["daily_to_total_ratio"] = df["daily_boxoffice"] / df["total_boxoffice"] # 口碑热度:评分数与票房的比值,衡量单位票房带动的讨论量 df["heat_per_billion"] = df["rating_people"] / (df["total_boxoffice"] / 1e8)

这几个特征各有用处。boxoffice_rank用于排序榜单,days_since_release用来判断“这部片是处于首周爆发期还是长尾期”,daily_to_total_ratio能识别逆跌的片子——某天票房反而比前一天高,通常是口碑发酵的信号。heat_per_billion是分析里最出彩的指标,单位票房对应的评论人数越高,说明讨论热度越强,这在画散点图时能直接暴露出口碑和票房的背离。

这里插一句为什么要做特征而不是直接拿原始字段画图:单一字段只能描述“是什么”,特征才能回答“为什么”。只看累计票房你不知道它是上映 30 天堆出来的还是 3 天冲出来的;只有把上映天数和单日票房放一起,你才有判断依据。这就是数据分析里常说的“特征工程”,在这个项目里它只需要四个列,成本很低,收益很高。

3.3 画图前的最后一道关卡:用 describe 和 isnull 做数据体检

清洗完、特征构建完,别急着to_csv就开画,先做一轮快速体检。这一轮大概只要一分钟,但能拦下大部分“图表看着不对”的问题。

# 1. 描述性统计,检查数值范围是否合理 print(df[["total_boxoffice", "douban_score", "days_since_release"]].describe()) # 2. 缺失值统计 print(df.isnull().sum()) # 3. 重复行检查 print(df.duplicated(subset=["movie_name"]).sum())

describe()的输出重点看 min 和 max:票房有没有负数,评分有没有超过 10,上映天数有没有负值。这些异常值往往来自接口的脏数据,比如某部电影提前点映导致上映日期写错。缺失值方面,评分缺失不影响画票房榜,但画评分分布时必须过滤掉。重复行是另一个高频坑,接口分页时可能把同一部电影返回两次,不查重的话柱状图里会出现两根一模一样的柱子。

有异常就处理,处理规则要简单直接:票房非正的整行删掉,评分 NaN 的暂时保留但标记出来,重复的取最新一条。删完再看一眼行数,确认没有误删过多。数据干净了,后面所有图表一次成型,那种滋味和画完发现数据错了再全部重画完全不一样。

4. pyecharts 出图:把票房与评分数据变成能上汇报页的图表

4.1 图表选型逻辑:一个维度一张图,不硬凑

pyecharts 能画的图很多,但每张图都有它擅长回答的问题。我的原则是:先想清楚这张图要说什么,再选图表类型,顺序绝对反过来不成立。选型标准就三条:数据是离散的还是连续的、对比的是排名还是趋势、读者需要在图里花几秒钟读懂。

要回答的问题数据结构推荐图表pyecharts 类名
票房 TOP20 是哪些片片名 + 数值横向柱状图Bar
每日票房怎么波动日期 + 数值折线图 + 标记点Line
评分集中在哪个区间连续数值分布直方图(用 Bar 模拟)Bar
各类型影片票房占比类别占比饼图 / 环形图Pie
票房与评分是否相关两个连续变量散点图Scatter

这里特别说下散点图,它是整个项目信息密度最高的图,横轴是豆瓣评分、纵轴是累计票房,每个点是一部电影。这张图画出来,你一眼就能看见“右上角高票房高评分”的片子其实非常少,大量电影挤在“评分 6-7 分、票房几千万”的中间地带。很多没做过分析的人会以为高分必然高票房,看完散点图这个迷思立刻就破了。

4.2 票房 TOP15 横向柱状图:Bar 的标签、颜色与排序调优

画排名类数据,我几乎不用竖向柱状图,原因很现实:片名超过六个字后,竖向图底部的 X 轴标签会挤成黑压压一团,字贴字根本没法看。横向柱状图把片名放在 Y 轴,空间足够,阅读顺序也自然——从上往下扫就是排名。

from pyecharts.charts import Bar from pyecharts import options as opts import pandas as pd df = pd.read_csv("movies_clean.csv") top15 = df.nlargest(15, "total_boxoffice") bar = ( Bar() .add_xaxis(top15["movie_name"].tolist()) .add_yaxis( "累计票房(元)", top15["total_boxoffice"].tolist(), label_opts=opts.LabelOpts( position="right", # 数值标签放在柱子右侧 formatter="{c}", # 显示原始数值 ), ) .reversal_axis() # 关键:把柱状图转成横向 .set_global_opts( title_opts=opts.TitleOpts(title="国内上映电影票房 TOP15"), yaxis_opts=opts.AxisOpts(name="片名"), xaxis_opts=opts.AxisOpts(name="累计票房", axislabel_opts=opts.LabelOpts(formatter="{value}")), ) ) bar.render("top15_boxoffice.html")

这段代码里reversal_axis()是最关键的一行,它把柱子从竖直翻转为水平,同时自动交换 X/Y 轴的角色。LabelOpts(position="right")把数值标签放在每根柱子末端,读数更直观。formatter="{c}"是数据占位符,{c}代表当前数据点的值,默认会显示,但显式写出来是提醒自己这里可以改成更友好的格式,比如把 120000000 变成“1.2 亿”,后面优化时直接改这个 function 就行。

图表生成后是 HTML 文件,浏览器直接打开就能看。如果要在 Jupyter Notebook 里内联显示,需要在前面加一句bar.render_notebook()而不是bar.render(),这是新手最容易搞混的地方。

4.3 每日票房走势折线图:Line 的 MarkPoint 找到档期高点

折线图适合看时间序列,但一条光秃秃的折线信息量不够。我会在线上标记两个东西:最高单日票房对应哪部电影、平均票房线在哪里。pyecharts 的MarkPointMarkLine就是干这个的。

from pyecharts.charts import Line from pyecharts import options as opts # 假设 daily_df 包含 date 和 total 两列 dates = daily_df["date"].dt.strftime("%m-%d").tolist() totals = daily_df["total"].tolist() line = ( Line() .add_xaxis(dates) .add_yaxis( "单日票房(元)", totals, markpoint_opts=opts.MarkPointOpts( data=[opts.MarkPointItem(type_="max", name="峰值")], symbol="pin", symbol_size=50, ), markline_opts=opts.MarkLineOpts( data=[opts.MarkLineItem(type_="average", name="平均线")] ), is_smooth=True, ) .set_global_opts( title_opts=opts.TitleOpts(title="每日票房走势"), xaxis_opts=opts.AxisOpts(name="日期"), yaxis_opts=opts.AxisOpts(name="票房", splitline_opts=opts.SplitLineOpts(is_show=True)), ) ) line.render("daily_trend.html")

MarkPointItem(type_="max")会自动找出数据里的最大值并在图中插一个标记,symbol="pin"是图钉样式,视觉上最显眼。MarkLineItem(type_="average")画一条平均虚线,一眼看出哪些日子在均值之上。看走势图时最值得关注的就是峰值的日期和关联事件——如果峰值出现在周五周六,说明市场还是吃档期红利;如果峰值出现在非周末,通常是某部爆款的口碑效应带热了大盘。

is_smooth=True会让折线变成平滑曲线,视觉上更柔和,但要注意它只是贝塞尔插值,不改变数据本身,别为了美观牺牲准确性。如果你要输出严格的趋势图,建议保留直折线。

4.4 评分分布与类型占比:Pie 和直方图的正确打开方式

评分分布直方图能非常直观地反映市场结构:观众打出来的分数集中在 6.5 到 8 分之间,说明大部分电影属于“能看但不出彩”;如果分布出现双峰,比如 5 分和 8 分各有一个峰,说明市场在“烂片”和“佳作”之间极化。pyecharts 没有专门的直方图类,我一般用 Bar 手动分箱替代。

import numpy as np scores = df["douban_score"].dropna() bins = [0, 3, 4, 5, 6, 7, 8, 9, 10] labels = ["0-3", "3-4", "4-5", "5-6", "6-7", "7-8", "8-9", "9-10"] hist_counts = pd.cut(scores, bins=bins, labels=labels).value_counts().reindex(labels) bar_hist = ( Bar() .add_xaxis(labels) .add_yaxis("电影数量", hist_counts.tolist()) .set_global_opts( title_opts=opts.TitleOpts(title="上映电影评分分布"), yaxis_opts=opts.AxisOpts(name="数量"), ) ) bar_hist.render("score_distribution.html")

pd.cut做分箱,value_counts()统计各箱数量,reindex(labels)保证箱子顺序不乱。这个方案比直接用现成的直方图库更可控,因为箱子边界由你定,不会被库的默认算法带偏。评分不足的新片我选择先过滤,否则dropna()会把这些空值排除在统计之外。

类型占比饼图则是另一个维度。把每部电影的类型拆开统计,能回答“市场更偏爱哪种类型”的问题。要注意的是电影类型是多值字段,一部电影可能同时标着“喜剧”和“剧情”,直接按整字段 groupby 会把组合类型当成单独一类,饼图碎成几十块没法读。常见做法是先拆分再统计:

from collections import Counter genre_counter = Counter() for genres in df["genre"].dropna(): for g in genres.split("/"): # 假设字段格式是 "剧情/喜剧/爱情" genre_counter[g.strip()] += 1 pie = ( Pie() .add( "类型", [list(z) for z in zip(genre_counter.keys(), genre_counter.values())], radius=["40%", "70%"], # 环形图效果 ) .set_global_opts(title_opts=opts.TitleOpts(title="影片类型分布")) .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%")) ) pie.render("genre_pie.html")

radius=["40%", "70%"]是环形图的核心参数,内径 40% 外径 70%,中间留白可以放标题或总数,视觉效果比实心饼图更清爽。formatter="{b}: {d}%"中的{b}是类别名,{d}是百分比,比默认的数值标签更利于阅读。类型分布图最有意思的发现通常是:喜剧片数量最多,但平均票房不高;悬疑片数量少,单部均值却靠前。这种对比直接指向选题方向:市场缺的不是类型,是同质化。

4.5 组合图表:用 Grid 和 Tab 把多张图拼成一份报告

单张图画得再漂亮,零散地扔给导师或同事看,都显得单薄。pyecharts 提供了两种组合方式:Grid用于同画面分区布局,Tab用于多页签切换。

from pyecharts.charts import Grid, Line, Bar grid = Grid() grid.add(bar, grid_opts=opts.GridOpts(pos_top="10%", pos_left="15%")) grid.add(line, grid_opts=opts.GridOpts(pos_top="55%", pos_left="15%")) grid.render("combined_dashboard.html")

Grid把上一节生成的barline叠在同一个 HTML 页面的上下两个区域,pos_top控制每个子图的纵向位置。左右分栏则改pos_leftTab的用法更简单,适合做多页签报告:

from pyecharts.charts import Tab tab = Tab() tab.add(bar, "票房TOP15") tab.add(line, "每日走势") tab.add(pie, "类型分布") tab.render("full_report.html")

打开生成的 HTML,浏览器顶部会出现三个标签页,点击切换。这个模式非常适合课程设计答辩场景:一页一个分析主题,翻页逻辑清晰,不用现场来回开文件。到这里,一个完整的票房评分可视化项目的主体已经成型了。

5. 避坑指南:pyecharts 项目里最常翻车的六个地方

5.1 图表和代码里的中文全部变成方块

现象:浏览器打开 HTML,标题、坐标轴、图例全是“□□□”或乱码;代码里含中文注释的文件在其他机器上跑直接报SyntaxError

原因:pyecharts 渲染出的 HTML 依赖浏览器的字体渲染,如果页面没有声明 UTF-8 或者系统缺少中文字体,就会出现方块。代码层面通常是 Python 文件本身保存的编码不是 UTF-8。

解决:HTML 层面,pyecharts 默认模板已经带了<meta charset="utf-8">,一般不用管。系统层面,Windows 和 mac 的现代浏览器都自带中文字库,真出现方块就检查操作系统的字体设置,安装“微软雅黑”或“苹方”即可。代码层面,所有.py文件统一用 UTF-8 保存,不要用系统默认的 GBK。

5.2 图表数据点太多,页面卡到拖不动

现象:把一整年的票房日报全部画进折线图,三百多个点,页面滚动还行,但鼠标悬停时卡顿明显。

原因:pyecharts 基于 ECharts,尾部超过一定数量后,渲染和事件绑定的开销会指数上升。三百个点其实还没到极限,但画三五千个点时几乎必卡。

解决:聚合代替全量。日数据可以先按周聚合,折线图的横轴从 365 个点变成 52 个点,趋势完全保留。如果确实需要每个点都显示,就把tooltip的触发方式从axis改为item,减少同时渲染的提示框数量。

5.3 柱状图的 X 轴标签叠成黑压压一片

现象:十五部电影的片名全部挤在 X 轴底部,互相遮挡,只能看到最后一个字。

原因:片名词长超过图表的单轴空间,而标签方向是水平的,就会重叠。这个问题在竖向柱状图里几乎必现,在横向柱状图里则不会出现。

解决:比如用来画片名,无脑选横向柱状图,把片名放到 Y 轴。但如果业务上必须竖向,设置axislabel_opts=opts.LabelOpts(rotate=45)让标签旋转四十五度,或者增大图表高度set_global_opts(height="600px")。最省事的一条经验:优先改图表方向,其次改宽度,旋转标签是最后手段。

5.4 折线图的 X 轴时间顺序全乱

现象:日期显示为01-0301-1001-05,走势线左右乱跳,完全不成形。

原因:日期列是字符串,add_xaxis()按字符串排序,而字符串排序里"01-10"小于"01-03",自然乱序。数据清洗阶段没有把日期转成datetime类型,这是清洗不到位的直接后果。

解决:清洗阶段就做pd.to_datetime(),画图前再按日期sort_values()升序排一遍。如果 X 轴仍要显示成MM-DD格式,用dt.strftime("%m-%d")转换字符串,但排序必须发生在转换之前。

5.5 上传到服务器后图片不显示

现象:本地打开 HTML 一切正常,部署到服务器或发给别人后,图表区域空白,控制台报ECharts is not defined

原因:pyecharts 的 HTML 默认通过 CDN 加载 ECharts 的 JS 文件,目标机器无法访问外网时,图表就渲染不出来。这属于环境依赖问题,不是代码逻辑问题。

解决:本地生成时就强制内嵌脚本,调用bar.render("chart.html")之后,手动检查生成的 HTML 里<script>标签的 src 是https://cdn.jsdelivr.net开头还是本地路径。要彻底离线可用,把 pyecharts 的模板配置改成下载 ECharts 到本地再引用,或者直接用bar.render("chart.html")生成后用 Python 脚本批量替换 CDN 地址为本地路径。最简单的方案是把 HTML 文件发给对方时同时把 ECharts 的 JS 文件放旁边,但这会把整个过程搞得笨重。我的习惯是:演示场景提前确认对方能访问 CDN,不能就直接截图输出图片。

5.6 评分数据缺失导致统计图少一块

现象:评分分布直方图只有六七个柱子,明显缺失低分段,看了原始数据发现多部片子没有评分。

原因:新片上映前三天评分数不足,平台不展示分数,接口返回空值。直接dropna()删掉这些行会让样本减少,而且删掉的大多是刚上映的片子,导致样本偏向老片。

解决:分场景处理。画评分分布图时,明确标注“统计周期内已开分的影片”,把 NaN 行剔除没问题,但要在图下面用文字说明;画票房榜时不要删,因为票房数据完整,评分只是辅助信息。更稳妥的做法是单独建一个has_score布尔列,分析时按需过滤,而不是物理删除行。

6. 从作业到作品:用定时任务和 Flask 把图表变成可视化报告

图表都渲出来之后,下一步是让整个分析流程自动化。常见做法是写一个run.py把爬取、清洗、出图、渲染四步串起来,然后用系统定时任务每天跑一次。Windows 用任务计划程序,macOS 用 launchd,核心配置都一样:指定 Python 解释器的绝对路径和工作目录,然后设置触发时间。这样每天凌晨两点自动抓前一天数据、更新图表,第二天早上打开 HTML 就是新鲜报告。

给 HTML 包一层简单界面也是个值得做的方向。用 Flask 起一个本地服务,把render()生成的 HTML 嵌到模板里,访问http://localhost:5000就能在一个页面里切换所有图表。相比直接打开静态文件,这样做的好处是可以加交互控件——比如下拉选择档期、日期范围筛选,所有筛选在 Python 端重新聚合数据再出新图。做成这样,课程设计的答辩评审会明显感觉“这是个系统”而不是“一堆脚本”。

免费源码库里这种题材的完整项目很多,但你拿到的多数版本能直接运行、数据却是死的。真正的价值是把数据更新这步做成活的,每天有新数据进来,图表就会自动长出新结论。我自己做完这个项目后养成的一个习惯是:画图前先花几十秒想清楚这张图要给谁看、要回答什么问题,想不清楚就不画。图表数量多不等于分析质量高,一张能让人盯着看三十秒的散点图,超过五张没人细看的柱状图。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 12:42:11

AN41908聚焦驱动开发实战:从寄存器到设备树的完整指南

简介&#xff1a;AN41908自动聚焦芯片的SPI驱动源码&#xff0c;专为需要精确控制镜头对焦的嵌入式开发场景设计。该驱动承担操作系统与AN41908之间的指令翻译&#xff1a;初始化时配置SPI时钟频率与数据模式&#xff0c;运行中通过读写寄存器下发聚焦命令并解析位置反馈&#…

作者头像 李华
网站建设 2026/9/23 12:40:38

ASME Y14.5-2009 中文全译本解读:GDT 基准、公差与检具设计实战

简介&#xff1a;ASME Y14.5-2009中文版是机械设计与制造领域尺寸与公差标注的权威标准译本&#xff0c;面向机械工程师、制图人员、质检及工艺技术人员&#xff0c;也适合高校机械专业师生作为工程图样规范参考。该标准为ASME Y14.5M-1994(R2004)的更新版本&#xff0c;系统规…

作者头像 李华
网站建设 2026/9/23 12:40:32

PaddleOCR 2.0实战指南:从文本检测到部署避坑全解析

简介&#xff1a;PaddleOCR 2.0 是基于飞桨深度学习框架的中英文光学字符识别工具&#xff0c;面向需要把图片、截图或扫描件中的文字批量提取为可编辑文本的办公人员、开发者和内容整理者。它支持本地单机运行&#xff0c;无需联网即可完成延时截图识别、图片旋转与镜像识别、…

作者头像 李华
网站建设 2026/9/23 12:39:52

Windows下cuDNN 8.8.0与CUDA 11.x精准安装指南

简介&#xff1a;本资源为 NVIDIA cuDNN 8.8.0 for Windows x64 官方预编译库包&#xff0c;专为使用 CUDA 11.x 版本进行深度学习开发的 Windows 开发者设计&#xff0c;适用于 PyTorch、TensorFlow 等框架的 GPU 加速环境部署与本地调试。压缩包共含 31 个文件&#xff0c;涵…

作者头像 李华
网站建设 2026/9/23 12:39:00

Copula与变分贝叶斯在几何误差建模中的MATLAB实践

简介&#xff1a;这份Matlab代码包面向机器学习、统计推断方向的研究者与进阶学习者&#xff0c;核心复现论文“Copula Variational Bayes inference via information geometry”中的算法&#xff0c;目标是在数据存在非线性、非对称依赖关系时&#xff0c;用Copula构造灵活的变…

作者头像 李华