简介:「Python网络舆情分析系统」是一套基于Django框架的Web应用完整项目源码包,面向具备基础编程能力、希望深入理解Python后端开发的高校学生与开发者,尤其适合作为毕业设计或课程实践参考。资源共290个文件,压缩包约93.5MB,内容涵盖Python源码(.py)、编译文件(.pyc)、前端样式与脚本(.css/.js)、HTML页面、SQL数据库脚本以及说明文档、PPT等,可支撑从环境搭建到功能调试的完整学习链路。目前已吸引461人学习下载。通过研究源码,读者可以掌握Django项目的分层设计、数据库集成方法及可扩展管理系统的构建思路;配套的文档与数据库脚本则便于快速还原运行环境,PPT和LW材料可用于答辩汇报或技术分享。整个包目录结构清晰,适合边读源码边对照实践,系统性提升Python Web开发能力。
1. 基于 Python 的舆情分析系统:不只是一份能跑的 Django 毕设源码
手里这套 Python 网络舆情分析系统,拿到手第一眼可能会被“项目源码 + 数据库脚本 + 文档 + LW + PPT”这几个字误导,以为又是一份纯应付答辩的模板工程。但把源码拆开看下来,它实际上是一个标准的 Django 管理后台 + 舆情数据采集分析的前后端一体项目,数据库脚本、ORM 模型、后台管理页面、图表展示都有完整实现,拿来复现 Python 实战项目、补数据库集成经验,甚至是直接改造成毕设,都够用。
对新手来说,这份源码最大的好处是能同时看到“Web 页面怎么和数据库交互”“舆情数据怎么从入库到展示”这两条完整链路;对熟手来说,它是一份能快速扩展的骨架——加采集器、换分词库、接情感分析接口,改造点都很清楚。下面按我拆项目的习惯,从技术栈选型、数据库脚本导入、核心模块实现、参数调节到避坑记录,一条线讲完。
2. 技术栈与数据库设计:Django 的 MVT 架构和 ORM 是怎么落地的
2.1 为什么选 Django 这套技术栈
这个项目用的是 Python 最主流的 Web 框架 Django,原因是舆情分析系统的典型场景——数据采集入库、后台管理、统计展示——几乎都是 CRUD 加聚合查询,Django 自带的 Admin 后台和 ORM 能省掉一大半重复劳动。项目里能看到 layui.css、admin.css 这类文件,说明前端管理页面用的是 Layui 这套轻量 UI 框架,搭配 Django 模板引擎渲染,不需要单独写前端工程。
Django 的 MVT 架构在项目里分得很清楚:Model 层负责舆情数据表的映射,View 层接收请求、处理业务逻辑,Template 层渲染页面。实际读源码的时候,建议按这个顺序走:先看 models.py 里的表结构,再看 views.py 里的业务函数,最后看 urls.py 里的路由配置,这样整条链路很快就通了。
2.2 数据库模型设计:舆情数据表怎么建
项目提供数据库脚本,但先看 models.py 更能理解表结构的设计意图。舆情分析系统的核心表通常包含舆情信息表,字段一般有标题、来源、发布时间、正文内容、情感标签、采集时间等。用 Django 的 ORM 定义大致长这样:
# models.py from django.db import models class NewsInfo(models.Model): title = models.CharField(max_length=200, verbose_name='标题') source = models.CharField(max_length=50, verbose_name='来源') content = models.TextField(verbose_name='正文内容') publish_time = models.DateTimeField(verbose_name='发布时间') sentiment = models.IntegerField( choices=[(1, '正面'), (0, '中性'), (-1, '负面')], default=0, verbose_name='情感标签' ) keyword = models.CharField(max_length=20, blank=True, verbose_name='关键词') created_at = models.DateTimeField(auto_now_add=True, verbose_name='入库时间') class Meta: db_table = 'news_info' verbose_name = '舆情信息' verbose_name_plural = verbose_name def __str__(self): return self.title这里的 sentiment 字段是整个舆情分析的核心——用整数存情感倾向而不是直接用字符串,好处是后续做统计聚合时可以直接按数值分组,GROUP BY sentiment一条 SQL 就能出饼图数据。created_at 设置成自动写入,保证入库时间不用手动维护。
2.3 数据库脚本导入:MySQL 建库建表全流程
项目里附带的数据库脚本通常是.sql文件,对应 MySQL 的建库建表语句。导入时先建库再导表,不要直接在默认库跑,不然表名冲突很难排查。常见操作是:
mysql -u root -p CREATE DATABASE yuqing DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE yuqing; SOURCE /path/to/yuqing.sql;注意字符集务必选utf8mb4而不是utf8。舆情数据经常带 emoji 表情或特殊符号,utf8在 MySQL 里是 3 字节,存 emoji 直接报错,utf8mb4是 4 字节,能完整存下来。这个项目里如果导入脚本后页面打开乱码,九成是字符集问题,后面避坑章节还会细说。
3. 核心功能拆解:舆情数据怎么从入库到展示
3.1 数据采集入库:ORM 批量操作与去重策略
舆情分析系统的第一环是数据进来。源码里在 views.py 或独立的 utils.py 里通常有一段数据采集入库的逻辑,不管是爬虫抓取还是手工导入,最终都要落到 ORM 写入。批量写入时优先用bulk_create,逐条save()在数据量上来后会非常慢:
# utils.py from .models import NewsInfo def batch_save_news(news_list): """ news_list: [{'title': '...', 'source': '...', 'content': '...', 'publish_time': '2025-01-01 10:00:00'}, ...] """ objs = [] for item in news_list: # 按标题 + 发布时间判断是否已存在,避免重复入库 if NewsInfo.objects.filter(title=item['title'], publish_time=item['publish_time']).exists(): continue objs.append(NewsInfo(**item)) if objs: NewsInfo.objects.bulk_create(objs, batch_size=500) return len(objs)batch_size=500是分批写入的大小,一般建议 200 到 1000 之间,太大容易超过 MySQL 的 max_allowed_packet 限制,太小又会增加数据库交互次数。去重用title + publish_time两个字段组合判断,比单独用标题可靠,因为不同来源转载时标题可能相同但发布时间不同。
3.2 情感分析实现:基于情感词典的判别逻辑
舆情系统的关键输出是情感标签。源码里的实现方式通常不是调用大模型接口,而是用情感词典打分——维护一个正面词表和一个负面词表,对正文分词后在词表里匹配打分。这种方式的好处是离线可跑、解释性强,也适合毕设答辩时讲清楚原理:
# sentiment.py import jieba POSITIVE_WORDS = set(['支持', '满意', '优秀', '点赞', '利好', '提升']) NEGATIVE_WORDS = set(['反对', '投诉', '失望', '严重', '违规', '下跌']) def analyze_sentiment(text): words = jieba.lcut(text) score = 0 for w in words: if w in POSITIVE_WORDS: score += 1 elif w in NEGATIVE_WORDS: score -= 1 if score > 0: return 1 # 正向 elif score < 0: return -1 # 负向 return 0 # 中性这个方法看着简单,但有几个坑必须说明白。分词结果直接影响情感打分——比如“不支持”会被 jieba 切成“不”和“支持”,“支持”是正面的,但整体语义是负面的,词典法天然处理不了否定前缀。一个妥协做法是把“不”“无”“没”等否定词纳进来,如果在情感词前 2 个词内出现,权重反转。源码里如果没做这层处理,改造时优先级最高,因为否定场景在舆情数据里太常见了。
3.3 可视化与统计页面:ORM 聚合查询做数据图表
后台管理页面展示舆情趋势时,用的是 Django ORM 的聚合查询。按天统计舆情数量、按情感类型分组,都是这类系统的标配需求。用django.db.models的Count能直接出结果:
# views.py from django.db.models import Count from django.shortcuts import render from .models import NewsInfo from django.utils import timezone from datetime import timedelta def dashboard(request): # 最近 7 天每日舆情数量 end_date = timezone.now() start_date = end_date - timedelta(days=6) daily_data = (NewsInfo.objects .filter(created_at__range=[start_date, end_date]) .extra({'day': "DATE_FORMAT(created_at, '%%Y-%%m-%%d')"}) .values('day') .annotate(total=Count('id')) .order_by('day')) # 情感类型分布 sentiment_data = (NewsInfo.objects .values('sentiment') .annotate(total=Count('id')) .order_by('sentiment')) return render(request, 'admin/dashboard.html', { 'daily_data': list(daily_data), 'sentiment_data': list(sentiment_data), })这里的extra里面用了DATE_FORMAT函数,在 MySQL 下可以把created_at按天格式化后分组。注意%%Y是 Django 转义后的写法,直接在 MySQL 里是%Y,写错一个百分号,日期分组就查不出数据。这个统计结果可以直接喂给前端图表库,Layui 自带的layui.use('table')或 ECharts 都行,数据格式统一成[{day: '2025-06-01', total: 12}]这样的列表就能渲染。
4. 参数与运行配置:让项目在自己的环境里跑起来
4.1 Django 项目配置与启动流程
拿到源码后第一步不是直接runserver,而是先检查 settings.py 里的环境配置。数据库连接、静态文件路径、时区这三个地方,是九成运行报错的重灾区。一个典型的配置长这样:
# settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'yuqing', # 数据库名 'USER': 'root', # 数据库用户 'PASSWORD': '123456', # 改成自己的密码 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': {'charset': 'utf8mb4'}, } } TIME_ZONE = 'Asia/Shanghai' USE_TZ = True STATIC_URL = '/static/' STATICFILES_DIRS = [BASE_DIR / 'static']OPTIONS里强制指定utf8mb4是防止读取时中文变乱码的关键。USE_TZ = True加上TIME_ZONE = 'Asia/Shanghai'的组合,会让 Django 在数据库里存 UTC 时间、展示时转本地时间,查询时用datetime.now()还是会出偏差——上面统计代码里我用timezone.now()就是因为这个。
启动前先迁移数据库,再创建管理员账号:
pip install django pymysql jieba mysqlclient python manage.py makemigrations python manage.py migrate python manage.py createsuperuser python manage.py runserver 0.0.0.0:8000pymysql 和 mysqlclient 只需要装一个。通常 Django 连 MySQL 优先装 mysqlclient,但它在 Windows 上常常装不上,这时改用 pymysql,并在__init__.py里写pymysql.install_as_MySQLdb()兼容,这个操作是源码里比较常见的处理方式。
4.2 舆情分析参数调节:情感词典与采集频率
情感词典的维护直接影响分析结果的准确率。源码自带的情感词典不可能覆盖所有领域词汇,通用词表在金融、教育、医疗等垂直场景下准确率会明显下降。实际操作中,我会把词典独立成一个words.txt文件按行存放,每次从后台管理页面追加词汇,不重新部署代码:
# 添加词汇后格式,每行一个词 好评 值得推荐 体验不错 虚假宣传 问题严重采集频率和分页参数在视图层控制。页面列表展示用 Django 的分页器,每页条数和最大展示范围都能调:
# views.py from django.core.paginator import Paginator def news_list(request): page = request.GET.get('page', 1) keyword = request.GET.get('keyword', '') news_qs = NewsInfo.objects.order_by('-publish_time') if keyword: news_qs = news_qs.filter(title__icontains=keyword) paginator = Paginator(news_qs, 10) # 每页 10 条 page_obj = paginator.get_page(page) return render(request, 'admin/news_list.html', {'page_obj': page_obj})分页器参数有讲究:Paginator(news_qs, 10)里的 10 是每页条数,数据量大时不要设置超过 50,否则页面渲染会明显卡顿;get_page(page)比page(page)好在页码越界时不会抛异常,自动返回最后一页。
5. 常见问题与避坑:复现这套系统我踩过的坑
5.1 数据库脚本导入时报错“Unknown collation”
现象:执行SOURCE yuqing.sql时报错,提示Unknown collation: 'utf8mb4_0900_ai_ci'。
原因:项目是在 MySQL 8.0 环境下导出的数据库脚本,默认排序规则是utf8mb4_0900_ai_ci,但你本地用的可能是 MySQL 5.7 或更低版本,不支持这个排序规则。
解决:用文本编辑器打开 SQL 文件,全局替换utf8mb4_0900_ai_ci为utf8mb4_general_ci,保存后再执行导入。这是一个很常见的兼容性问题,适合在毕设文档的“运行环境”部分特别标注出来。
5.2 Django 管理后台登录后样式丢失
现象:访问/admin/后台能登录,但页面全是纯文本,CSS 样式完全没加载。
原因:Django 的开发服务器在 DEBUG 模式下不会自动处理 Admin 自带的静态文件,需要配置STATIC_ROOT并执行collectstatic,或者直接在 settings.py 里把STATICFILES_DIRS指向 Django 源码的 admin 静态目录——但后者不优雅,部署时必踩。
解决:做一次静态文件收集:
python manage.py collectstatic然后把 settings.py 里的STATIC_ROOT指向一个真实存在的目录,比如项目根目录下的static_collected。如果还在开发阶段,也可以直接把django.contrib.admin的静态文件路径手动加进STATICFILES_DIRS,但这种方法只适合临时调试。
5.3 中文乱码与 emoji 存储失败
现象:舆情正文里有 emoji 表情时,写入数据库报错,或者保存后读出来全是???。
原因:数据库表字符集不是utf8mb4,或者 Django 连接 MySQL 时没有指定 charset。MySQL 的小于 5.5.3 的版本完全不支持 4 字节 UTF-8 字符,5.5+ 需要显式使用utf8mb4。
解决:两步走。第一步改表:
ALTER DATABASE yuqing CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE news_info CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;第二步在 Django 的数据库配置OPTIONS里加'charset': 'utf8mb4',然后重启服务。这套组合下来,emoji 和生僻字都能正常存取。
5.4 bulk_create 大批量插入时主键冲突
现象:第一次批量导入数据成功,第二次跑同样的采集脚本时报主键重复,部分数据没写进去。
原因:bulk_create遇到重复主键默认是整体报错,而不是跳过。如果表的主键用的是自增 id,第二次导入时 id 不会重复,但项目如果把 title 设置成了唯一索引,就会撞上。
解决:批量导入前先做一次去重查询,在 Python 层面过滤掉已存在的记录,或者直接改用INSERT IGNORE语义——Django 的bulk_create支持ignore_conflicts=True参数:
NewsInfo.objects.bulk_create(objs, batch_size=500, ignore_conflicts=True)注意ignore_conflicts=True是在 MySQL 5.7+ 才生效,并且它会忽略所有冲突,不只会忽略主键冲突,其他约束冲突也会被静默吞掉,所以最好仍然在业务端先做去重。
5.5 分页点击第 2 页后筛选条件丢失
现象:搜索关键词后点击第 2 页,列表又变回全部数据,筛选条件没了。
原因:分页链接只生成了?page=2,没有把keyword参数拼接进去。这是 Django 分页最常见的翻车点。
解决:在模板里生成分页链接时带上原来查询参数:
# views.py 里拿到当前请求的完整 query dict,去掉 page 再传给模板 base_query = request.GET.copy() if 'page' in base_query: del base_query['page'] page_base = base_query.urlencode() # keyword=xxx模板里分页链接写成?{{ page_base }}&page={{ page_obj.next_page_number }},这样第 2 页依然带着关键词。这个细节没处理好的话,在答辩演示时很容易被问住。
6. 进阶验证技巧:用一条命令检查整条链路是否跑通
项目改完、服务跑起来之后,很多人的验证方式是打开浏览器点一圈页面,觉得界面能显示就算成功。但后端的数据链路有没有真通,光看页面是不够的——页面可能读取的是缓存或者前端写死的假数据。我会用 Django 的 shell 直接验证核心链路,比如批量入库 10 条测试数据后立即查统计结果:
python manage.py shell -c " from datetime import timedelta from django.utils import timezone from newsapp.models import NewsInfo # 清空测试数据 NewsInfo.objects.all().delete() # 造 10 条数据,带不同情感标签 for i in range(10): NewsInfo.objects.create( title=f'测试舆情{i}', source='test', content='这是一个用于验证系统的测试文本', publish_time=timezone.now() - timedelta(hours=i), sentiment=i % 3 - 1 ) # 验证统计查询 from django.db.models import Count print('总数:', NewsInfo.objects.count()) print('按情感分组:', list(NewsInfo.objects.values('sentiment').annotate(c=Count('id')))) "输出里能看到总数是 10,按情感分组有三组数字,如果分组结果符合预期,说明从 ORM 到数据库再到统计聚合,这条路是通的。页面展示最多只是把这段数据渲染成了图表,数据源没问题,页面基本不会出大错。从那以后我每次调完采集脚本,都会用这种 shell 直查的方式先验证数据链路,再开页面看效果,省掉了一大半浏览器刷新排查的时间。
另外一个值得做的小技巧是打开 Django 的 SQL 日志,观察 ORM 生成的 SQL 是否合理。在 settings.py 里临时加一段日志配置:
LOGGING = { 'version': 1, 'handlers': {'console': {'class': 'logging.StreamHandler'}}, 'loggers': {'django.db.backends': {'handlers': ['console'], 'level': 'DEBUG'}}, }然后跑任何页面,终端里会打印出所有实际执行 SQL。看到SELECT * FROM news_info这种不带条件的全表扫描出现在列表页时,就该给 view 加过滤条件或分页了;看到 1 秒内重复执行两三遍一模一样的 SQL,就说明有 N+1 查询问题,需要用select_related或prefetch_related优化。舆情分析系统的数据量一上来,这两个优化点直接决定后台页面会不会卡死。
这套项目源码里的核心链路——采集入库、情感分析、聚合统计——全部拆开验证过之后,剩下的就是在自己业务方向上做扩展了。希望这份拆解笔记能帮你把项目真正跑通,也帮你在毕设答辩或项目复盘时,能清楚地讲出每一步背后的原理和坑。
本文还有配套的精品资源,点击获取