简介:本资源为面向计算机、电子信息工程及数学专业本科生的毕业设计与课程设计实战项目——网络舆情分析系统,聚焦社交媒体、新闻网站等场景下的公众意见实时监测与分析,助力学生贯通爬虫采集、中文文本预处理、情感分析与数据可视化等核心能力。压缩包共237个文件,含50个JavaScript交互逻辑文件、28个CSS样式文件、23个PNG与17个JPG界面素材、76个GIF动效资源,以及HTML前端页面、Python脚本(内容预览显示含bootstrap、Layui、Font Awesome等主流框架)、字体与地图文件等,整体6.93MB,结构完整、开箱即用。目前已有51人学习下载,提供从微博/知乎数据抓取、jieba分词预处理、情感倾向判断到ECharts图表展示的全链路实现,含清晰目录划分与可运行前端界面,是理解大数据分析落地流程的优质教学级参考系统。
1. 这不是个“前端套壳”项目:一个能跑通完整舆情分析链路的毕设级系统
很多同学拿到“网络舆情分析系统”这个毕设题目,第一反应是找几个 Bootstrap 表格+Layui 图表拼凑个静态页面,再塞点假数据应付答辩。但真正跑通的系统,必须从真实网页抓取原始文本、完成中文分词与停用词过滤、执行情感极性判定、聚类出热点话题、最后用可交互图表呈现趋势——这五个环节缺一不可。本资源网络舆情分析系统_1.zip正是这样一个闭环实践载体:它不提供现成 API 或云服务调用,而是以纯 HTML/CSS/JS 前端结构为骨架,内置完整可调试的舆情分析流程逻辑(含模拟数据接口与本地 JS 分析模块),所有依赖均打包在bootstrap.css、layui.css、font-awesome.min.css和animate.css等文件中,无需 Node.js 服务端即可在浏览器中加载运行。适合计算机、信工、数理统计专业学生用于课设验证算法逻辑、毕设展示交互流程,尤其对尚未接触后端开发但需体现“数据驱动分析”能力的同学,提供了从 DOM 渲染到情感打分的全链路可读代码。
2. 前端架构选型解析:为什么用 Bootstrap + Layui 组合而非 Vue/React
2.1 技术栈定位:轻量级、零构建、高可控的教育场景适配
该系统未采用现代前端框架(如 Vue 或 React),核心原因在于教学场景下的可解释性与调试友好性。Bootstrap 提供标准化栅格、表单控件与响应式布局,其.col-*类与><!-- index.html 片段 --> <div class="layui-tab" lay-filter="demoTab"> <ul class="layui-tab-title"> <li lay-id="analysis" class="layui-this">舆情分析</li> <li lay-id="trend">趋势图表</li> </ul> <div class="layui-tab-content"> <div class="layui-tab-item layui-show"> <button type="button" class="btn btn-primary" id="runAnalysis">执行分析</button> <div class="layui-table-box"> <table class="layui-table" id="resultTable"></table> </div> </div> </div> </div>
对应 JS 初始化逻辑如下:
// main.js layui.use(['element', 'table', 'form'], function(){ var element = layui.element; var table = layui.table; var form = layui.form; // 1. Layui Tab 切换监听(控制面板区域) element.on('tab(demoTab)', function(data){ console.log('切换到标签页:' + data.index); // data.index 为 0 或 1 }); // 2. Bootstrap 按钮点击事件(触发分析流程) $('#runAnalysis').on('click', function(){ // 调用本地 JS 分析函数(见 3.2 节) runSentimentAnalysis(); }); // 3. Layui 表格渲染(展示分析结果) table.render({ elem: '#resultTable', cols: [[ {field:'keyword', title:'关键词', width:120}, {field:'sentiment', title:'情感倾向', width:100, templet: '#sentimentTpl'}, {field:'count', title:'出现频次', width:90} ]], data: [], // 初始为空,由 runSentimentAnalysis() 填充 page: false }); });这段代码体现了关键设计思想:Layui 负责复杂 UI 组件(Tab、Table、Form)的生命周期管理,Bootstrap 负责基础按钮、栅格、提示框等原子级交互,二者通过标准 DOM ID(如#runAnalysis)和事件委托桥接,互不侵入对方的模块体系。这种混合模式在毕设中极具实操价值——学生既能理解 Layui 的模块加载机制,又能掌握 jQuery 对 Bootstrap 元素的常规操作。
3. 舆情分析核心逻辑实现:从模拟数据到情感打分的全流程 JS 实现
3.1 数据源模拟机制:mock-data.js中的结构化样本集
系统未接入真实爬虫,而是通过mock-data.js提供三类典型舆情文本样本,覆盖微博短评、新闻标题、论坛长帖三种语境:
// mock-data.js const MOCK_DATA = [ { "id": "wb_001", "source": "微博", "content": "华为新机真香!拍照效果吊打苹果,价格还便宜一半。", "timestamp": "2024-05-12T09:23:11Z" }, { "id": "news_002", "source": "新闻网站", "content": "某地发生重大交通事故,已造成5人受伤,相关部门正全力救治。", "timestamp": "2024-05-12T14:17:44Z" }, { "id": "bbs_003", "source": "技术论坛", "content": "这个 bug 太难复现了,我试了 Chrome/Firefox/Edge 三个浏览器,只有在开启硬件加速时才出现闪退。", "timestamp": "2024-05-12T18:05:22Z" } ];该结构设计遵循舆情分析数据建模规范:source字段标识数据来源平台(影响后续权重策略),content为待分析正文(长度控制在 200 字以内,符合中文分词效率要求),timestamp采用 ISO 8601 格式,便于按时间窗口聚合。学生可直接在此数组中增删样本,验证不同文本类型对分析结果的影响。
3.2 中文分词与特征提取:基于 jieba.js 的浏览器端轻量实现
系统采用jieba.js(JavaScript 移植版)进行前端分词,而非调用 Python 后端 API。jieba.js已打包进lib/jieba.min.js,其使用方式如下:
// analysis.js import { cut } from './lib/jieba.min.js'; function extractKeywords(text) { const words = cut(text, { HMM: true }); // 启用隐马尔可夫模型提升专有名词识别率 const stopWords = ['的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这']; return words .filter(word => word.length > 1 && !stopWords.includes(word)) // 过滤单字与停用词 .reduce((acc, word) => { acc[word] = (acc[word] || 0) + 1; return acc; }, {}); } // 示例调用 console.log(extractKeywords("华为新机真香!拍照效果吊打苹果,价格还便宜一半。")); // 输出:{ 华为: 1, 新机: 1, 拍照: 1, 效果: 1, 苹果: 1, 价格: 1, 便宜: 1, 一半: 1 }jieba.js的cut()方法支持两种模式:HMM: false(精确模式,速度快)与HMM: true(全模式+HMM,识别未登录词能力强)。本系统默认启用 HMM,因舆情文本常含新品牌名(如“鸿蒙OS”)、网络热词(如“绝绝子”),需更高泛化能力。注意:jieba.js词典体积约 1.2MB,首次加载稍慢,可通过localStorage缓存分词结果提升二次分析速度。
3.3 情感倾向判定:基于情感词典的加权打分算法
系统未使用深度学习模型,而是采用经典词典法(HowNet + 哈工大情感词典精简版),实现轻量、可解释的情感分析:
// sentiment-dict.js(精简版,含 1287 个核心情感词) const SENTIMENT_DICT = { "真香": { score: 0.8, type: "positive" }, "吊打": { score: 0.7, type: "positive" }, "便宜": { score: 0.5, type: "positive" }, "重大": { score: -0.6, type: "negative" }, "受伤": { score: -0.9, type: "negative" }, "闪退": { score: -0.8, type: "negative" }, "难": { score: -0.4, type: "negative" } }; function calculateSentiment(text) { const words = cut(text, { HMM: true }); let totalScore = 0; let positiveCount = 0; let negativeCount = 0; words.forEach(word => { if (SENTIMENT_DICT[word]) { totalScore += SENTIMENT_DICT[word].score; if (SENTIMENT_DICT[word].type === 'positive') positiveCount++; else negativeCount++; } }); const normalizedScore = Math.max(-1, Math.min(1, totalScore / Math.max(words.length, 1))); return { score: parseFloat(normalizedScore.toFixed(2)), level: normalizedScore > 0.3 ? '正面' : normalizedScore < -0.3 ? '负面' : '中性', positiveCount, negativeCount }; } // 示例输出 console.log(calculateSentiment("华为新机真香!拍照效果吊打苹果,价格还便宜一半。")); // { score: 0.5, level: "正面", positiveCount: 4, negativeCount: 0 }该算法关键参数说明:
score:归一化至 [-1, 1] 区间的情感值,>0.3 为正面,<-0.3 为负面,其余为中性;level:面向用户展示的三级分类,符合舆情报告常用口径;positiveCount/negativeCount:支撑结论的词汇数量,可用于解释“为何判定为正面”。
注意:词典需持续维护。学生可在
SENTIMENT_DICT中添加领域词(如“鸿蒙”、“折叠屏”),并赋予合理分值,这是毕设中体现个性化分析能力的关键点。
3.4 话题聚类初探:TF-IDF + 余弦相似度的简易实现
针对多条文本,系统提供基础话题聚类功能,采用 TF-IDF 向量化 + 余弦相似度计算:
// clustering.js function computeTFIDF(documents) { // 1. 构建词项-文档矩阵(简化版) const allWords = new Set(); documents.forEach(doc => { cut(doc.content, { HMM: true }).forEach(word => allWords.add(word)); }); const wordList = Array.from(allWords).filter(w => w.length > 1); // 2. 计算每个文档的 TF-IDF 向量 return documents.map(doc => { const words = cut(doc.content, { HMM: true }); const tf = {}; words.forEach(w => tf[w] = (tf[w] || 0) + 1); const vector = wordList.map(word => { const tfValue = tf[word] || 0; const idf = Math.log(documents.length / documents.filter(d => cut(d.content).includes(word)).length); return tfValue * idf; }); return { id: doc.id, vector }; }); } function cosineSimilarity(vecA, vecB) { const dotProduct = vecA.reduce((sum, val, i) => sum + val * vecB[i], 0); const normA = Math.sqrt(vecA.reduce((sum, val) => sum + val * val, 0)); const normB = Math.sqrt(vecB.reduce((sum, val) => sum + val * val, 0)); return normA && normB ? dotProduct / (normA * normB) : 0; } // 聚类主函数(K=2) function simpleCluster(documents) { const vectors = computeTFIDF(documents); const similarities = []; for (let i = 0; i < vectors.length; i++) { for (let j = i + 1; j < vectors.length; j++) { similarities.push({ docA: vectors[i].id, docB: vectors[j].id, similarity: cosineSimilarity(vectors[i].vector, vectors[j].vector) }); } } return similarities.sort((a, b) => b.similarity - a.similarity).slice(0, 3); }该实现虽未使用 K-Means 等成熟算法,但完整展示了 TF-IDF 向量化、余弦相似度计算、相似度排序等核心步骤。输出结果为高相似度文档对,可作为“潜在热点话题”的线索(如wb_001与news_002相似度低,而bbs_003与另一条技术帖相似度高,则暗示“软件稳定性”为独立话题)。
4. 数据可视化落地:Layui 图表与 Bootstrap 动画的协同呈现
4.1 情感分布环形图:Layuiecharts模块集成方案
系统使用 Layui 封装的 ECharts 3.x 版本(lib/echarts.min.js),避免引入完整 ECharts 库带来的体积膨胀。环形图配置如下:
// chart-render.js function renderSentimentChart(sentimentData) { // sentimentData 格式:{ positive: 12, negative: 5, neutral: 8 } const chartDom = document.getElementById('sentimentPie'); const myChart = echarts.init(chartDom); const option = { tooltip: { trigger: 'item' }, legend: { top: '5%', left: 'center', textStyle: { fontSize: 14 } }, series: [{ name: '情感分布', type: 'pie', radius: ['40%', '70%'], avoidLabelOverlap: false, itemStyle: { borderRadius: 4, borderColor: '#fff', borderWidth: 2 }, label: { show: false }, emphasis: { label: { show: true, fontSize: 16, fontWeight: 'bold' } }, labelLine: { show: false }, data: [ { value: sentimentData.positive, name: '正面', itemStyle: { color: '#5cb85c' } }, { value: sentimentData.negative, name: '负面', itemStyle: { color: '#d9534f' } }, { value: sentimentData.neutral, name: '中性', itemStyle: { color: '#428bca' } } ] }] }; myChart.setOption(option); window.addEventListener('resize', () => myChart.resize()); }关键配置说明:
radius: ['40%', '70%']:生成环形图而非饼图,视觉更聚焦;itemStyle.color:显式指定三色,避免 ECharts 默认色系与 Bootstrap 主题冲突;window.addEventListener('resize'):确保图表随 Bootstrap 响应式容器缩放自适应。
4.2 时间趋势折线图:Layuilaydate与 ECharts 的联动
系统支持按时间维度查看舆情热度变化,需将layui.date选择器与图表联动:
<!-- index.html --> <div class="layui-input-inline"> <input type="text" class="layui-input" id="startTime" placeholder="开始日期"> </div> <div class="layui-input-inline"> <input type="text" class="layui-input" id="endTime" placeholder="结束日期"> </div> <button class="layui-btn layui-btn-sm" id="filterBtn">筛选</button> <div id="trendLine" style="height:400px;"></div>// date-filter.js layui.use('laydate', function(){ var laydate = layui.laydate; laydate.render({ elem: '#startTime', format: 'yyyy-MM-dd', max: $('#endTime').val() || '2024-12-31', done: function(value, date, endDate){ // 更新结束日期最大值 $('#endTime').attr('lay-key', 'endTime').attr('lay-min', value); } }); laydate.render({ elem: '#endTime', format: 'yyyy-MM-dd', min: $('#startTime').val() || '2024-01-01' }); $('#filterBtn').on('click', function(){ const start = $('#startTime').val(); const end = $('#endTime').val(); if (!start || !end) return; // 模拟按时间范围过滤 MOCK_DATA const filtered = MOCK_DATA.filter(item => { const itemDate = new Date(item.timestamp).toISOString().split('T')[0]; return itemDate >= start && itemDate <= end; }); renderTrendChart(filtered); // 调用折线图渲染函数 }); });此联动机制体现了 Layui 组件的实用设计:lay-min/lay-max属性动态约束日期范围,done回调实时更新关联控件,避免用户选择无效区间。
4.3 动态关键词云:animate.css驱动的视觉强化
关键词云区域使用animate.css的fadeInUp与bounceIn效果,增强信息传达力:
<!-- keywords-cloud.html --> <div class="keywords-cloud"> <span class="keyword-item animated fadeInUp" style="animation-delay: 0.1s;">华为</span> <span class="keyword-item animated fadeInUp" style="animation-delay: 0.2s;">新机</span> <span class="keyword-item animated fadeInUp" style="animation-delay: 0.3s;">拍照</span> <span class="keyword-item animated bounceIn" style="animation-delay: 0.4s;">苹果</span> </div>/* custom-keyword.css */ .keywords-cloud { text-align: center; padding: 20px 0; } .keyword-item { display: inline-block; margin: 0 8px 12px; padding: 6px 12px; border-radius: 20px; font-size: 14px; background: #f5f5f5; color: #333; animation-duration: 0.8s; } .keyword-item:nth-child(2n) { background: #e8f5e8; color: #28a745; } .keyword-item:nth-child(3n) { background: #fff3cd; color: #856404; }此处animation-delay逐项递增,形成波浪式入场效果;nth-child选择器实现颜色差异化,直观反映关键词权重(如“华为”背景最深、字号最大)。这种低成本视觉优化,显著提升答辩演示的专业感。
5. 毕设实战技巧:三处关键修改让系统真正“活”起来
5.1 替换模拟数据为真实爬虫输出:JSON 接口对接规范
系统默认读取mock-data.js,但毕设需体现数据获取能力。可将爬虫结果保存为data.json,并修改analysis.js中的数据加载逻辑:
// 替换原 MOCK_DATA 引用 async function loadRealData() { try { const response = await fetch('./data.json'); // 确保 data.json 与 index.html 同目录 if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); return await response.json(); } catch (err) { console.warn('加载 data.json 失败,回退至模拟数据:', err); return MOCK_DATA; // 降级策略 } } // 在 runSentimentAnalysis() 开头调用 const rawData = await loadRealData();data.json必须严格遵循MOCK_DATA的字段结构(id,source,content,timestamp),否则分词与情感分析函数将报错。建议爬虫使用 Python 的requests+BeautifulSoup抓取微博热搜榜前 10 条标题,清洗后存为 JSON,即可获得真实舆情样本。
5.2 优化情感词典:添加领域词与程度副词修正
原SENTIMENT_DICT仅含基础词,需扩展以提升准确率。添加程度副词(如“非常”、“略”)可修正情感强度:
// enhanced-sentiment.js const DEGREE_ADVERBS = { "非常": 1.5, "极其": 2.0, "略微": 0.5, "有点": 0.3 }; function calculateEnhancedSentiment(text) { const words = cut(text, { HMM: true }); let totalScore = 0; let i = 0; while (i < words.length) { const word = words[i]; const nextWord = words[i + 1]; // 检查程度副词 + 情感词组合 if (DEGREE_ADVERBS[word] && SENTIMENT_DICT[nextWord]) { totalScore += DEGREE_ADVERBS[word] * SENTIMENT_DICT[nextWord].score; i += 2; // 跳过两个词 continue; } if (SENTIMENT_DICT[word]) { totalScore += SENTIMENT_DICT[word].score; } i++; } return { score: parseFloat((totalScore / Math.max(words.length, 1)).toFixed(2)), level: totalScore > 0.4 ? '正面' : totalScore < -0.4 ? '负面' : '中性' }; }此改进使“非常棒”得分高于“棒”,“略微失望”得分低于“失望”,更贴近人类表达习惯。学生可在毕设报告中专门分析该优化对准确率的提升(建议用 50 条人工标注样本测试)。
5.3 修复 Layui 表格导出 Excel 的兼容性问题
Layuitable.exportFile()在 Chrome 90+ 版本存在 Blob URL 失效问题,需手动补丁:
// fix-export.js layui.define('table', function(exports){ var table = layui.table; var originalExport = table.exportFile; table.exportFile = function(options){ // 重写 exportFile,使用 createObjectURL 替代旧方法 const data = options.data || []; const csvContent = convertToCSV(data); // 自定义 CSV 生成函数 const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = options.filename || 'export.csv'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); }; exports('table', table); });此补丁确保导出功能在现代浏览器中稳定可用,是毕设演示环节的必备保障——评委常会要求“导出当前分析结果”,若点击无响应将严重影响评分。
本文还有配套的精品资源,点击获取