ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

社交网络情绪分析实战:基于SnowNLP和jieba的中文情感分析

2026/9/9 10:17:38 拓冰建站 浏览量
社交网络情绪分析实战:基于SnowNLP和jieba的中文情感分析 简介基于社交网络的情绪化分析项目是一个面向毕业设计的完整实践资源涵盖微博数据爬取、情感分析与Python数据处理全流程适合自然语言处理、数据挖掘方向的初学者及需要完成类似课题的学生。资源以6.25MB的RAR压缩包形式提供整体按爬虫采集、情感分析和说明文档三个模块组织便于按技术链路循序渐进学习。已有597人学习/下载。其中爬虫部分涉及requests、BeautifulSoup、Scrapy等常用工具情感分析部分介绍VADER、TextBlob及BERT等模型的运用配套资料可帮助读者理解从微博采集文本、清洗数据、完成情感极性判断并通过Pandas、Matplotlib进行结果处理与可视化展示。整体既给出完整课题设计思路也包含关键代码实现与模块组织方式能够支撑论文撰写和系统实现阶段的参考并能提升对社交网络用户情绪模式的认知与应用能力。1. 项目思路与整体方案设计自从社交平台成了大家表达情绪的“主阵地”每天刷微博、朋友圈、评论区的海量文本里其实藏着一整座情绪数据金矿。这个“基于社交网络的情绪化分析”项目核心就是把这部分非结构化的文本变成可量化、可追踪的情绪指标最后以可视化图表的形式呈现出来。说白了就是想搞清楚一件事某段时间、某个话题下大家到底是开心、愤怒、悲伤还是中立。这类任务在自然语言处理里有个专门的方向叫情感分析Sentiment Analysis也叫意见挖掘。我们这次只针对中文社交网络难度会比英文场景高不少主要原因是中文分词、网络新词、反讽语气这些坑特别多。项目整体走的是“数据采集 → 数据清洗 → 情感打分 → 趋势聚合与可视化”这条标准路线技术栈选型也相对轻量Python 为主爬虫用 requests BeautifulSoup分析和建模用 jieba、SnowNLP可视化交给 pyecharts。顺带说一下为什么选 SnowNLP 而不是从头 train 一个深度学习模型。很大一个原因是这个项目偏研究探索性质重点是验证“社交网络情绪分析”的整套流程能不能跑通而不是追求刷榜级的准确率。SnowNLP 的好处是开箱即用内置的语料在微博评论这种场景下表现不错它对文本的情感倾向输出是 0~1 之间的概率值越接近 1 越正向越接近 0 越负向非常直观。等流程跑通后如果你想把准确率再往上提后续完全可以替换成微调过的 BERT 或者 ERNIE 模型。整个项目的目标输出有三层第一层是单条文本的情绪得分第二层是某个话题/某时间段内的整体情绪分布第三层是趋势曲线图和Top情绪词云图。这三层结果基本能回答“大家现在对这件事的态度到底是什么样”这个问题无论是做舆情观察、产品反馈分析还是写社媒运营复盘都有直接用得上。2. 数据采集与预处理2.1 爬虫取数接口选型与反爬应对做情绪分析第一步肯定是先要有数据。这里的“社交网络”我选了微博热搜作为切入点因为热搜话题天然带热度而且短文本里情绪信号的密集度非常高。爬虫这部分我没有用 Selenium 那种重型方案而是直接用 requests 模拟请求因为微博移动端的热搜榜单接口返回的是结构化 JSON解析非常方便。请求地址大致长这样import requests import json url https://weibo.com/ajax/side/hotSearch 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/15E148 Safari/604.1, Referer: https://weibo.com/ } resp requests.get(url, headersheaders, timeout10) data resp.json()这里有几个细节特别重要。一个是 User-Agent 尽量模拟手机端因为网页端接口的字段经常变而且手机端的反爬相对宽松。另一个是 Referer 必须带上否则服务器会直接拒绝。我实测下来单次请求拿到的热搜榜是 50 条左右足够作为一个分析批次了。不过这仅仅是拿到热搜列表真正要做情绪分析还得抓取每条热搜下面有代表性的评论或帖子文本。后来我换了个思路不追求全量评论而是在热搜话题下的实时微博流里按时间顺序抓取 500~1000 条文本这样做有两个好处一是样本量对情绪分布统计来说已经够了二是减少触发反爬的频率。注意爬虫采集务必遵守目标平台 robots 协议和服务条款控制请求频率只做个人学习研究使用不要拿采集数据商用。我每次请求之间都加了 random.uniform(3, 6) 的随机延时另外做了异常重试避免给对方服务器造成压力。2.2 清洗环节去除噪声和无关符号拿到的原始文本没法直接用微博文本里充斥着大量噪声emoji 表情、话题标签#xxx#、用户、URL 链接、图片描述文字还有各种“转发微博”之类的模板文本。清洗这一步直接决定后续特征提取的质量。我写了一个清洗函数按顺序处理这几类噪声import re def clean_text(text): # 去URL text re.sub(rhttp\S, , text) # 去用户 text re.sub(r[\w\u4e00-\u9fa5], , text) # 去话题标签但保留标签内容用于后续分析 text re.sub(r#([^#])#, r\1, text) # 去emoji和特殊符号 text re.sub(r[\U0001F300-\U0001F9FF], , text) # 去多余空格 text re.sub(r\s, , text).strip() return text这里有一个我踩过的坑话题标签不能直接删掉应该把 # 符号去掉但保留里面的文本。因为热搜话题本身比如“某地晚霞上热搜”就是重要的情绪触发词如果整段删掉后面统计词频的时候就把关键信息给丢了。刚开始我直接把整个标签删了结果发现词云里全是“转发微博”“视频”这种泛词完全没有分析价值后来才意识到这个问题。另外英文和数字在这个场景下大概率是噪声可以统一过滤但要注意保留一些品牌名里的英文比如“iPhone”“GPT”这种所以清洗时我做了一个白名单机制把包含常见品牌词根的英文串保留下来。清洗完毕后统计一下有效文本的占比一般情况下五千条原始数据清洗完大概能剩四千条左右可用的有效文本这个量级已经足够支撑后续建模分析了。3. 情绪分析核心实现3.1 Jieba 分词 自定义词典扩展中文情感分析和英文最大的区别是英文按空格切词就行中文必须分词。分词的质量直接决定后面情感判断和关键词统计的准确性。我用的分词工具是 jieba它支持三种模式精确模式、全模式和搜索引擎模式。在情绪分析场景下精确模式是首选因为它不会把完整词组拆得七零八碎。不过 jieba 默认词典对社交网络用语覆盖非常有限很多网络热词它根本分不对。比如“绝绝子”是形容词如果不加自定义词典它会被拆成“绝”“绝”“子”那情感计算就废了。所以我在项目里维护了一个自定义词典收集常见的网络热词和情绪词比如“蚌埠住了”“破防”“yyds”“emo”等等词典一行一个词带上词频和词性import jieba # 加载自定义词典 jieba.load_userdict(weibo_dict.txt) # 词典内容示例破防 100 n, emo 100 v, 绝绝子 100 adj text 今天看到这个视频真的破防了 words jieba.lcut(text) print(words) # [今天, 看到, 这个, 视频, 真的, 破防, 了]这里有个关键技巧自定义词典要在程序启动时先加载然后再执行切词顺序反了等于没加载。而且词典里的词频可以统一写成 100这是一个保证“优先识别”的经验值实测下来对新词识别的稳定度最高。3.2 SnowNLP 情感得分与阈值校正分词做完接下来就是情感打分。SnowNLP 的调用方式很简单几行代码就搞定from snownlp import SnowNLP def get_sentiment_score(text): s SnowNLP(text) return s.sentiments # 输出0~1之间的值但这里有个坑是必须处理的SnowNLP 内置模型在电商商品评价语料上训练直接拿它的 0.5 作为中性阈值放到微博场景下会发现严重偏差。我跑第一批数据时几乎所有文本得分都集中在 0.3 以下如果机械地把小于 0.5 都当负面就会得出“全网都在愤怒”的错误结论。解决办法是阈值重标定。具体操作是人工抽样标注 500 条文本分别标为负面、中性、正面三类拿这些标注数据反推模型输出分数的分布范围。我当时标完统计的结果是负面文本普遍在 0~0.35中性在 0.35~0.65正面在 0.65~1。所以我把判断规则重新定义为这样def emotion_category(score): if score 0.35: return 负面 elif score 0.65: return 正面 else: return 中性这一步看似简单但它是整个项目准确率的基石。如果不做阈值校正就算后面画图画得再漂亮结论方向都是错的。可以这么理解SnowNLP 的原始分数只是一个相对坐标我们要做的是找到这个坐标体系下对应微博语料的“基准线”然后围绕基准线重新划分情绪区间。3.3 情绪得分批量计算与语料校准单条文本算完还不够为了提升模型在特定领域的适应性我还做了一个小型的语料校准操作。SnowNLP 支持用新的训练数据来对情感分类器做二次训练不过实测下来直接用少量语料微调的效果有限因为它的底层是朴素贝叶斯对训练数据量和特征分布都很敏感。所以我的建议是想快速出结果优先用“阈值重标定”想深入研究再考虑微调或换模型。批量计算的代码结构大致是这样import pandas as pd from snownlp import SnowNLP def batch_sentiment(text_list): scores [] for text in text_list: try: s SnowNLP(text) scores.append(s.sentiments) except Exception as e: scores.append(0.5) # 异常按中性处理 return scores df pd.read_csv(cleaned_weibo.csv) df[sentiment_score] batch_sentiment(df[clean_text].tolist()) df[emotion] df[sentiment_score].apply(emotion_category)跑完这一轮每条文本就有了一个 0~1 的得分和一个正负面标签。我建议在输出结果的时候把原始文本、清洗后文本、得分、情绪标签都放到同一个 CSV 里方便后续核对。有一次我发现某一批数据几乎全是满分正面排查后发现是爬取的时候我误把广告账号的种草文案全抓进来了这种“数据污染”只有靠回到原始文本才能发现所以可追溯性非常重要。4. 结果聚合从单条得分到整体趋势4.1 三种时间维度的情绪聚合方式单条文本的情感得分本身意义不大真正的洞察来自聚合。我在项目里把聚合分成三个维度按小时聚合、按日聚合、按话题聚合。按小时聚合适合分析突发事件的情绪扩散曲线比如一个话题几点上热搜、几点情绪爆发到顶峰按日聚合适合观察持续多日的舆情变化按话题聚合则是直接把同话题下所有文本的得分取平均得到该话题的整体情绪偏向。聚合计算的核心逻辑是这样trend df.groupby([date_hour, emotion]).size().reset_index(namecount) # 计算每个时间片的总情绪均值 avg_score df.groupby(date_hour)[sentiment_score].mean()这里有一个细节值得注意均值很容易被极端值带偏个别极端负面文本得分趋近 0会把整体均值拉得很低。所以我在聚合的时候同时计算了两个指标一个是普通均值另一个是正负面文本占比。占比比如“负面文本占比 60%”往往比均值更能反映真实情况因为它不受极端值影响而且对外行也更容易解释清楚。4.2 情绪占比分布图与词云的可视化分析做完不展示等于白做。我用的可视化工具是 pyecharts它生成的是 HTML 文件浏览器直接打开就能看交互性也比 matplotlib 强很多。第一张图是情绪占比饼图把全部文本按正、中、负三个类别统计百分比一眼就能看出整体情绪结构。第二张图是时间趋势折线图横轴是时间纵轴是情绪得分均值或正负面占比能清楚看到情绪随时间的波动。第三张图是关键词词云我按不同情绪类别分别生成了词云这样能知道“正面情绪的人都在讨论什么词”“负面情绪集中在什么话题”。词云的生成要注意一下分词后需要先过滤掉停用词我用的是哈工大停用词表再额外加了“微博”“视频”“网页链接”这类平台通用词。如果不过滤词云里出现频率最高的永远是“一个”“我们”“什么”完全没有区分度。切词做词云的代码这样写from wordcloud import WordCloud def generate_wordcloud(text_series, output_path): all_words [] for text in text_series: all_words.extend(jieba.lcut(text)) # 过滤单个字和停用词 stopwords set(open(stopwords.txt, encodingutf-8).read().split()) filtered [w for w in all_words if len(w) 1 and w not in stopwords] wc WordCloud(font_pathsimhei.ttf, width800, height600, background_colorwhite).generate( .join(filtered)) wc.to_file(output_path)这里我踩过一个特别典型的坑WordCloud 默认文字布局是不规则排列的生成的词云图看起来挺漂亮但词的位置和颜色可能会影响阅读优先级另外中文字体文件必须显式指定否则词云里全是乱码方框。我用的是黑体字体文件 simhei.ttfWindows 系统自带的路径就能拿到Linux 服务器上需要单独安装字体包。4.3 情绪时间曲线的“拐点”解读趋势折线图画出来之后真正的分析工作才算开始。我拿到第一批数据画完曲线时发现某天凌晨 2 点到 4 点出现了一个非常突兀的情绪高分峰一开始还以为是数据异常回去翻了原始文本才发现那段时间恰逢一个明星官宣好消息粉丝群体集中发帖情绪自然集体高亢。这个案例说明一个问题情感分析不只是给文本打分更重要的是结合时间背景去解读“为什么此时此地会出现这个情绪拐点”。另外折线图建议同时叠加文本量曲线用副坐标轴展示。因为有的时间点情绪均值虽然高但样本量只有几十条参考价值不大而有的时间点情绪均值中等但样本量上千条说明这是覆盖面更广的普遍情绪。叠加之后可以直接在图上判断“高热度强负面”的组合这种场景下的舆情风险才是最高的。5. 常见问题排查与技术要点总结这节我把自己在这个项目里实打实踩过的坑和解决办法整理成了一份速查表希望你能避开这些雷。问题现象根本原因解决办法所有情感得分集中在极小范围SnowNLP 内置模型与微博语料分布不匹配人工标注样本重标定阈值区间词云全是“转发微博”等泛词模板文本和平台词没过滤干净扩展专属停用词表清洗时去掉模板句式爬虫请求频繁被限制请求频率过高、缺少随机延时增加随机延时轮换 UA限制单批次请求量分词把网络热词拆碎默认词典缺少社交网络词汇维护自定义词典启动时加载 userdict带话题标签的文本情感判断错误标签符号干扰模型判断去 # 号但保留话题正文既保留语义又降噪时间趋势图出现虚假拐点某时段样本量过低均值失真叠加样本量曲线样本过少的时间点标记为“数据不足”5.1 中文编码与运行环境避坑前前后后在环境上面也折腾了不少时间主要问题出在 Windows 下 Python 读写 CSV 文件时的默认编码上。Windows 的 Python 默认用 GBK但爬虫拿到的是 UTF-8直接 to_csv 保存中文文本再重新读入就会乱码。解决方案统一成这三步文件写入时显式指定 encodingutf-8-sig读入时也用同样的编码pandas 读取时加 enginepython 防止分隔符误判代码文件开头统一加# -*- coding: utf-8 -*-保证脚本本身不乱码。还有 pyecharts 的版本坑1.x 版本和 0.5.x 版本的 API 差异很大网上大量教程用的还是老版本语法。如果你是参照网上的案例最好先确认一下自己装的 pyecharts 大版本不然照着抄代码经常报 ImportError。我项目里用的是 1.x图表输出到 HTML 文件整体非常稳定。5.2 从“能跑通”到“能用”的三个提升方向项目做到能出图出结论只是完成了第一步。如果要让结果更有实际价值可以从三个方向做迭代优化。第一个方向是模型升级。SnowNLP 的朴素贝叶斯上限摆在那边换成基于预训练模型比如 ERNIE、BERT-wwm做微调准确率会有明显提升但代价是必须准备更高质量的人工标注语料而且要上 GPU 训练。对于想走算法方向的同学这一步是必经之路。第二个方向是情绪维度扩展。目前是正、中、负三分类但实际上社交网络上的情绪远不止这三种愤怒、焦虑、惊喜、失望这些细粒度情绪更有分析价值。我用一个公开的中文情绪分类数据集跑过一次细粒度分类实验准确率大概在 80% 左右比三分类结果的信息量丰富得多。第三个方向是实时化改造。现在整个流程是离线的爬取一批、分析一批、出图一批。如果把它改成定时任务每小时自动抓取、计算、推送结果到报表就可以做成一个持续监测的舆情小工具配合定时调度工具使用投入产出比很高。5.3 评价模型效果的正确姿势最后想聊一下效果评估。很多人看情感分析模型习惯性看“准确率有多少”但准确率在情感分析场景下并不能说明一切。一个数据集中 90% 都是中性文本那模型无脑判中性就能拿到 90% 的准确率但这显然没价值。我自己的做法是看三分类的混淆矩阵重点看“负面被误判为正面”的比例因为在舆情场景下漏掉一个潜在的负面信号比把中立判成负面严重得多。这个项目我最终调下来人工抽检 200 条的结果是负面识别召回率大约在 82% 左右正面识别的精准率略高一些在 88% 上下。对一个小体量研究项目来说这个水平足够支撑后续的观察和决策参考了。回头看这个项目我的整体感觉是技术本身并不复杂真正花时间的地方全在细节上——清洗规则、阈值校正、自定义词典、可视化表达。做社交网络情绪分析最忌讳的就是拿到模型就甩手跑数据前后端每一步都先想清楚“这个处理到底会不会影响情绪判断”输出结果才靠得住。如果你也想上手做类似的分析建议先不要急着追求模型多先进把数据流程走通、跑出一份可信的情绪报告比什么都实在。本文还有配套的精品资源点击获取