新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于Python的微博舆情分析系统:爬虫、情感分析与可视化全链路实战

发布时间:2026/9/28 17:18:39来源:尧图网络
基于Python的微博舆情分析系统:爬虫、情感分析与可视化全链路实战
简介这份资源是面向计算机相关专业学生与Python初学者的一套微博舆情分析可视化系统可直接用于毕业设计、期末大作业或课程设计。项目整合了爬虫采集、情感分析与可视化展示三大模块代码附带详细注释新手也能读懂并快速部署运行。压缩包共146个文件约3.85MB其中19个py文件承载爬虫与情感分析核心逻辑14个html与21个js、7个css构成前端可视化界面6个csv与1个sql提供数据与建表支持另有图片、字体等静态资源目录结构清晰、模块划分明确。目前已有698人学习下载说明其参考价值得到一定认可。读者可获得一套功能完善、界面美观、操作简单的完整项目源码既能理解微博数据抓取与情感倾向判定的实现思路也能借鉴前后端交互与图表展示的写法适合作为高分毕设模板或二次开发基础。1. 微博舆情分析系统到底在分析什么从一条热搜到一张情绪曲线刷到一条热搜评论区吵成一锅粥你大概会想知道这波讨论到底是真愤怒还是纯玩梗情绪是从哪一刻开始转向的哪个大 V 带偏了节奏这套「基于 Python 微博舆情分析可视化系统 爬虫 情感分析」的毕业设计干的就是把这种模糊直觉变成可量化曲线的事。它由三块拼成爬虫负责把微博正文、发布时间、点赞评论转发数抓下来情感分析给每条微博打一个情绪分可视化把情绪随时间的变化、地域分布、关键词云画出来。适合正在做毕设的计算机学生也适合想入门 python 爬虫、python 数据分析与可视化的新手——因为它是少数能把「爬取—清洗—建模—展示」全链路串起来的完整项目。下面我按真实落地顺序拆不讲空话直接给能跑的代码和参数。2. 爬虫层用 requests 抓微博数据先解决「抓得到」再谈「抓得全」2.1 为什么选 requests 移动端接口而不是硬刚网页版微博网页版weibo.com的页面是 JS 动态渲染的直接 requests.get 拿到的 HTML 里根本没有微博正文全是骨架。新手最容易在这里翻车写了几十行解析代码跑出来空列表还以为是正则写错了。常见做法是两条路一是用 python selenium 驱动浏览器等渲染完再取 DOM二是直接请求微博移动端m.weibo.cn的 JSON 接口。毕设场景我一般推荐后者因为返回的就是结构化 JSON省掉解析 HTML 的玄学速度快、代码短。移动端接口形如https://m.weibo.cn/api/container/getIndex?containerid...pageN翻页靠 page 参数。它需要带一个正常的 User-Agent 和 Cookie否则会返回ok:0。注意这里只讨论公开数据的采集思路实际使用要遵守目标站点的 robots 协议和访问频率限制别把人家服务器打挂。import requests import time import json HEADERS { User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile Safari/604.1, Cookie: 你的Cookie, # 从浏览器登录后复制会过期需定期更新 Referer: https://m.weibo.cn/, } def fetch_page(containerid, page): url https://m.weibo.cn/api/container/getIndex params {containerid: containerid, page: page} resp requests.get(url, headersHEADERS, paramsparams, timeout10) if resp.status_code ! 200: return None data resp.json() if data.get(ok) ! 1: # ok0 通常意味着被限流或Cookie失效 return None return data.get(data, {}).get(cards, []) def parse_cards(cards): rows [] for card in cards: mblog card.get(mblog) if not mblog: continue rows.append({ mid: mblog.get(id), text: mblog.get(text, ), # 含HTML标签后面要清洗 created_at: mblog.get(created_at), reposts: mblog.get(reposts_count, 0), comments: mblog.get(comments_count, 0), attitudes: mblog.get(attitudes_count, 0), }) return rows if __name__ __main__: all_rows [] for p in range(1, 11): # 先抓10页试水别一上来就100页 cards fetch_page(100103type1q你的关键词, p) if not cards: print(fpage {p} 返回空可能被限流停) break all_rows.extend(parse_cards(cards)) time.sleep(2) # 关键每页间隔2秒降低被封概率 print(f共抓到 {len(all_rows)} 条)逻辑说明fetch_page负责发请求并做两层校验——HTTP 状态码和业务字段ok任何一层不过就返回 None避免把错误数据混进结果。parse_cards把嵌套的 card 结构拍平成一行行记录只留分析需要的字段。参数上containerid决定搜什么关键词搜索、某条微博的评论、某个超话page控制翻页time.sleep(2)是保命参数别省。2.2 数据落库用 SQLAlchemy 存爬虫数据别再用 CSV 硬扛抓个几百条存 CSV 没问题但毕设要展示「随时间变化的趋势」数据量上千、还要反复查询过滤CSV 每次全量读进内存就很痛苦。常见做法是用 SQLAlchemy 把数据写进 SQLite零配置单文件适合毕设或 MySQL。SQLAlchemy 的好处是定义一次模型换数据库只改连接串代码不用动。from sqlalchemy import create_engine, Column, Integer, String, DateTime, Text from sqlalchemy.orm import declarative_base, sessionmaker from datetime import datetime Base declarative_base() class Weibo(Base): __tablename__ weibo id Column(Integer, primary_keyTrue, autoincrementTrue) mid Column(String(32), uniqueTrue, indexTrue) # 去重靠它 text Column(Text) created_at Column(String(32)) reposts Column(Integer, default0) comments Column(Integer, default0) attitudes Column(Integer, default0) sentiment Column(Integer, default0) # 情感分后面填 engine create_engine(sqlite:///weibo.db, echoFalse) Base.metadata.create_all(engine) Session sessionmaker(bindengine) def save_rows(rows): session Session() new_count 0 for r in rows: exists session.query(Weibo).filter_by(midr[mid]).first() if exists: # 已存在就跳过实现幂等 continue session.add(Weibo(**r)) new_count 1 session.commit() session.close() return new_count逻辑说明mid设成 unique 索引是整套系统去重的核心——微博翻页时经常出现重复卡片不去重会导致情感曲线被同一批数据反复加权。save_rows里先查后插虽然慢一点但保证重复跑爬虫不会污染库。参数上create_engine的echoTrue会打印所有 SQL调试时开上线关。如果换 MySQL连接串改成mysqlpymysql://user:pwdhost/db?charsetutf8mb4即可。3. 情感分析层中文微博的情绪打分snownlp 够用但要知道它的边界3.1 为什么毕设首选 snownlp而不是一上来就上 BERT多模态情感分析、视频人物情感分析这些词最近很热但毕设的时间预算有限。snownlp 是纯 Python 实现的中文情感库装完即用对每条微博返回 0~1 的情感分越接近 1 越正面几百行代码就能跑通全流程。BERT 类模型精度更高但需要 GPU、需要标注数据微调、部署重对「先跑通再优化」的毕设节奏不友好。我的建议是用 snownlp 做基线把系统跑通、可视化做漂亮如果还有时间再换模型对比这本身就是很好的论文素材。from snownlp import SnowNLP import re def clean_text(raw): # 微博正文带 a 标签、、话题符号先清掉再分析 text re.sub(r[^], , raw) text re.sub(r[\w\u4e00-\u9fa5-], , text) text re.sub(r#.*?#, , text) return text.strip() def score_text(raw): text clean_text(raw) if len(text) 3: # 太短没信息量直接判中性 return 0.5 try: return SnowNLP(text).sentiments except Exception: return 0.5 # 异常兜底别让一条脏数据中断整批 def label(score): if score 0.6: return 正面 elif score 0.4: return 负面 return 中性逻辑说明clean_text必须在打分前做因为a标签和 会干扰分词导致情感分失真。score_text对短文本直接返回 0.5是因为 snownlp 对「哈哈」「绝了」这类短句判断极不稳定与其让它乱打分不如归为中性。阈值 0.6/0.4 是经验值不是标准答案——你可以拿一批人工标注的样本画 ROC 曲线来调这也是毕设里能体现工作量的点。3.2 批量打分与写回数据库单条打分慢但 snownlp 没有原生批量接口只能循环。上千条数据大概几十秒可接受。关键是打分结果要写回sentiment字段供可视化层查询。def batch_score(): session Session() rows session.query(Weibo).filter(Weibo.sentiment 0).all() # 只处理没打分的 for row in rows: s score_text(row.text) row.sentiment int(s * 100) # 存0~100的整数方便后续聚合 session.commit() session.close() print(f完成 {len(rows)} 条打分)逻辑说明用sentiment 0作为「未处理」标记避免重复打分浪费算力。存成 0~100 的整数而不是浮点是为了后面按区间分桶统计时更直观。注意如果一条微博真实情感分恰好是 0会被误判为未处理实际项目里可以加一个scored布尔字段更严谨。4. 可视化层把情绪曲线、词云、地域分布画进一个界面4.1 用 pyecharts 出图比 matplotlib 更适合做「系统」matplotlib 出的是静态图适合论文插图但毕设要的是「可视化系统」得有交互——鼠标悬停看数值、图例点击筛选。pyecharts 生成 HTML天然带交互还能嵌进 Flask 页面。常见做法是Flask 提供数据和路由pyecharts 渲染图表前端用 iframe 或直接返回 HTML。from pyecharts.charts import Line, Pie, WordCloud from pyecharts import options as opts from collections import Counter import jieba def sentiment_trend(): session Session() rows session.query(Weibo).all() session.close() # 按日期聚合平均情感分 daily {} for r in rows: day r.created_at[:10] if r.created_at else 未知 daily.setdefault(day, []).append(r.sentiment) days sorted(daily.keys()) avg [round(sum(daily[d]) / len(daily[d]), 1) for d in days] line ( Line() .add_xaxis(days) .add_yaxis(平均情感分, avg, is_smoothTrue) .set_global_opts( title_optsopts.TitleOpts(title微博情感趋势), yaxis_optsopts.AxisOpts(min_0, max_100), ) ) return line.render_embed() def word_cloud(): session Session() rows session.query(Weibo).all() session.close() words [] for r in rows: words.extend(jieba.cut(clean_text(r.text))) words [w for w in words if len(w) 1] # 过滤单字和标点 counter Counter(words).most_common(100) wc ( WordCloud() .add(, counter, word_size_range[12, 60]) .set_global_opts(title_optsopts.TitleOpts(title高频词云)) ) return wc.render_embed()逻辑说明sentiment_trend按日期分桶求均值得到情绪随时间变化的曲线——这是舆情分析最核心的一张图能看出情绪拐点。word_cloud用 jieba 分词后统计词频过滤掉单字「的」「了」这类无意义词取前 100 个画云。参数上is_smoothTrue让曲线平滑word_size_range控制字号范围太小看不清太大挤成一团12~60 是常用区间。4.2 Flask 把三层串起来的最小骨架from flask import Flask, render_template_string app Flask(__name__) app.route(/) def index(): trend_html sentiment_trend() cloud_html word_cloud() return render_template_string( htmlbody h2微博舆情分析看板/h2 div{{ trend|safe }}/div div{{ cloud|safe }}/div /body/html , trendtrend_html, cloudcloud_html) if __name__ __main__: app.run(debugTrue, port5000)逻辑说明render_embed()返回的是图表 HTML 片段用|safe告诉 Jinja2 不要转义否则会显示成一堆源码。debugTrue开发时自动重载部署时关掉。跑起来后访问http://127.0.0.1:5000就能看到看板。这套骨架很朴素但把「爬虫→数据库→情感分析→可视化」全链路打通了剩下的就是往上面加图表和样式。5. 避坑与排查这套系统最容易翻车的 5 个地方5.1 现象爬虫跑几页后返回空程序静默结束原因微博移动端接口对高频请求会限流连续快速翻页触发风控返回ok:0。解决把time.sleep从 2 秒加到 3~5 秒并在返回空时主动break而不是继续硬刷Cookie 失效也会导致同样现象重新登录复制新 Cookie。5.2 现象情感分析结果全是 0.5曲线一条直线原因clean_text没生效正文里全是 HTML 标签snownlp 对着一堆a href...打分自然全判中性。解决在打分前打印几条清洗后的文本肉眼确认确保标签、、话题符号都被清掉。5.3 现象词云里全是「转发」「微博」「网页链接」原因这些是微博正文的模板词不是真实内容。解决在分词后加一个停用词表把「转发」「微博」「网页链接」「分享」等过滤掉再统计词频。5.4 现象数据库里同一条微博出现多次情感曲线被拉偏原因翻页时接口会返回重复卡片或者爬虫中断后重跑没去重。解决mid字段设 unique 索引插入前先查重跑前不用清库靠去重逻辑保证幂等。5.5 现象pyecharts 图表在 Flask 页面里显示成空白原因render_embed()返回的 HTML 依赖 echarts 的 JS 资源如果页面没加载对应脚本就会空白。解决确认 pyecharts 版本与模板匹配或改用render_notebook()在 Jupyter 里先验证图表本身能出再排查 Flask 渲染问题。6. 让系统从「能跑」到「能写进论文」三个进阶技巧第一个技巧是加一层「情绪拐点检测」。光有曲线不够论文里要能说清「哪一天情绪突变」。做法是对日均情感分序列做一阶差分差分绝对值超过阈值比如 15 分的日期标记为拐点再结合当天的高频词解释原因。这比单纯描述「情绪有波动」有说服力得多。def detect_turning_points(days, avg, threshold15): points [] for i in range(1, len(avg)): diff avg[i] - avg[i-1] if abs(diff) threshold: points.append({date: days[i], delta: diff}) return points逻辑说明threshold是灵敏度旋钮调小会标出很多拐点调大只留剧烈变化。建议先用 15 跑一遍看拐点数量是否合理一般 3~8 个比较适合写进论文再微调。第二个技巧是做「正面/负面/中性」的堆叠面积图而不是只看均值。均值会掩盖极化现象——可能某天均值没变但正面和负面同时暴涨说明讨论在撕裂。堆叠图能一眼看出这种结构变化。第三个技巧是给情感分析加一个「人工校验集」。随机抽 100 条自己手动标正面/负面/中性和 snownlp 的结果算准确率。这个数字写进论文比空口说「效果良好」强太多。我当年做类似项目时snownlp 在微博短文本上的准确率大概七成出头负面识别偏弱——这个结论本身就是有价值的发现说明还有优化空间也给了你「未来工作」的素材。最后一个习惯每次改完爬虫或分析逻辑先拿 50 条小样本跑通全链路确认数据库、情感分、图表都对再放大到全量。我踩过最深的坑就是直接跑几千条结果发现清洗逻辑有 bug全部重来。小步验证比事后后悔药管用。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

