十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Python实现影视预告评论情感分析与可视化实战

用Python实现影视预告评论情感分析与可视化实战 最近《米尔扎布尔》Mirzapur电影版正式预告发布的消息让很多追剧人瞬间来了精神。作为印度 Amazon Prime Video 上最具辨识度的犯罪剧集之一这部剧凭借硬核的暴力美学、家族权力斗争和密集的剧情反转积累了大量忠实观众。不过在 CSDN 上除了聊预告本身我们其实还可以换一个角度怎么把一个影视热点变成一次有意思的数据分析实战。这篇文章不打算做影评而是围绕“影视预告热度分析”这个方向完整演示一套基于 Python 的数据处理流程。即使你完全不了解《米尔扎布尔》也不影响阅读。核心内容包括数据从哪来、怎么清洗、情感分析怎么做、结果如何可视化以及在实际操作中最容易踩的坑。项目代码可以直接复制运行适合想通过真实场景练手的数据分析初学者也适合正在做影视内容相关产品、需要设计热度监控方案的开发同学。1. 从预告发布聊起影视热度分析到底在分析什么1.1 一部剧的预告片能带来哪些可量化数据预告片发布本质上是一次内容营销事件。围绕这个事件会产生非常多的数据而且每一类数据的分析价值都不一样。第一类是播放数据。预告片在 YouTube、Prime Video 等平台上的播放量、完播率、平均观看时长能直接反映观众对预告内容的接受程度。播放量高但完播率低说明标题和封面足够吸引人但正片内容没能留住观众这往往意味着预告片剪辑节奏或核心看点呈现出了问题。第二类是互动数据。点赞数、点踩数、收藏数、分享数、评论数这些指标比播放数量更能反映观众的真实情绪。尤其是指踩与评论区的措辞很多时候比平台内置的评分更早暴露口碑趋势。第三类是舆情文本数据。评论区、社交平台讨论帖、新闻稿标题这些都是非结构化文本。它们蕴藏着观众最关心的信息点比如某个角色的回归、剧情尺度、拍摄质感、与原剧的延续性等等。用自然语言处理技术对这些文本做情感分析就能得到一张“观众整体情绪随时间变化”的曲线。所以影视热度分析并不是一个简单的“读播放量”的动作而是一套从数据采集、清洗、建模到可视化的完整数据工程流程。本文后续讲解全部围绕第三条线——评论文本分析展开这也是数据量最大、最值得做的部分。1.2 为什么适合用 Python 来做Python 在数据处理领域有天然优势。pandas 提供了强大的 DataFrame 结构可以快速完成数据清洗、筛选、聚合jieba、SnowNLP 等库能处理文本分词和基础情感判断wordcloud 能把高频词变成词云图matplotlib、pyecharts 能输出用于汇报展示的图表。更关键的是Python 的代码表达能力很强。一个 200 行之内的脚本就能完成从原始评论到可视化图表的全链路处理。这对于个人开发者、产品运营和数据小白来说学习成本非常低。而且这套流程并不只适用于《米尔扎布尔》预告片你可以把它平移到任何一个影视作品、产品发布会、体育赛事热点上属于非常通用的分析能力。2. 环境准备与项目结构2.1 运行环境与依赖版本本文示例代码以 Python 3.9 为基础建议使用独立的虚拟环境避免污染系统 Python。操作系统方面Windows、macOS、Linux 都支持。由于涉及中文字体显示Windows 环境下使用系统自带的微软雅黑即可macOS 可以使用系统中文字体。需要安装的依赖库如下pip install pandas2.0.3 pip install matplotlib3.7.2 pip install wordcloud1.9.2 pip install jieba0.42.1版本不强制锁定如果你已经安装了更新版本通常也能正常运行。如果安装wordcloud时遇到编译问题在 Windows 上建议直接下载对应 Python 版本的 whl 文件安装或者使用 Anaconda 环境来规避编译依赖。2.2 项目目录结构为了便于理解和后续扩展我们按照下面的目录结构组织项目mirzapur_analysis/ ├── data/ │ ├── raw/ │ │ └── comments.json │ └── cleaned/ │ └── comments_clean.csv ├── output/ │ ├── sentiment_pie.png │ ├── trend_line.png │ └── wordcloud.png ├── src/ │ ├── clean.py │ ├── sentiment.py │ └── visualize.py └── requirements.txtdata/raw存放原始评论文本格式为 JSONdata/cleaned存放清洗后的结构化数据output保存可视化图片src下按职责拆分代码文件。在实际项目中原始数据一般来自评论接口或爬虫这里为了演示我们自己构造一份包含中英文评论的 JSON 数据。模拟数据能让你更专注地理解处理思路后续接入真实数据时只需要替换数据读取部分即可。3. 数据的合法获取与字段设计3.1 评论数据从哪里来很多同学拿到一个分析需求第一反应就是“写爬虫去抓”。但对于影视评论来说优先考虑的应该是官方接口。YouTube 对每条视频提供了 Data API v3通过commentThreads.list可以获取视频下的评论列表。Amazon Prime Video 本身没有公开的评论 API不过在公开讨论区、IMDb 评论区也有大量内容。IMDb 提供了非商用数据集但评论明细的实时获取还是需要遵守其服务条款。这里的核心原则是优先使用官方渠道注意 API 调用频率限制不要对目标平台造成访问压力。如果是商业项目务必确认数据使用是否合规避免因抓取行为带来法律风险。3.2 数据字段设计无论从哪个渠道拿数据最终我们都需要把数据结构化。建议至少保留以下字段字段名类型说明comment_idstring评论唯一IDuser_namestring用户名脱敏处理textstring评论文本published_atdatetime发布时间like_countint点赞数reply_countint回复数sourcestring数据来源平台comment_id用于去重published_at用于后续的时间趋势分析like_count可以作为情感权重的参考——一个高赞的负面评论和一条无人问津的负面评论对整体口碑的影响完全不同。本文演示用的模拟数据就是按照这个结构设计的。3.3 构建一份可用的模拟数据集在data/raw/comments.json中写入如下内容[ {comment_id: 001, user_name: user_01, text: Great trailer, cant wait for the movie!, published_at: 2024-05-20 08:05:00, like_count: 128, reply_count: 12, source: youtube}, {comment_id: 002, user_name: user_02, text: 终于等到电影版了预告片节奏很燃期待上映, published_at: 2024-05-20 08:12:00, like_count: 256, reply_count: 23, source: prime}, {comment_id: 003, user_name: user_03, text: Boring, nothing special about this teaser., published_at: 2024-05-20 08:20:00, like_count: 3, reply_count: 0, source: youtube}, {comment_id: 004, user_name: user_04, text: 豆瓣肯定会炸这尺度看着比剧版还猛。, published_at: 2024-05-20 08:35:00, like_count: 189, reply_count: 16, source: douban}, {comment_id: 005, user_name: user_05, text: 没有任何一个角色是安全的这才是 Mirzapur 的灵魂, published_at: 2024-05-20 08:44:00, like_count: 357, reply_count: 30, source: twitter}, {comment_id: 006, user_name: user_06, text: 节奏真快两分钟的预告信息量拉满, published_at: 2024-05-20 09:02:00, like_count: 96, reply_count: 5, source: bilibili}, {comment_id: 007, user_name: user_07, text: Again a glorification of violence, not interested., published_at: 2024-05-20 09:15:00, like_count: 21, reply_count: 4, source: youtube}, {comment_id: 008, user_name: user_08, text: 如果剧情像第三季一样拖沓电影版也救不回来, published_at: 2024-05-20 09:30:00, like_count: 45, reply_count: 9, source: weibo} ]这份数据包含了英语、中文混合评论覆盖正面、负面、中性不同情感倾向。由于是模拟数据字段结构完全由我们自己掌控你可以随时追加更多评论来观察分析结果的变化。4. 核心实现从清洗到情感分析4.1 数据读取与基础清洗原始评论不能直接用于分析因为里面夹杂着大小写差异、表情符号、URL、提及等噪声。清洗的目的就是把文本整理成“干净、可计算”的格式。在src/clean.py中写入以下代码import json import re import pandas as pd def load_data(file_path): with open(file_path, r, encodingutf-8) as f: data json.load(f) df pd.DataFrame(data) df[published_at] pd.to_datetime(df[published_at]) return df def clean_text(text): # 转小写便于统一英文大小写 text text.lower() # 移除 URL text re.sub(rhttp\S|www\.\S, , text) # 移除 提及 text re.sub(r\w, , text) # 移除多余空白字符 text re.sub(r\s, , text).strip() return text def clean_data(df): df[clean_text] df[text].apply(clean_text) # 去掉空文本 df df[df[clean_text] ! ] # 按评论ID去重保留第一条 df df.drop_duplicates(subsetcomment_id, keepfirst) return df if __name__ __main__: df load_data(../data/raw/comments.json) df clean_data(df) df.to_csv(../data/cleaned/comments_clean.csv, indexFalse, encodingutf-8-sig) print(df.head())清洗公式中有几个值得注意的细节。pd.to_datetime会把字符串时间统一转换为 pandas 的 datetime 类型方便后续按小时、日、周聚合。re.sub(rhttp\S|www\.\S, , text)使用正则匹配并移除 URL避免链接干扰分词和情感判断。utf-8-sig编码是为了让 CSV 文件在 Excel 中打开时中文不乱码。第一次运行前检查一下路径确保当前工作目录在src/下或者使用绝对路径。控制台如果输出前五行数据说明清洗流程已经跑通。4.2 在清洗基础上增加字段清洗后的数据只能算“机器可读”还称不上“分析友好”。在实际项目中我们通常还会增加两个标准字段df[length] df[clean_text].str.len() df[word_count] df[clean_text].str.split().apply(len)length表示评论字符数word_count表示分词后的词数。这两个指标可以帮我们发现异常评论。例如 500 字以上的超长评论通常是粉丝在写详细观后感系统崩溃式的高频刷屏文本也可能是机器产生的垃圾评论。更严谨的做法是建立评论质量规则比如“命中固定广告词列表的评论直接过滤”“连续重复字符超过 5 个的评论打标”。这些规则可以沉淀成独立的filter_rules.py文件而不是全部堆在清洗脚本里便于后期维护和更新。4.3 情感分析的轻量实现方案提到情感分析很多同学第一反应是用机器学习或者大模型。但对于评论数据量在几百到几万条的场景基于情感词典的轻量方案完全够用而且部署成本极低、运行速度快、结果可解释性强。核心思路是维护两个词表积极词表和消极词表。对每条评论统计命中积极词和消极词的次数再用公式计算情感得分sentiment_score (positive_num - negative_num) / (positive_num negative_num 1)分母加 1 是为了防止除零。得分范围落在 -1 到 1 之间大于 0 判定为正面小于 0 判定为负面等于 0 判定为中性。在src/sentiment.py中写入import pandas as pd POSITIVE_WORDS { great, amazing, excellent, good, awesome, love, 期待, 燃, 精彩, 震撼, 喜欢, 经典, 不错, 拉满, 灵魂 } NEGATIVE_WORDS { bad, boring, terrible, awful, worst, hate, 拖沓, 失望, 垃圾, 无聊, 救不回来 } def get_sentiment_scores(text): words text.split() pos_count sum(1 for w in words if w in POSITIVE_WORDS) neg_count sum(1 for w in words if w in NEGATIVE_WORDS) score (pos_count - neg_count) / (pos_count neg_count 1) return pos_count, neg_count, round(score, 4) def label_sentiment(score): if score 0: return 正面 elif score 0: return 负面 return 中性 def analyze_sentiment(df): df[[pos_num, neg_num, sentiment_score]] df[clean_text].apply( lambda x: pd.Series(get_sentiment_scores(x)) ) df[sentiment_label] df[sentiment_score].apply(label_sentiment) return df此处对中文使用了split()按空格分割。但中文文本没有天然空格split()会把整句当作一个词导致词典匹配失效。所以中文评论必须经过分词处理。在项目里加上分词增强逻辑import jieba def tokenize_text(text): seg_list jieba.lcut(text) return .join(seg_list)清洗之后、情感分析之前先对中文文本分词再重新拼接成以空格分隔的文本。这样后续split()得到的每个词才有意义。由于本文模拟数据中既有英文又有中文代码里直接对clean_text做分词会出现中英混切的问题。为了演示效果更稳定建议先用一个简单规则判断文本是否包含中文再决定是否走 jieba 分词import re def is_chinese(text): return bool(re.search(r[\u4e00-\u9fa5], text)) def smart_tokenize(text): if is_chinese(text): return .join(jieba.lcut(text)) return text.lower()这种中文英文分开处理的策略在真实评论场景中非常实用。因为评论区通常是多语言混合的统一走英文分词会丢失中文语义统一走中文分词又会把英文单词拆坏。4.4 完整的主流程串联在src/main.py中把所有步骤串起来import pandas as pd from clean import load_data, clean_data, clean_text from sentiment import analyze_sentiment def main(): df load_data(../data/raw/comments.json) df clean_data(df) df[clean_text] df[clean_text].apply(smart_tokenize) df analyze_sentiment(df) print(df[[comment_id, clean_text, sentiment_score, sentiment_label]]) df.to_csv(../data/cleaned/comments_sentiment.csv, indexFalse, encodingutf-8-sig) if __name__ __main__: main()运行后控制台会输出如下格式的结果comment_id clean_text sentiment_score sentiment_label 0 001 great trailer , can t wait for the movie ! 0.5000 正面 1 002 终于 等到 电影版 了 预告片 节奏 很 燃 期待 上映 0.4000 正面值得注意的是第一条英文评论在分词后出现了can t这种被拆开的形态这是因为我们统一使用空格分词没有做英文词形还原。对于情感词典方案cant被拆开并不会影响主要内容词的匹配所以可以接受。5. 可视化和趋势解读5.1 情感分布饼图数据算出情感标签后第一步通常是看整体分布。写一个src/visualize.pyimport pandas as pd import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei] plt.rcParams[axes.unicode_minus] False def draw_sentiment_pie(df): labels df[sentiment_label].value_counts().index.tolist() counts df[sentiment_label].value_counts().tolist() plt.figure(figsize(8, 6)) plt.pie(counts, labelslabels, autopct%.1f%%, startangle90) plt.title(《米尔扎布尔》电影版预告观众评论情感分布) plt.savefig(../output/sentiment_pie.png, dpi150, bbox_inchestight) plt.close() if __name__ __main__: df pd.read_csv(../data/cleaned/comments_sentiment.csv) draw_sentiment_pie(df)这里的rcParams设置非常关键。如果不设置中文字体Matplotlib 默认字体无法显示中文图内文字会变成一堆方框。在 Linux 服务器上更是需要提前确认系统中是否安装了中文字体否则必须切换字体或改用英文标签。5.2 评论时间趋势图趋势图能看到评论热度是脉冲式的还是长尾式的。预告片刚发布时评论通常集中爆发随后快速下降这叫脉冲式热度。长尾式则说明作品有持续性讨论通常是口碑发酵的表现。def draw_trend_line(df): df[date] df[published_at].dt.date daily_count df.groupby(date).size().reset_index(namecomment_num) plt.figure(figsize(12, 5)) plt.plot(daily_count[date], daily_count[comment_num], markero) plt.title(评论数量随时间变化) plt.xlabel(日期) plt.ylabel(评论数) plt.grid(True, linestyle--, alpha0.6) plt.xticks(rotation45) plt.tight_layout() plt.savefig(../output/trend_line.png, dpi150) plt.close()视觉化的价值在于让结论一目了然。如果数据源是真实接口published_at是 UTC 时间画图前还需要统一转成东八区时间否则按天聚合会错位。5.3 词云图制作词云是另一个非常适合做“快速抓重点”的可视化形式。高频出现的角色名、场景词、评价词能直观反映观众讨论焦点。from wordcloud import WordCloud def draw_wordcloud(df): text .join(df[clean_text].tolist()) wc WordCloud( font_pathC:/Windows/Fonts/msyh.ttc, width1200, height700, background_colorwhite, colormapviridis, max_words100, collocationsFalse ).generate(text) wc.to_file(../output/wordcloud.png)font_path参数是中文词云的必选项。Windows 下使用微软雅黑路径C:/Windows/Fonts/msyh.ttcmacOS 下使用System/Library/Fonts/PingFang.ttcLinux 如果没有中文字体则需要先安装fonts-wqy-zenhei之类的字体包。当前这份只有 8 条评论的模拟数据词云效果不会太丰富。你可以往comments.json里追加几十条评论会发现词云里的高频词逐渐稳定下来变得越来越有分析价值。6. 常见报错与排查思路实测过程中最容易遇到下面几类问题。问题现象常见原因解决思路pandas 读取 JSON 报错ValueError: Expected objectJSON 文件编码或格式异常检查文件是否为 UTF-8 编码用 JSON 校验工具格式化中文显示为方框Matplotlib 未配置中文字体设置rcParams[font.sans-serif]确认系统有中文字体wordcloud安装失败缺少编译环境Windows 下下载 whl 包离线安装或使用 Anaconda评论时间全部变成 NaT时间格式不统一使用pd.to_datetime的format参数统一格式情感得分全为 0中文未分词导致词典失效对中文文本先使用 jieba 分词再匹配词表词云出现大量无意义单字collocationsFalse未设置wordcloud 2.0 以上版本默认开启二元组建议关闭如果情感分析结果看起来与直觉不符先不要急着怀疑模型优先检查词典覆盖度。词典方案的天花板由词表质量决定词表里没有“绝了”“封神”“烂尾”这些高频网络词结果自然会有偏差。生产环境中更推荐使用基于预训练模型的情感分类服务或者调用大模型 API 做结构化输出。词典方案的定位是快速验证、离线可跑、成本为零适合给中小规模数据做初筛。7. 工程化落地建议7.1 把这套流程变成定时任务在开发环境跑通之后如果要持续跟踪《米尔扎布尔》电影版后续的宣传节奏可以考虑把脚本改造成定时任务。Linux 下使用 crontabWindows 下使用计划任务。每次调度执行后把最新图片推送到内部群或报表页面就能形成一套完整的监控机制。更合理的数据流设计是采集 → 原始数据存储 → 清洗 → 入库 → 分析 → 可视化 → 输出报表每一层独立存放。清洗前的数据永远不修改清洗后的结果写入单独的表或文件方便出了问题追溯源头。7.2 注意异常处理和日志脚本化运行之后异常处理就不能只靠 print 了。至少在关键步骤加上 try-except 和日志输出。import logging logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) def main(): try: df load_data(../data/raw/comments.json) logging.info(数据加载成功共 %s 条, len(df)) except FileNotFoundError: logging.error(原始数据文件不存在请检查路径) return日志里记录“数据条数”“过滤条数”“正面/负面占比”这些关键指标有助于快速判断当次运行是否正常。比如某次运行突然发现评论数比前一天少了 90%很可能是接口返回异常或过滤规则误伤而不是热度真的下降了。7.3 安全与合规边界影视评论数据属于平台用户生成内容使用时需要注意几点。不要存储不必要的个人信息。用户名和用户 ID 只保留分析所需的最小字段能脱敏就脱敏。不要将评论数据用于商业模型训练或对外分发除非确认数据授权范围。不要高频率请求接口更不要绕过平台的风控策略。API 调用需要遵守平台速率限制建议在代码中增加随机延时或令牌桶限流。7.4 后续可以扩展的方向如果想把这套项目继续做深有四个方向可以参考。一是加入更细粒度的主题分类。不只判断情感还判断观众在讨论角色、剧情、画面、音乐还是演员需要构建一个简单的关键词规则分类器。二是引入热度指数计算。将播放量、点赞数、评论数、分享数多个维度加权形成一个综合热度分避免单一指标带来的误判。三是对接大模型做摘要。每天把新增评论喂给大模型输出“今日观众关注点”的摘要甚至可以自动生成报告减少人工整理成本。四是前端可视化。用 Flask 或者 FastAPI 把分析结果封装成 HTTP 接口再配合 ECharts 做成一个简单的数据看板这样团队其他人也能直接访问。8. 练习建议与最后的提醒如果你完全跟着本文代码做了一遍现在应该已经掌握了一套完整的评论数据处理链路从 JSON 加载、文本清洗、中英文分词、情感打分到图表输出。这套技能可以复用到很多场景不限于影视评论像应用商店用户评价、公众号留言、电商商品评论思路完全一致。建议你替换成自己关注的作品找一份真实的公开数据集把这份代码跑通。真实数据和模拟数据最大的不同在于噪声更多——长评论、表情符号、网络用语、错别字每一项都会考验清洗规则。能正确处理真实数据才算是把这套流程真正变成自己的东西。如果你正在关注《米尔扎布尔》电影版的后续动态不妨把这些分析代码跑起来等预告片正式放出后再把真实评论填进去。你可能会看到播放量、评论情绪和口碑走势之间的关系远比想象中更有意思。遇到具体报错欢迎在评论区留言交流。
返回列表