ARTICLE DETAIL

资讯详情

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

Python网络舆情分析系统实战:从爬虫到情感分析

Python网络舆情分析系统实战:从爬虫到情感分析 简介这是面向高校计算机相关专业期末大作业与项目实战的基于Python的网络舆情分析系统完整项目覆盖数据采集、文本预处理、情感分析和可视化展示等核心环节难度适中适合正在完成课程设计、毕业设计或需要综合练手的学习者。整个项目经导师评审通过并获得九十八分源码均已在本地编译并经过严格调试下载后可直接对照运行减少环境搭建和排错成本。资源包共一百一十八个文件以Python脚本、Java界面源码、jar依赖、class字节码、txt说明文档和xml配置文件为主同时提供ipynb交互式示例、Excel数据文件、图表图片及说明文档整体约四十五点二MB便于按模块快速定位。目前已有143人学习下载。借助完整可运行的工程代码、配套数据与说明文档可以清晰梳理舆情分析系统的整体逻辑、界面设计和统计图表生成方式也便于替换或扩展数据源、算法模型与展示样式作为大作业或项目实战的起点。1. 网络舆情分析系统是人工智能大作业的稳妥选择如果你正被人工智能大作业追着跑又不想用MNIST手写数字识别这类练手题基于Python搭建一个网络舆情分析系统是比较稳的一步棋。它把爬虫采集、文本清洗、情感判断和可视化串成了完整链路代码量足够撑起课设报告同时又不依赖GPU和深度学习框架。源码拿到手真正要花心思的反而是后面这些事反爬策略、停用词表、情感阈值、ECharts路径。节点跑通只算及格参数调得能让导师追问时答得上来才配得上“高分”两个字。下面按我拿到这类项目后一路踩坑的顺序把架构、启动步骤、调参和排错完整拆一遍。2. 先看数据流再看代码网络舆情系统的架构与技术选型2.1 舆情项目的四层架构采集、清洗、分析、展示一套能应付答辩的舆情分析系统代码再乱模块边界一定是清楚的。我拿到一套人工智能大作业源码第一件事不是逐行读而是先把项目根目录里的文件按这四层归类采集层负责从新闻网站、微博搜索页或公开API抓取文本清洗层负责去HTML标签、去重、过滤掉推广内容分析层负责分词、关键词提取、情感打分和统计展示层负责生成词云、趋势折线图和分类饼图。只要这四个边界在后面无论是换数据源还是换算法都只动一层不会牵一发动全身。这四层对应到常见源码包里一般是这么分布的采集层是crawler.py或spider/目录清洗和分析层是preprocess.py和analyze.py展示层可能是app.py里的Flask页面也可能是report.py直接生成HTML。很多拿到手就翻车的同学都是跳过采集层直接跑分析脚本结果数据格式不匹配报错又回头找爬虫绕了一大圈才明白系统是流水线不是散装零件。下面这个表格是本类项目最常见的技术栈你可以拿它和手里的源码做对照看缺了哪层就往哪层补层级常见实现输入输出采集层requests BeautifulSoup / Scrapy关键词、页码原始文本CSV清洗层pandas re原始CSV去重、去噪后的DataFrame分析层jieba SnowNLP / snownlp清洗后文本词频、情感分数、主题分布展示层pyecharts / ECharts / Flask分析结果HTML图表、报告目录如果拿到手的源码少了某层最简单的补齐方式不是重写而是找一个同类开源模块补上。比如采集层只有新闻源没有微博源你可以自己加一个函数分析层只有词频没有情感那就在analyze.py里加一段基于SnowNLP的脚本。这部分后面会展开。2.2 选定Python技术栈的理由够用、可解释、不烧算力为什么这类人工智能大作业普遍选择Python而不是Java或C因为舆情分析的核心是文本处理而Python生态把从抓到看中间每一环都封好了。这是技术选型里的“省心”路线requests发请求BeautifulSoup解析HTMLjieba切词SnowNLP算情感pyecharts画图。每一样都不是最强但合起来正好覆盖一个舆情分析系统的全部需求而且每个库都有海量中文教程出问题搜索就能解决。这里要回答一个老师大概率会问的问题为什么不用BERT或者LSTM来做情感分析答案是性价比。深度学习模型确实能在情感分类上做得更好但你首先得有标注数据其次得配环境、调超参数最后还要在答辩现场证明你的模型不是过拟合。对大作业体量来说SnowNLP内置的朴素贝叶斯模型已经能给出0到1的情感倾向分虽然不够细腻但足够支撑“正面、中性、负面”三类统计。你向导师解释“我用了朴素贝叶斯”比解释“我用了注意力机制”轻松得多追问到细节也能接得住。选型里还有一个容易被忽略的点数据存储。常见的高分项目资料包一般会用SQLite或CSV而不是MySQL。原因很简单SQLite是Python自带的不需要额外装服务交给老师演示时也不用担心数据库没启动。CSV则更方便Excel打开核对。我一般建议保留CSV作为中间产物同时用SQLite存一份结构化结果这样报告里的数据表格和图表都能对得上。工具链上vscode python环境配置是这套项目里最基础的一环。我拿到源码会先把Python版本固定下来建议3.9到3.11之间太新的版本装旧版SnowNLP可能遇到依赖库schema的兼容问题。环境统一之后再用requirements.txt把依赖锁住这比在全局环境里一个个pip install要稳得多也方便换电脑复现。3. 在本地把Python源码跑通环境搭建与最小执行步骤3.1 创建虚拟环境并安装依赖网络舆情分析系统的依赖不算多但如果不做环境隔离很容易把Python官方包和项目包混在一起。我的习惯是每个项目都建独立虚拟环境尤其是用来交作业的项目答辩前几天环境崩掉是血泪教训。python -m venv venv # Windows下激活虚拟环境 venv\Scripts\activate # Linux/macOS下激活虚拟环境 source venv/bin/activate python -m pip install --upgrade pip pip install -r requirements.txtrequirements.txt是这套项目的依赖清单通常长这样requests2.31.0 beautifulsoup44.12.2 jieba0.42.1 snownlp0.12.2 pandas2.0.0 pyecharts2.0.0 flask3.0.0如果源码包里没有这个文件你可以按上面的版本手动生成一份。这里特别提醒snownlp有两个常见包名一个是snownlp另一个是SnowNLP大小写不同但指的是同一个库。安装时用snownlp小写Python导入时用from snownlp import SnowNLP。语法层面稍微注意因为误写成SnowNLP会让解释器一脸懵。装依赖时最容易出现的问题有两个一是pandas和numpy版本冲突二是pyecharts在较新Python环境里缺少importlib_resources。前者建议通过requirements.txt固定版本解决别在项目里单独安装最新版pandas后者可以在安装完requirements后补一句pip install importlib_resources。3.2 先跑采集层用可复现的方式抓取数据采集是整个舆情项目里最容易翻车的环节。真实社交媒体反爬严格直接跑爬虫经常会撞上验证码或空数据。我见过的可靠方案是采集脚本保留但给它加一个--offline参数演示时走本地缓存数据平时研究再走真实网络这样答辩现场不会因为外网波动断掉。# keyword_crawler.py import requests import csv import time import random from bs4 import BeautifulSoup def collect_news(keyword, max_pages3, delay1.5, outputdata/news.csv): 从公开搜索结果页抓取包含关键词的网页标题和摘要。 这里以适合课堂演示的公开页面为例换数据源时只要改 parse_page函数里的CSS选择器即可。 results [] seen_titles set() for page in range(1, max_pages 1): # 构造搜索urlpn参数是搜索结果的偏移量 url fhttps://www.bing.com/search?q{keyword}first{page*10} resp requests.get(url, headers{ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36 }, timeout10) if resp.status_code ! 200: print(f第{page}页返回状态码{resp.status_code}跳过) continue soup BeautifulSoup(resp.text, html.parser) # 不同搜索平台结果块的class不同这里是通用写法 for item in soup.select(li.b_algo): title_tag item.select_one(h2 a) snippet_tag item.select_one(p) if title_tag is None: continue title title_tag.get_text(stripTrue) snippet snippet_tag.get_text(stripTrue) if snippet_tag else if title in seen_titles: continue # 去重 seen_titles.add(title) results.append([keyword, title, snippet]) # 防止请求过快在页面之间随机停顿 time.sleep(delay random.uniform(0, 1)) with open(output, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([keyword, title, content]) writer.writerows(results) print(f采集完成共{len(results)}条保存到{output}) if __name__ __main__: # python keyword_crawler.py --keyword 人工智能 --pages 3 --output data/ai.csv import argparse parser argparse.ArgumentParser() parser.add_argument(--keyword, requiredTrue) parser.add_argument(--pages, typeint, default3) parser.add_argument(--output, defaultdata/news.csv) args parser.parse_args() collect_news(args.keyword, args.pages)这段代码里三个参数最关键keyword决定分析主题pages决定数据量而delay是反爬的命门。很多新手把delay设成0结果发几页就被封IP。我一般设1.5秒以上每次请求之间再加随机抖动让访问频率更像“人”。encodingutf-8-sig是为了让CSV被Excel打开时中文不乱码很多资料包里的爬虫脚本没写这个参数生成的CSV用Excel打开就是一片乱码这是最常见的“看起来坏了”的场景。3.3 再跑分析主流程一条命令生成结果目录采集到CSV后接下来就是分析主流程。这个环节的验收标准是给一条命令输出一个带图表和统计结果的目录。很多高分项目的代码里都有一个类似analyze.py的总入口里面把清洗、分词、情感、统计串成流水线。python analyze.py --input data/ai.csv --output output/这段命令背后的analyze.py核心逻辑如下# analyze.py import pandas as pd from snownlp import SnowNLP import jieba import jieba.analyse def clean_text(text): 去掉HTML标签和多余空白保留中文、英文、数字 import re text re.sub(r[^], , text) # 去HTML标签 text re.sub(r[^\w\s], , text) # 去标点 return text.strip() def analyze_csv(input_path, output_dir): df pd.read_csv(input_path, encodingutf-8-sig) df df.drop_duplicates(subset[title]) # 按标题去重 df[content] df[content].fillna() # 空内容补全 df[clean] df[content].apply(lambda x: clean_text(x)) # 情感打分0~1越接近1越正向 df[sentiment] df[clean].apply( lambda x: SnowNLP(x).sentiments if len(x) 0 else 0.5 ) # 关键词提取基于TF-IDF从所有文本里取top10 all_text .join(df[clean].tolist()) tags jieba.analyse.extract_tags(all_text, topK10, withWeightTrue) print(关键词TOP10) for word, weight in tags: print(f {word}: {weight:.4f}) df.to_csv(f{output_dir}/result.csv, indexFalse, encodingutf-8-sig) print(f分析完成结果保存到{output_dir}/result.csv) if __name__ __main__: import argparse parser argparse.ArgumentParser() parser.add_argument(--input, requiredTrue) parser.add_argument(--output, defaultoutput) args parser.parse_args() analyze_csv(args.input, args.output)注意sentiment列是后面画情感趋势图的原材料。fillna()这步不能省因为抓回来的数据里可能有的摘要为空不处理的话SnowNLP()会直接抛异常。extract_tags用的是TF-IDF统计withWeightTrue会输出每个词的权重这个权重值正是报告里“关键词表”的来源。4. 调出导师认可的结果分词、情感阈值与图表参数4.1 分词与词频jieba必做的两个动作舆情分析里最常见的一句“玄学”是为什么我分词分出来一堆没用的词答案多半是没让jieba学会领域词汇同时没过滤停用词。默认的jieba词库偏向通用领域在“人工智能”这个主题下它会把“机器学习”“深度学习”切开也会把“AI”当成单字。解决办法通常是两件事加载自定义词典准备一份停用词表。import jieba import jieba.analyse # userdict.txt 每行格式词语 词频 词性 jieba.load_userdict(userdict.txt) # 例如文件内容 # 人工智能 10 n # 机器学习 10 n # 大数据 10 n stopwords set(open(stopwords.txt, encodingutf-8).read().split()) # 例如文件内容 # 我们 因为 所以 但是 如果 虽然 而且 然后 来说 进行 通过 def filter_words(text): words jieba.cut(text) return [w for w in words if w.strip() and w not in stopwords and len(w) 1]自定义词典的最后一列是词性n代表名词v代表动词。词频写10或100都行它只影响词典里词被切出的优先级。注意len(w) 1这步能把单字噪声过滤掉但代价是“不”“很”这些单字否定词也会被丢对后续情感分析会有影响。所以如果你要保留否定词就不要加这个过滤条件而是在情感计算前单独处理。分词完下一步通常是词频统计。常见做法是使用collections.Counter统计再用pyecharts的WordCloud接口画图。这里有个容易踩坑的点词频统计前一定要做停用词过滤否则高频词永远是“的、了、在、是”这类没有分析价值的词。一份好的停用词表应该在100到300之间覆盖虚词、代词、常见动词不要贪多。4.2 情感得分阈值别把0.5当唯一标准SnowNLP输出的sentiments值是一个0到1之间的概率大于0.5表示偏正向。这个数字看起来简单直接用会出问题训练语料是商品评论在“舆情”这种新闻标题和评论文本上分数会整体偏高负面事件里也可能看到0.6以上的分数。所以不要写死“0.5为正0.5以下为负”要按实际数据调阈值。from snownlp import SnowNLP def classify_sentiment(score): 按经验阈值分成正面、中性、负面三类 if score 0.6: return 正面 elif score 0.4: return 负面 else: return 中性 def adjust_with_negation(text, score): 简单否定词修正句子含不/没有且分数偏高时降一档 neg_words [不, 没有, 无, 未] contain_neg any(w in text for w in neg_words) if contain_neg and score 0.6: return 0.4 # 拉回中性 return score阈值到底取0.4还是0.45取决于你的数据分布。我一般会在跑完分析后随机抽30条结果自己手动标一遍正负然后和程序结果对一下再回来调阈值。这步很土但最有效。笔记里推荐的方法是将人工标注结果导成Excel表格用公式算准确率准确率到80%以上再固化阈值。如果负面样本少可以把负面阈值调高到0.35减少漏报。否定词修正这一段不是SnowNLP自带的是我自己加的经验规则。因为朴素贝叶斯处理“不好”“不划算”这类词时会把“好”“划算”单独算正向整体判断容易失真。加了否定词修正后误判会少一些但也不能覆盖全部情况像“不错”本身就是正向加了否定规则反而错。所以这条规则必须只作用在带有明确否定词的句子上而且只把分数拉回中性不要一刀切成负向。4.3 可视化报告图表要能独立打开展示层是老师对项目的第一印象它不决定算法水平但决定报告好不好看。常见做法是使用pyecharts生成独立的HTML文件这样不需要启动Flask也能打开。我的习惯是生成两张图一张词云一张情感随时间变化的折线图。from pyecharts.charts import WordCloud, Line from pyecharts import options as opts import pandas as pd df pd.read_csv(output/result.csv, encodingutf-8-sig) # 以“正面/中性/负面”三类的数量做时间序列 date_group df.groupby([date, sentiment]).size().reset_index(namecount) pivot date_group.pivot(indexdate, columnssentiment, valuescount).fillna(0) line Line() line.add_xaxis(pivot.index.tolist()) for sent in [正面, 中性, 负面]: if sent in pivot.columns: line.add_yaxis(sent, pivot[sent].tolist(), is_smoothTrue) line.set_global_opts( title_optsopts.TitleOpts(title舆情情感趋势), yaxis_optsopts.AxisOpts(name数量) ) line.render(output/trend.html) # 词云使用pyecharts自带wordcloud组件 wc WordCloud() wc.add(, [tuple(x) for x in df[word_weight].to_numpy()], word_size_range[20, 100], shapecircle) wc.render(output/wordcloud.html)这段代码有两个参数值得细调word_size_range控制词云里最大字和最小字区间太宽会让小词看不清我一般用20到100shape可以换成diamond或pin但要注意太花哨的形状会让文字排版变乱答辩时用圆或云更好。一张图表生成后先在浏览器里打开确认路径没问题再放进报告避免图表白屏的尴尬。5. 拿到源码后的避坑指南5个高频报错与排查5.1 requests请求频繁返回418或403现象采集脚本运行几页后请求不再返回HTML而是返回一堆418或403状态码或者页面内容变成验证码。原因目标网站识别到了自动化请求特征。最明显的是没有设置User-Agent或每分钟请求次数远超正常人。高频访问下服务器直接把请求判定为爬虫。解决给每个请求设置完整请求头尤其是User-Agent和Referer。再把请求停顿从0.1秒提高到1.5秒以上必要时使用随机延时。如果目标网站验证码强度太大换数据源。抓取公开搜索页面和新闻RSS是最低风险的选择不要死磕登录才能看的内容。5.2 分词结果全都是单字词云上全是“的、了、一”现象jieba切出来的词全是单字几乎看不到有意义的双字词。原因多半是分词前做了过于激进的正则清洗。比如把所有非中文字符都替换掉或者把长度大于1的词全滤掉了也可能自定义词典没有生效词库切不开“机器”“学习”这样的常用词。解决先检查jieba.lcut(机器学习)在命令行里是否能正确切出“机器学习”如果不能说明词库没加载对改用jieba.load_userdict加载领域词典。然后再看stopwords里是否误把“机器”“学习”这类词加进停用表。排查时一条条打印过滤后的结果看到哪一步开始变成单字问题就在哪一步。5.3 SnowNLP情感得分全部偏高或全部居中现象整个数据集的sentiments都集中在0.6以上或者说几乎全在0.4到0.6之间没有区分度。原因SnowNLP默认训练语料是电商购物评论在舆情这种新闻标题、短评论场景下分布明显偏正。所有人都高于0.5不代表所有舆情都正面而是模型没见过这个领域的负面表达。解决先抽30条人工标注画出你数据真实的正负比例再把阈值从0.5调整到0.6/0.4。如果还是没区分度就在情感打分前引入自定义情感词典把“抗议、下架、处罚、泄露”这类领域敏感词打上负面标记覆盖掉模型原本的误判。这比换模型更快也更好解释。5.4 pandas输出CSV后Excel打开一片乱码现象df.to_csv(result.csv)后用Excel打开全是乱码但用记事本和Python读都是正常的。原因pandas默认用UTF-8编码写文件Excel对UTF-8的识别不友好读成了本地系统编码。解决写CSV时指定编码为utf-8-sig也就是在UTF-8文件开头加BOM标记Excel就能正确识别。具体写法是df.to_csv(result.csv, indexFalse, encodingutf-8-sig)。这个坑不报错最容易被忽略答辩前拷到老师电脑上打开才发现就很被动。5.5 本地打开生成的HTML图表白屏现象浏览器双击trend.html和wordcloud.html页面一片空白控制台提示找不到某个JS文件。原因pyecharts在渲染图表时会引用本地JS库如果你在项目里改动了render输出路径或把HTML文件挪到了别的目录JS相对路径就断了。解决图表HTML和负责JS的目录要保持相对位置。最简单的处理方式是把所有生成的HTML放在output目录下render(output/trend.html)之后不要再单独移动文件。如果一定要移动用浏览器F12看控制台里具体哪个资源404把对应JS文件一起拷过去。答辩前记得到output目录下双击HTML确认每张图都能独立打开。6. 从能跑到高分答辩演示的结果验证和三个加分技巧到这一步系统已经能跑坑也填完了剩下的工作是把“能运行”包装成“有价值”。我会建议先做一次结果验证再准备三个演示细节。验证方法很简单从分析结果里随机抽20条文本人工判断正负和系统结果做对比算一个(一致条数 / 总条数)的准确率。你不用把准确率做到很高只要在答辩报告里写明“随机抽20条人工核对正确率85%”导师就会觉得你的结果可信。三个加分技巧里最实用的是给图表加日期维度。很多舆情分析系统的图表只是词云和饼图加一张情感随日期变化的折线图立刻让项目有了“监测”的意味。第二个技巧是在报告中交代数据来源和时间范围比如“抽取某搜索平台前3页结果时间跨度为近一周”。这看起来简单但说明你考虑过数据边界导师追问时你就不会慌。第三个技巧是准备好一张“系统流程图”不用画得花哨框图和箭头足够。答辩时你不必讲代码照着流程图把数据从采集到展示走一遍老师基本就能理解后面提的问题也会围绕流程展开而不是钻到某个冷门函数里。我个人的习惯是每次跑完分析都顺手把关键词权重、情感分布和样例文本存成一个结构化文件报告里每张图都能在数据里找到支撑。希望这些踩坑经验和调参技巧能帮到你祝你的大作业顺利答辩。本文还有配套的精品资源点击获取
返回列表