嵌入式驱动开发实战:设备树、固件加载与调试全解析 2026/9/28 18:54:27

嵌入式驱动开发实战:设备树、固件加载与调试全解析

1. 嵌入式驱动开发到底在忙什么很多人对嵌入式驱动开发这个岗位有误解,觉得就是对着芯片手册抄寄存器、写写初始化代码,或者认为它跟应用层开发比起来更“底层”所以更枯燥。我做了十多年嵌入式,从早期的裸机开发到后来完整的Linux BSP维护&a…

阅读更多 →
在线教程丨Qwen3-Coder-Flash 配 TaoToken:settings.json 骨架与 Agentic 编程验证 2026/9/28 18:54:27

在线教程丨Qwen3-Coder-Flash 配 TaoToken:settings.json 骨架与 Agentic 编程验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Dify + Nacos 配置 TaoToken:MCP 集成与 Prompt 迭代的敏捷开发秘籍 2026/9/28 18:54:26

Dify + Nacos 配置 TaoToken:MCP 集成与 Prompt 迭代的敏捷开发秘籍

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
高血压的术语大全的庖丁解牛 2026/9/28 18:54:26

高血压的术语大全的庖丁解牛

总纲:高血压,是体循环动脉血管内压力持续升高的心血管综合征。很多人误以为高血压头晕头痛,没有不舒服就不用管。读懂本质:高血压被称为无声杀手,早期大多无症状;它不是单纯血压数字偏高,长期高…

阅读更多 →
【Linux操作系统学习】mkdir、cp、rm、mv命令 2026/9/28 18:54:26

【Linux操作系统学习】mkdir、cp、rm、mv命令

mkdir A 创建A文件(mkdir:创建指令) mkdir -p B/C/D 创建深度文件(B>C>D) mkdir shy{1…10} 创建多个文件(创建文件shy1到shy10,十个文件) touch /home/jiwang/A /2.txt (在 /home/jiwang/ 目…

阅读更多 →
定制多连接器线缆组件全流程指南:设计选材与测试要点 2026/9/28 18:54:20

定制多连接器线缆组件全流程指南:设计选材与测试要点

上午九点刚过,设备工程部的老周就夹着一捆线进了我办公室:“这个月的第二回了,新装的四台伺服电机,编码器线、抱闸线、电源线加起来十几根,在走线槽里缠成一窝,脉冲丢帧、干扰乱飘,客户已经拍了…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