简介:一份基于Python的人工智能大作业网络舆情分析系统完整项目,面向计算机及相关专业学生,适用于期末大作业、毕业设计或个人项目实战练习。该项目经导师指导并通过评审,最终得分98分,源码已在本地编译运行并严格调试,覆盖舆情数据采集、文本处理、统计分析与可视化展示等环节,附带详细说明文档、图表生成脚本、配置代码及数据表格,有助于使用者快速理解系统设计思路并二次开发。压缩包共118个文件,主要类型包括Python脚本、Java辅助类、文本说明、Markdown文档、Jupyter笔记及Excel数据表等,整体大小45.2MB,目录按功能模块划分,清晰易检索,并包含相关图片素材,便于对照验证界面与图表效果。目前已有143人学习下载,适合需要可运行高分项目作为参考的开发者。
1. 网络舆情分析大作业:为什么说这是一条完整的技术链路
期末周拿到"基于 Python 的人工智能大作业"这个题目时,很多人的第一反应是:舆情分析不就是用爬虫抓点评论,再画几张图吗?真动手才发现,从数据采集、文本清洗、情感计算到可视化展示,是一条完整的技术链路,任何一环断了都交不出东西。这套高分项目源码加全套资料,解决的就是这个痛点:它不是给你一段跑完就完的代码,而是把舆情分析从采集到答辩展示的每一步都铺好了。适合两类人:一是想快速复现、稳妥拿分的大三学生,二是想把这套流程改造成自己课程设计底座的开发者。下面按照我在实际项目里拆解的顺序,把每个模块怎么用、参数怎么调、坑在哪讲清楚。
2. 数据采集层:用 requests 与 BeautifulSoup 把舆情评论捞回来
我拿到这套资料时,最关心的就是数据从哪来、怎么存。大多数舆情大作业的难点从来不是算法,而是没有干净、足量的文本数据。这一章先把采集层的架构和代码讲清楚,后面分析层才能站得住。
2.1 三层架构与模块划分
这套系统整体分成采集层、分析层、展示层三个部分,对应到源码包里的目录也很清晰:spider/负责请求和解析,analysis/负责分词和情感计算,visual/负责图表生成和报告导出。我第一次看到这个结构的时候比较意外,因为很多大作业源码是把三层揉在一个文件里,答辩拆分时说不清楚,而这份源码的模块边界做得比较干净。
采集层最核心的选型是 requests 搭配 BeautifulSoup。有人问为什么不用 Scrapy,我一般会解释:对于期末大作业的数据量级——通常几千条评论——requests 足够,而且调试时能直接看到请求和响应,不用像 Scrapy 那样起一个完整爬虫工程。当你需要在 Jupyter 里边写边看返回结果时,这个选择能省很多时间。
2.2 评论列表抓取与请求参数
来看采集层最基础的一个函数,源码里抓取评论列表的部分是这个套路:
import requests from bs4 import BeautifulSoup import time import random def fetch_comments(url, page=1): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/120.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9" } params = {"page": page} resp = requests.get(url, headers=headers, params=params, timeout=10) if resp.status_code == 200: resp.encoding = "utf-8" soup = BeautifulSoup(resp.text, "html.parser") items = soup.select(".comment-list .item .text") return [item.get_text(strip=True) for item in items] return []这段代码的逻辑是:先把请求头里的User-Agent伪装成浏览器,避免被目标站点直接拒绝;再把页码作为 GET 参数传过去;拿到响应后强制用utf-8解码,然后通过 CSS 选择器定位评论节点。这里的timeout=10是有讲究的,如果不设置,网络异常时脚本会一直挂着,影响后面批量采集的稳定性。
我建议你根据自己的数据源修改选择器和翻页参数。比如某些平台的评论是>import csv import os def save_comments(comments, file_path="data/comments.csv"): file_exists = os.path.isfile(file_path) with open(file_path, "a", encoding="utf-8", newline="") as f: writer = csv.writer(f) if not file_exists: writer.writerow(["content", "source", "time"]) for c in comments: writer.writerow([c, "target_site", time.strftime("%Y-%m-%d %H:%M:%S")])
用追加模式"a"写入而不是覆盖模式,这样即使采集中途断了,已抓到的数据不会丢。newline=""是 csv 模块在 Windows 下的必备参数,不加的话每行中间会多一个空行,看起来是小问题,但会让后面的 pandas 读取多出很多空值。每次数据进来时打上source和time字段,后面做时间趋势分析时可以直接按日期聚合。
我在复现时发现,采集速度不能拉满。有些站点对单 IP 的访问频率很敏感,所以源码里建议在循环中加time.sleep(random.uniform(1, 3)),让每次请求间隔随机化。这是爬虫的基本礼仪,也是让任务能跑完的保命手段。
提示:抓取公开评论前,先看目标站点 robots 协议和用户协议,只用于学习实验,别碰需要登录才能看的私有数据。
3. 文本挖掘与情感分析:分词、打分、关键词提取三件套
数据到手后,真正体现"人工智能"含量的部分是文本分析。这一章讲清楚三个核心操作:分词与停用词过滤、SnowNLP 情感打分、TF-IDF 关键词提取。这套源码里这三件套是连成一条流水线的,我按顺序拆开说。
3.1 jieba 分词与停用词过滤
原始评论是一段一段的完整句子,计算机没法直接统计词频,第一步要分词。源码里用 jieba,这是 Python 中文分词的标配。分词之后还有一个关键动作:过滤停用词。停用词就是"的""了""是""在"这类没有实际信息量的词,不过滤的话,后面做词云时会满屏都是这些虚词。
import jieba import pandas as pd def load_stopwords(path="stopwords.txt"): stopwords = set() with open(path, "r", encoding="utf-8") as f: for line in f: stopwords.add(line.strip()) return stopwords def clean_text(text, stopwords): words = jieba.lcut(text) filtered = [] for w in words: if not w.strip(): continue if w in stopwords: continue if len(w) <= 1: continue filtered.append(w) return " ".join(filtered)jieba.lcut返回的是列表,比jieba.cut的生成器更直观,方便调试。停用词表建议自己按数据场景加词,比如你的舆情对象是某款手机,那"手机""产品"这类高频但无区分度的词也可以丢进停用词表。len(w) <= 1这个判断能去掉单字噪声,比如语气词"啊""哈"。
把清洗后的文本存回 DataFrame 时,我一般会新增一列,这样后面情感分析和词云都基于清洗后的列,不需要重复分词。这套源码里给到的做法也是类似的,它用df["clean_content"] = df["content"].apply(lambda x: clean_text(x, stopwords))一次性生成新列,比循环遍历效率高。
3.2 SnowNLP 情感打分与阈值划分
情感分析部分是项目的灵魂。源码选的是 snownlp 库,它给每段文本打一个 0 到 1 之间的情感分数,越接近 1 越正向,越接近 0 越负向。注意这个分数并不是分类结果,需要自己划阈值。
from snownlp import SnowNLP def sentiment_label(text, pos_th=0.6, neg_th=0.4): if not text.strip(): return "neutral" s = SnowNLP(text) score = s.sentiments if score >= pos_th: return "positive" if score <= neg_th: return "negative" return "neutral"这里有两个可以调的参数:pos_th和neg_th。默认 0.6 和 0.4 是经验值,我实际测试时发现,不同平台的评论语言风格差异很大:知乎评论用词偏书面,分数偏高;短视频评论大量使用口语和反讽,0.6 的阈值会把很多明显负向的内容判成中性。所以你在答辩前最好取一部分数据人工标注,再回过来调阈值。源码里把这组参数放在config.py中,就是方便你反复试。
需要提醒的是,snownlp 对否定句式容易判错,比如"这个功能一点都不好用",模型可能看到"好用"就给高分。这是朴素贝叶斯模型的天然短板,源码里没有做过于复杂的优化,如果大作业想拿高分,可以在答辩时主动说这个局限,并演示如何用规则修正——这比假装没有问题更能体现工程思维。
3.3 TF-IDF 关键词提取
除了情感分布,舆情分析还需要知道大家在讨论什么。关键词提取源码用的是jieba.analyse.extract_tags,这个函数背后是 TF-IDF 算法——某个词在一篇文档中出现得多,但在整个语料中出现得少,说明它有区分度,权重就高。
import jieba.analyse def extract_keywords(text_list, top_k=20): corpus = " ".join(text_list) tags = jieba.analyse.extract_tags( corpus, topK=top_k, withWeight=True, allowPOS=("n", "v", "adj", "nz", "vn") ) return tagstopK=20控制返回多少个关键词,withWeight=True会把每个词的 TF-IDF 权重一并返回,方便后续排序和可视化。allowPOS这个参数是我比较欣赏的一个细节:它限定只提取名词、动词、形容词等有实际含义的词性,把副词、连词全部过滤掉。如果你不设这个参数,会发现关键词里混进很多"非常""还是"之类的高频副词,词云就花了。
我复现的时候,把这份关键词结果按权重排序后导出成 CSV,然后和情感分数列做交叉分析,能看出来负向情感集中在哪些主题词上。这一步不是源码强制要做的,但对答辩很有价值:它从"大家情绪如何"深化到了"大家为什么情绪不好"。
4. 结果可视化与答辩展示:pyecharts 大屏和词云怎么搭
分析结果算出来后,还需要一个直观的展示。这一章讲从数据到图表的完整落地,覆盖 pyecharts 柱状图和饼图、词云图、以及把多张图合成一个 HTML 报告。对于期末答辩来说,这一章的完成度直接影响第一印象。
4.1 pyecharts 情感分布柱状图
源码的可视化部分用的是 pyecharts,它生成的是基于 ECharts 的 HTML 图表,交互效果比 matplotlib 静态图好一个档次。看看情感分布的柱状图怎么画:
from pyecharts.charts import Bar from pyecharts import options as opts def draw_sentiment_bar(labels, counts, save_path="sentiment_bar.html"): bar = Bar() bar.add_xaxis(labels) bar.add_yaxis( "评论数", counts, category_gap="40%", label_opts=opts.LabelOpts(position="top") ) bar.set_global_opts( title_opts=opts.TitleOpts(title="舆情情感分布"), yaxis_opts=opts.AxisOpts(name="条"), xaxis_opts=opts.AxisOpts(name="情感类别") ) bar.render(save_path)category_gap="40%"是柱间距占类目宽度的比例,调大柱子变细,调小柱子变粗。LabelOpts(position="top")让每根柱子顶部直接显示数字,答辩展示时不用眼睛去对数轴。render默认输出 HTML 文件,双击浏览器就能打开,不需要额外部署服务。
我一般会把柱状图、饼图、折线图分别渲染成三个 HTML 文件,再整合到一个索引页。源码里就是这么做的,visual/目录下有几个独立的绘图函数,每个函数接收 pandas 的 Series 或 list,返回值是渲染好的 HTML 路径。
4.2 词云图与中文字体问题
词云是整个大作业里最出效果的一张图。wordcloud 库本身不复杂,但有一个高频翻车点:默认字体不包含中文,生成的图片全是方框。源码把字体路径显式指定为msyh.ttc,这是微软雅黑。
from wordcloud import WordCloud import matplotlib.pyplot as plt def draw_wordcloud(word_freq, font_path="msyh.ttc", save_path="wordcloud.png"): wc = WordCloud( font_path=font_path, width=800, height=600, background_color="white", max_words=100 ) wc.generate_from_frequencies(word_freq) plt.imshow(wc, interpolation="bilinear") plt.axis("off") plt.savefig(save_path, dpi=150, bbox_inches="tight")max_words=100是词云上最多显示词的数量。generate_from_frequencies接收的是字典格式,键是词、值是权重,正好对应 3.3 节extract_tags返回的 TF-IDF 结果。如果你电脑上没有msyh.ttc,可以用find font -iname "*.ttc"找系统中文字体路径,否则必须安装中文字体。这一步在 Linux 服务器上跑的时候尤其容易踩。
4.3 一键导出 HTML 报告
答辩时如果一个个打开 HTML 文件,场面会很散。源码里提供了一个build_report的函数,把图表数据和结论文字拼到一个报告页里:
def build_report(sentiment_counts, keywords, output="report.html"): summary = f"共分析评论 {sum(sentiment_counts.values())} 条,正向占比 " \ f"{sentiment_counts.get('positive', 0) / max(sum(sentiment_counts.values()), 1):.1%}" html = f""" <html> <head><meta charset="utf-8"><title>舆情分析报告</title></head> <body> <h1>{summary}</h1> <h2>情感分布</h2> <iframe src="sentiment_bar.html" width="100%" height="400"></iframe> <h2>高频关键词</h2> <p>{keywords}</p> <img src="wordcloud.png" width="800"> </body> </html> """ with open(output, "w", encoding="utf-8") as f: f.write(html)<iframe>把前面生成的柱状图直接嵌进报告页,<img>嵌入词云图,这样整个答辩展示只需要打开一个report.html。max(sum(..., 1)这个写法是防止评论数为零时除零报错。
报告里我建议你也输出原始数据的抽样表格,比如正向和负向评论各挑 5 条典型的附上,让老师直观看到模型判得对不对。源码的report.html模板里预留了<p>{keywords}</p>的位置,你可以在summary里叠加更多指标,比如时间趋势峰值。
5. 避坑合集:舆情分析项目里最容易翻车的五个现场
这个项目我从复现到改造,踩过不少坑,很多是运行时才暴露的。这一章把最常见的五个问题按"现象 → 原因 → 解决"写清楚,你照着排查比一个个搜报错效率高得多。
5.1 目标站点返回 403:User-Agent 伪装不到位
- 现象:
requests.get返回状态码 403,或者返回的页面是验证码页面,解析不到任何评论数据。 - 原因:目标站点识别出请求来自脚本。很多站点会校验
User-Agent、Accept-Language等请求头,默认的python-requests/x.xx一眼就能识别。 - 解决:把请求头补全,至少要带
User-Agent和Accept;如果还不行,用fake_useragent库随机生成 UA,并在每次请求之间加随机延时。源码里给的headers字典是我的基础模板,你可以在里面继续加Referer,模拟从站内页面跳转过来的路径。
5.2 中文乱码:编码声明不统一
- 现象:写入 CSV 后打开全是乱码,或者
UnicodeEncodeError: 'ascii' codec can't encode characters。 - 原因:
requests响应的encoding默认可能是ISO-8859-1,直接用resp.text就会把 UTF-8 的中文解析成乱码;写入文件时 Python 默认编码在 Windows 下不是 UTF-8。 - 解决:
resp.encoding = "utf-8"要在resp.text之前设置;打开写入文件时显式传encoding="utf-8";如果 CSV 要用 Excel 打开不乱码,写入时用utf-8-sig而不是utf-8。这是我改了三次才顿悟的细节,utf-8-sig会在文件头加 BOM,Excel 才认。
5.3 SnowNLP 对否定句和反讽误判
- 现象:明显负向的评论被判成正向,"这个手机电池一点都不耐用"得分 0.7。
- 原因:snownlp 是基于朴素贝叶斯训练的,它对否定词和反讽没有专门的语法建模,看到"耐用"这类正倾向词就整体拉高分数。
- 解决:先加一个简单的否定规则——如果句子中出现"不""没""不太""毫无"等词,且紧邻词是正倾向词,就把分数压到
1 - score。这个规则写在sentiment_label里,代码量小,但能让准确率明显提升。答辩时主动展示这个规则函数的输出,比单纯甩一个模型有说服力。
5.4 pyecharts 图在 Jupyter 里不显示
- 现象:在 Jupyter Notebook 里调用
bar.render_notebook()没反应,或者只看到空白输出。 - 原因:pyecharts 版本不同,渲染内核要求不同;老版本是新版本渲染器冲突,或者在 JupyterLab 里没有加载 ECharts 的 JS 依赖。
- 解决:优先用
bar.render("xxx.html")生成独立 HTML 文件,浏览器打开;如果一定要在 Notebook 里看,检查pyecharts版本并安装配套的echarts依赖包,或者改用chart.notebook()新接口。我的习惯是直接渲染到 HTML,反正答辩也要用浏览器展示。
5.5 pandas 与 numpy 版本冲突
- 现象:导入 pandas 时报
AttributeError: module 'numpy' has no attribute 'float',或者跑得好好的代码突然报错。 - 原因:numpy 2.x 移除了
np.float等旧别名,老代码里如果用了这些写法就会崩;pandas 版本和 numpy 版本不匹配也会出现类似问题。 - 解决:查看
requirements.txt,把 numpy 固定到 1.26.x,pandas 固定到 2.0 以上,这是目前兼容性最稳的组合。安装时用pip install "numpy==1.26.4" "pandas==2.0.3"精确锁版。如果是在虚拟环境里跑,建议每条依赖都锁大版本,不要全用最新版。
6. 进阶技巧:把一次性大作业改成参数化可复用的分析管线
如果你的目标不只是交差,而是想把这套源码变成以后课程设计、实习作品集里能反复用的底座,我建议你做两件小事:配置解耦和流程封装。
第一件事是把所有可变参数从代码里抽出来。源码里其实已经把阈值、爬取 URL、关键词数量散落在各个函数里,我拿到后第一件事就是建一个config.py:
# config.py CRAWL_URL = "https://example.com/comment?page={page}" HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0" } POS_TH = 0.6 NEG_TH = 0.4 TOP_K = 20 OUTPUT_DIR = "output"这样换一个舆情事件,只需要改CRAWL_URL和阈值,不用在爬虫函数和情感函数里翻找。
第二件事是把整套流程封装成一个入口函数,输入是数据源,输出是报告 HTML:
def run_pipeline(crawl_url=None, csv_path=None): if crawl_url: data = crawl_and_save(crawl_url) else: data = pd.read_csv(csv_path) data["label"] = data["content"].apply(sentiment_label) counts = data["label"].value_counts().to_dict() keywords = extract_keywords(data["clean_content"].tolist()) build_report(counts, keywords, output="output/report.html") print("分析报告已生成:output/report.html")这个入口函数我一般会在期末项目里作为main.py的调用目标。老师运行一份测试数据,直接看到输出报告,不关心内部细节,这也符合交付一个"系统"而不是"代码片段"的要求。
从那以后,我每次拿到任何课程设计或比赛源码,第一件事都不是急着看算法细节,而是先跑通数据流,再拆出可变参数,最后画清模块边界。这个习惯让我复现项目的速度提高了不少。希望这份舆情分析源码和全套资料也能让你少走这些弯路,期末顺利交出能打的作品。
本文还有配套的精品资源,点击获取