微博舆情分析毕设全链路:Python爬虫与情感分析实战

发布时间:2026/10/11 22:24:58
微博舆情分析毕设全链路:Python爬虫与情感分析实战
简介这是一套面向计算机专业学生与Python初学者的微博舆情分析可视化毕业设计项目围绕爬虫采集、情感分析与数据可视化三大模块展开适合用作毕业设计、期末大作业或课程设计参考。资源包共146个文件约3.85MB包含19个py源码文件、14个html页面、21个js脚本与7个css样式另有csv数据样本、sql建表脚本及图片素材前后端结构完整代码附有注释新手也能读懂。项目已积累698人学习下载功能涵盖微博数据抓取、评论情感倾向判断与图表展示界面美观、操作简单、部署便捷。下载后可获得一套可直接运行的完整方案便于快速理解爬虫与情感分析的实现思路并在此基础上进行二次开发或功能扩展对需要高分毕设的同学具有较高参考价值。1. 微博舆情分析毕设怎么选从爬虫到情感分析的全链路拆解做计算机毕业设计选一个能跑通、能演示、能写论文的题目比选一个听起来高大上的题目重要得多。微博舆情分析可视化系统就是这样一个典型它把 Python 爬虫、中文情感分析、数据可视化和 Web 前端串成一条完整链路既有技术深度又有直观的展示效果答辩时老师一眼就能看懂你在做什么。这套资源包含爬虫脚本、情感分析模块、可视化大屏和前端页面代码带注释部署简单适合作为毕业设计、期末大作业或课程设计使用。如果你正在纠结选题或者已经选了舆情分析但不知道从哪下手这套东西能帮你省掉大量试错时间。2. 环境搭建与数据采集把微博数据抓下来的完整流程2.1 运行环境与依赖安装拿到源码包后第一件事不是急着跑main.py而是先把环境理顺。这套系统基于 Python 3.8 开发常见做法是用 conda 或 venv 建一个独立环境避免和你机器上已有的包版本打架。依赖主要集中在爬虫、数据处理和可视化三块requests、lxml、pandas、jieba、snownlp、flask、pyecharts。如果你用的是 Anaconda直接pip install就行如果网络环境不稳定换国内镜像源。# 创建虚拟环境推荐 Python 3.8 conda create -n weibo_spider python3.8 conda activate weibo_spider # 安装核心依赖指定国内镜像加速 pip install requests lxml pandas jieba snownlp flask pyecharts -i https://pypi.tuna.tsinghua.edu.cn/simple # 如果 lxml 安装报错先装 wheel 再装 lxml pip install wheel pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple这里有几个参数值得注意requests负责发 HTTP 请求lxml做 XPath 解析jieba用于中文分词snownlp是轻量级中文情感分析库flask提供 Web 服务pyecharts生成可视化图表。版本上不建议追新snownlp和pyecharts的新版本 API 有变动用pip install snownlp0.12.3 pyecharts1.9.1更稳。装完之后用python -c import snownlp; print(snownlp.__version__)验证一下能打印出版本号就说明环境通了。2.2 爬虫脚本结构与请求头配置这套资源的爬虫部分不是简单的requests.get一把梭而是分了几个模块spider.py负责发请求和翻页parser.py负责解析 HTML 提取字段pipeline.py负责清洗和存 CSV。项目正文里提到的target.csv、articleData.csv、articleComments.csv就是爬虫跑完后落地的数据文件分别对应目标微博信息、文章数据和评论数据。# spider.py 核心片段请求头与翻页逻辑 import requests import time import random HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, Cookie: 你的Cookie值, # 从浏览器开发者工具复制 Referer: https://weibo.com/ } def fetch_page(url, max_retry3): for i in range(max_retry): try: resp requests.get(url, headersHEADERS, timeout10) if resp.status_code 200: return resp.text except requests.RequestException as e: print(f第{i1}次请求失败: {e}) time.sleep(random.uniform(2, 5)) # 随机延时降低被封风险 return None这段代码的关键在HEADERS里的Cookie和User-Agent。Cookie是你登录微博后浏览器里存的身份凭证不填的话很多页面返回的是登录墙而不是数据。User-Agent伪装成正常浏览器避免被识别为脚本。time.sleep(random.uniform(2, 5))是血泪经验固定间隔请求很容易触发频率限制随机延时能显著降低翻车概率。max_retry3是重试次数超过三次就放弃避免死循环。2.3 数据字段设计与 CSV 落地爬下来的数据不能直接扔进分析模块得先定义好字段结构。这套资源里articleData.csv的字段一般包括article_id、title、content、publish_time、author、reposts_count、comments_count、attitudes_count。articleComments.csv则包含comment_id、article_id、comment_text、comment_time、like_count。字段设计的原则是能唯一标识一条记录能支撑后续的情感分析和可视化维度。# pipeline.py 数据清洗与落地 import pandas as pd import re def clean_text(text): if not isinstance(text, str): return text re.sub(r.*?, , text) # 去 HTML 标签 text re.sub(r[\u200b-\u200f], , text) # 去零宽字符 text re.sub(r\s, , text).strip() # 合并空白 return text def save_to_csv(data_list, filename): df pd.DataFrame(data_list) df[content] df[content].apply(clean_text) df.drop_duplicates(subset[article_id], inplaceTrue) df.to_csv(filename, indexFalse, encodingutf-8-sig) print(f已保存 {len(df)} 条记录到 {filename})clean_text里三个正则分别处理 HTML 标签、零宽字符和多余空白。零宽字符是微博反爬的一个小手段肉眼看不见但会影响分词和情感分析结果。encodingutf-8-sig是为了 Excel 打开 CSV 不乱码这个细节很多新手会忽略答辩演示时打开文件一片乱码就很尴尬。drop_duplicates按article_id去重防止翻页时重复抓取。3. 情感分析与可视化从文本到图表的落地实现3.1 基于 SnowNLP 的情感打分与阈值调优情感分析这块这套资源用的是 SnowNLP一个基于朴素贝叶斯的中文情感分析库。它的sentiments属性返回 0 到 1 之间的浮点数越接近 1 表示越正面越接近 0 表示越负面。但直接拿默认阈值 0.5 来分类效果往往一般因为微博文本口语化严重反讽、缩写、表情符号都会干扰判断。from snownlp import SnowNLP import pandas as pd def analyze_sentiment(text): if not text or len(text) 3: return None s SnowNLP(text) score s.sentiments if score 0.6: label 正面 elif score 0.4: label 负面 else: label 中性 return pd.Series({score: score, label: label}) df pd.read_csv(articleComments.csv) df[[score, label]] df[comment_text].apply(analyze_sentiment) df.to_csv(comments_with_sentiment.csv, indexFalse, encodingutf-8-sig) print(df[label].value_counts())这里把阈值从默认的 0.5 调成了 0.6 和 0.4目的是给中性留出更宽的区间。微博评论里大量“哈哈”“转发微博”“//某某”这类文本SnowNLP 给出的分数往往在 0.45 到 0.55 之间如果硬按 0.5 切会被强行分到正面或负面导致统计失真。调成 0.6/0.4 之后中性样本占比会明显上升更符合实际分布。如果你想让结果更细可以把score保留下来做连续变量画核密度图或者箱线图比单纯饼图更有说服力。3.2 Pyecharts 可视化大屏的图表配置可视化部分用的是 Pyecharts生成 HTML 文件后可以直接在浏览器打开也可以嵌入 Flask 模板。这套资源里常见的图表包括情感分布饼图、评论时间折线图、热门关键词词云、转发评论点赞柱状图。每种图表的配置项不一样但核心逻辑都是“把 DataFrame 转成 list 再喂给图表对象”。from pyecharts.charts import Pie, Line, Bar, WordCloud from pyecharts import options as opts from pyecharts.globals import ThemeType # 情感分布饼图 sentiment_counts df[label].value_counts() pie ( Pie(init_optsopts.InitOpts(themeThemeType.LIGHT)) .add(, [list(z) for z in zip(sentiment_counts.index, sentiment_counts.values)]) .set_global_opts(title_optsopts.TitleOpts(title评论情感分布)) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c} ({d}%))) ) pie.render(sentiment_pie.html) # 评论时间折线图 df[comment_time] pd.to_datetime(df[comment_time]) time_counts df.groupby(df[comment_time].dt.date).size() line ( Line() .add_xaxis([str(d) for d in time_counts.index]) .add_yaxis(评论数, time_counts.values.tolist(), is_smoothTrue) .set_global_opts( title_optsopts.TitleOpts(title评论时间趋势), xaxis_optsopts.AxisOpts(name日期), yaxis_optsopts.AxisOpts(name评论数) ) ) line.render(comment_trend.html)ThemeType.LIGHT是主题配置换成DARK就是暗色系答辩演示时暗色系在投影仪上更清晰。is_smoothTrue让折线变平滑视觉上更舒服。formatter{b}: {c} ({d}%)控制饼图标签显示名称、数值和百分比。render出来的 HTML 文件可以单独打开也可以放到 Flask 的templates目录里用render_template渲染。注意 Pyecharts 1.x 和 0.x 的 API 差异很大网上很多老教程用的是overlap和grid在新版本里已经废弃了照着抄会报错。3.3 Flask 后端与前端页面的对接这套资源的 Web 部分用 Flask 做后端前端页面包括main.css、main1.css、main2.css、main3.css、css2.css、backend.css、backend-plugin.min.css等样式文件。后端负责读取 CSV、调用情感分析、生成图表数据前端负责展示。对接方式一般是 Flask 提供 JSON 接口前端用 ECharts 或 Pyecharts 渲染。# app.py 核心路由 from flask import Flask, render_template, jsonify import pandas as pd app Flask(__name__) app.route(/) def index(): return render_template(index.html) app.route(/api/sentiment) def api_sentiment(): df pd.read_csv(comments_with_sentiment.csv) counts df[label].value_counts().to_dict() return jsonify({ labels: list(counts.keys()), values: list(counts.values()) }) app.route(/api/trend) def api_trend(): df pd.read_csv(comments_with_sentiment.csv) df[comment_time] pd.to_datetime(df[comment_time]) trend df.groupby(df[comment_time].dt.date).size() return jsonify({ dates: [str(d) for d in trend.index], counts: trend.values.tolist() }) if __name__ __main__: app.run(debugTrue, host0.0.0.0, port5000)debugTrue在开发阶段很有用改完代码自动重启但部署到服务器时要关掉否则有安全风险。host0.0.0.0让局域网内其他设备也能访问方便你用手机或平板演示。前端拿到 JSON 后用fetch或axios请求接口再把数据塞进 ECharts 的option里。这套前后端分离的写法比直接在 Flask 模板里渲染 Pyecharts 更灵活也更容易改样式。4. 避坑与常见问题排查4.1 Cookie 失效导致爬虫返回登录页现象爬虫跑了几页之后返回的 HTML 里全是“登录”“注册”字样解析出来的数据为空。原因微博的 Cookie 有有效期通常几小时到几天不等过期后请求会被重定向到登录页。解决重新从浏览器开发者工具里复制最新 Cookie替换HEADERS里的值。更稳妥的做法是把 Cookie 存在单独的文件里每次运行前手动更新避免硬编码在代码里提交到 Git。4.2 SnowNLP 首次运行报错或速度极慢现象第一次调用SnowNLP(text).sentiments时卡住或者报LookupError。原因SnowNLP 首次运行需要加载内置语料模型如果安装不完整或路径有问题就会失败。解决卸载后重装pip install --force-reinstall snownlp0.12.3或者手动下载sentiment.marshal文件放到snownlp/sentiment/目录下。速度慢是因为逐条分析常见优化是先用jieba分词过滤掉短文本再批量处理。4.3 Pyecharts 图表在浏览器里空白现象render出来的 HTML 打开后一片空白或者只显示标题没有图形。原因Pyecharts 依赖的 JS 文件默认从 CDN 加载网络不通时图表渲染不出来。解决在InitOpts里指定js_host为本地路径或者用pyecharts提供的snapshot功能生成静态图片。另一个常见原因是数据格式不对比如add_xaxis传了 DataFrame 而不是 list图表会静默失败。4.4 CSV 文件用 Excel 打开乱码现象articleData.csv用 Excel 打开后中文全是乱码。原因Python 默认写 CSV 用utf-8编码Excel 在中文 Windows 下默认用 GBK 解码。解决保存时加encodingutf-8-sig这个编码会在文件头写入 BOMExcel 能正确识别。如果已经生成了乱码文件用记事本打开另存为 ANSI 编码也能救回来。4.5 Flask 端口被占用或无法访问现象运行app.py报Address already in use或者浏览器访问127.0.0.1:5000没反应。原因5000 端口被其他程序占用或者 Flask 只监听了127.0.0.1导致局域网设备访问不了。解决换端口app.run(port5001)或者用lsof -i:5000找到占用进程杀掉。局域网访问要改成host0.0.0.0同时检查防火墙有没有放行。5. 进阶技巧让情感分析结果更经得起答辩追问5.1 用 SnowNLP 做细粒度情感倾向对比默认的三分类正面/中性/负面在答辩时容易被问“你怎么定义正面”。一个更稳的做法是保留原始情感分数做两组对比一组是目标微博的评论情感分布另一组是同期同类话题的评论情感分布。用箱线图展示两组分数的中位数和四分位距比饼图更有说服力。import matplotlib.pyplot as plt import seaborn as sns # 假设有两组数据target_scores 和 baseline_scores plt.figure(figsize(8, 5)) sns.boxplot(data[target_scores, baseline_scores], paletteSet2) plt.xticks([0, 1], [目标话题, 对照话题]) plt.ylabel(情感分数) plt.title(情感分数分布对比) plt.savefig(sentiment_compare.png, dpi150, bbox_inchestight)boxplot能直观看出两组数据的集中趋势和离散程度。如果目标话题的中位数明显低于对照话题说明负面情绪更重这个结论比“正面 30%、负面 40%”更有分析深度。dpi150保证图片清晰度bbox_inchestight去掉多余白边直接插进论文里不用再裁剪。5.2 关键词提取与词云参数调优词云是舆情分析里最抓眼球的图表但默认参数出来的词云往往一堆“的”“了”“是”这种无意义词。常见做法是用jieba.analyse.extract_tags做 TF-IDF 关键词提取再喂给 WordCloud。import jieba.analyse from wordcloud import WordCloud # 提取 Top 100 关键词 text_all .join(df[comment_text].dropna().tolist()) keywords jieba.analyse.extract_tags(text_all, topK100, withWeightTrue) # 构建词频字典 freq_dict {word: weight for word, weight in keywords} # 生成词云 wc WordCloud( font_pathsimhei.ttf, # 中文字体路径不设会显示方块 background_colorwhite, width1200, height800, max_words100, colormapviridis ) wc.generate_from_frequencies(freq_dict) wc.to_file(wordcloud.png)font_path是中文字体的坑不指定的话所有汉字都是方块。Windows 下一般用C:/Windows/Fonts/simhei.ttfLinux 下需要自己下载一个中文字体放到项目目录。colormapviridis是配色方案换成Reds或Blues更适合正式论文。max_words100控制显示词数太多会挤在一起看不清。5.3 答辩演示前的检查清单答辩前我一般会强制走一遍这个流程先确认articleData.csv和articleComments.csv里有数据且字段完整再跑一遍情感分析确认comments_with_sentiment.csv生成成功然后启动 Flask 确认首页能打开、图表能加载最后用手机连同一局域网访问一遍确保演示时不会因为网络问题翻车。从那以后我每次交付前都会把这条链路完整跑一遍哪怕代码没改过。希望帮到你。本文还有配套的精品资源点击获取