ARTICLE DETAIL

建站实战干货

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

微博舆情分析系统:Python爬虫、分词与Flask可视化全解析

2026/10/3 5:24:11 拓冰建站 浏览量
微博舆情分析系统:Python爬虫、分词与Flask可视化全解析 简介一份基于Python实现的微博舆情分析系统毕业设计源码主要面向计算机相关专业学生、毕业设计者以及社交媒体数据分析爱好者。该系统完整覆盖微博数据采集、文本清洗、情感倾向分析、热点词提取与结果可视化等关键环节并提供了可运行的前后端代码能够直接用于课程设计、毕业设计演示或二次开发学习。压缩包共49个文件总体积约2.94MB包含Python后端源码py、前端页面样式与逻辑css/js、接口配置信息json/xml、数据库初始化脚本sql以及项目部署说明和核心代码目录myProject。目录划分清晰便于按功能模块快速定位部署说明zip附带了从环境准备到启动运行的指引对初学者非常友好。此外资源标签中的Java字样提示项目可能采用了多语言混合设计有助于深入理解不同技术栈在Web系统中的应用。目前已有187人学习下载适合希望快速上手舆情分析系统搭建的读者作为毕业设计或实战项目参考。1. 微博舆情分析系统一个能直接跑起来的 Python 毕设源码「微博舆情分析系统」这个关键词在毕业设计平台上一搜一大片但真正 zip 解压就能跑起来的其实不多。这套 Python 源码是其中少见的完整实例爬虫负责从微博拿数据分析模块负责算热词和情感倾向Flask 后端配合 static 里的前端模板把结果渲染成页面前后端代码全在 myProject 目录里按部署说明配置环境后可以直接启动。它适合正在做毕业设计、课程设计的人也适合想搞明白爬虫、分词、Web 展示是怎么串起来的数据分析初学者。需要提醒一句压缩包标签里虽然带了 java那更多是检索标签核心实现是 Python别被这个带偏。2. 三层架构与目录拆解爬虫、分析、展示的数据流整理2.1 三层架构采集层、分析层、Web 层各管什么拿到压缩包先别急着跑把结构理清楚后面排错会省很多时间。这套系统从数据流上看是标准的三层最下面是采集层对应 xlwb_spider 和 spider 两个模块中间是分析层对应 analyze、hotword、api最上面是 Web 展示层入口是 app.py配合 templates 和 static 目录渲染页面。采集层的工作方式很简单直白用 requests 请求微博移动端接口拿到 JSON 数据解析出微博正文、用户昵称、发布时间、点赞数、评论数、转发数然后写入本地数据库。分析层则是在数据落库之后做两件事一是对微博文本做 jieba 分词和词频统计输出高频热词二是用情感词典给每条微博打一个情感分再聚合出整体倾向。Web 层做的事情是把这些分析结果通过 JSON 接口暴露给前端页面前端用图表库渲染成词云、柱状图和趋势线。2.2 为什么选 Python Flask 而不是 Java Spring Boot压缩包标签里的 java 容易让人误解实际上这套系统在技术选型上是一个典型的 Python 毕设项目。爬虫部分用 requests 这种轻量级 HTTP 库就能搞定没必要上 ScrapyWeb 端用 Flask 而不是 Django是因为毕设场景只需要两三个页面和 JSON 接口Flask 的灵活度更高代码量也更少。有个细节值得留意资源目录里有 pojo 这个命名这明显是从 Java 项目里带过来的习惯用 Java 的术语管数据模型类。实际内容还是 Python 的类或字典结构一般是定义微博、用户这类数据实体的。这是一个很常见的过渡期代码风格项目作者估计是先用 Java 思维设计了一遍数据模型再用 Python 实现不影响运行但你在读代码时要有这个心理预期。2.3 目录逐层拆解与入口文件定位我拆包时习惯先把目录树打出来再逐个模块过一遍。下面是一个按实际场景整理后的结构文件名如果和你的包略有出入不奇怪毕业设计项目整理代码时经常会有文件挪动myProject ├── app.py # Flask 入口启动服务 ├── analyze/ # 舆情分析情感打分、热词统计 ├── api/ # 对外 JSON 接口 ├── xlwb_spider/ # 微博爬虫主目录 │ └── spider/ # 具体爬虫实现 ├── pojo/ # 数据模型定义 ├── resource/ # 停用词表、情感词典等资源文件 ├── hotword # 热词结果输出目录或文件 ├── static/ # 前端样式和 JS 图表库 ├── templates/ # HTML 页面模板 └── .idea/ # PyCharm 工程配置第一步永远先看 app.py它是整个系统的入口路由怎么注册、接口怎么挂载、数据库怎么初始化全部能从这一个文件顺藤摸瓜查清楚。resource 目录里的停用词表和情感词典是分析效果好不好看的关键后面会专门讲。提示.idea 是 PyCharm 的项目配置目录对运行没有影响可以直接忽略。如果打开项目时 IDE 报错说找不到 Python 解释器从这里也能看出这套代码原本就是用 PyCharm 开发的。3. 微博爬虫 xlwb_spider请求参数、登录态与数据落库3.1 构造微博搜索接口从 keyword 到响应解析爬虫层的关键是选对接口。我拆过的毕设微博项目里绝大多数都走微博移动端接口也就是 m.weibo.cn 搜索页背后的接口因为它返回的是结构化 JSON不需要去解析复杂的 HTML 页面。下面这段代码是典型的请求构造方式import requests headers { User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X), Referer: https://m.weibo.cn/, Cookie: SCookie这里填你自己账号的登录Cookie } def fetch_weibo(keyword, page1, count50): url https://m.weibo.cn/api/container/getIndex params { containerid: 100103type1q keyword, page_type: searchall, page: page } resp requests.get(url, headersheaders, paramsparams, timeout10) data resp.json() if data.get(ok) ! 1: return [] cards data[data][cards] weibos [] for card in cards: if card.get(card_type) ! 9: continue mblog card.get(mblog, {}) weibos.append({ content: mblog.get(text, ), user: mblog[user][screen_name], time: mblog[created_at], like_count: mblog.get(attitudes_count, 0), comment_count: mblog.get(comments_count, 0), repost_count: mblog.get(reposts_count, 0) }) return weibos这里的参数有几个值得说明containerid 是搜索容器的内部标识q 后面拼上你要查的关键词page_type 设为 searchall 表示全网搜索改成 mention 之类的会变成搜索结果的分组方式。返回的 cards 里会混着多种 card_type只有 card_type 等于 9 的才是真正的微博卡片所以代码里先过滤一层再取 mblog 字段拿正文和互动数据。3.2 登录态与反爬Cookie、随机延时、重试策略微博这几年对自动爬取的管控挺严毕设代码里如果直愣愣地高频请求很快会被限制。我一般会把请求包装成带重试和延时的安全函数这样可以显著提高采集成功率import random import time def safe_request(url, headers, params, max_retry3): for attempt in range(max_retry): try: resp requests.get(url, headersheaders, paramsparams, timeout10) if resp.status_code 200: return resp elif resp.status_code in (401, 403): print(f第 {attempt 1} 次被拒绝确认Cookie是否失效) else: print(fHTTP {resp.status_code}) except requests.exceptions.Timeout: print(请求超时准备重试) time.sleep(random.uniform(3, 8)) return None随机延时是这类项目里最重要的反爬手段。固定延时会让对方服务器很容易识别出爬虫特征随机分布在 3 到 8 秒之间配合移动端的 User-Agent基本能跑完一个小规模毕业设计所需的数据量。Cookie 失效是爬虫翻车的最常见原因代码里如果发现连续出现 401不要反复重试直接提示人手去浏览器重新登录一次微博把新 Cookie 贴回来更实际。3.3 落库设计微博数据存成什么结构才能喂给分析模块爬下来的数据总得找个地方存。毕设项目常见的做法是 SQLite文件型数据库不需要额外装服务拷到哪都能跑。表结构长这样import sqlite3 conn sqlite3.connect(weibo_analysis.db) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS weibo ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT, user_name TEXT, publish_time TEXT, like_count INT, comment_count INT, repost_count INT, keyword TEXT ) ) conn.commit() def insert_weibo(rows, keyword): for row in rows: cursor.execute( INSERT INTO weibo (content, user_name, publish_time, like_count, comment_count, repost_count, keyword) VALUES (?, ?, ?, ?, ?, ?, ?), (row[content], row[user], row[time], row[like_count], row[comment_count], row[repost_count], keyword) ) conn.commit()这里有个容易被忽略的细节content 字段在接口里是带 HTML 标签的像 这种入库前最好用正则把标签去掉只保留纯文本否则后边分词会分出一堆 a、href 这样的垃圾词。keyword 字段是给每次采集打标签的方便分析层按关键词过滤数据。注意数据去重也值得做。翻页采集时微博接口偶尔会返回同一批数据我一般会在插入前按 user_name publish_time content 拼一个唯一键检查一遍或者在 SQLite 里建唯一索引后续跑任务就不会积累重复脏数据。4. 热词统计与情感分析analyze 和 api 模块的关键实现4.1 jieba 分词与停用词过滤热词表是怎么产生的热词统计是舆情分析系统最直观的产出。思路很朴素把所有微博文本丢给 jieba 分词统计每个词出现的频次去掉停用词和单字剩下的就是高频关键词。实际实现时分词结果的干净程度决定热词榜的质量import jieba from collections import Counter STOP_WORDS set() with open(resource/stopwords.txt, encodingutf-8) as f: STOP_WORDS set(line.strip() for line in f) def extract_hotwords(texts, top_n20): word_counter Counter() for text in texts: words jieba.cut(text) for word in words: word word.strip().lower() if len(word) 2: continue if word in STOP_WORDS or not word.isalpha(): continue word_counter[word] 1 return word_counter.most_common(top_n)stopwords.txt 是热词质量的命门。很多人直接拿网上的通用停用词表结果还是出现一堆「我们」「你们」「这种」「因为」因为这些词带有很强的场景性通用表覆盖不全。我一般会先跑一次分词把结果里出现频率最高的前两百个词打出来人工扫一遍把明显没意义的口语词补进停用词表再重跑一次效果立竿见影。4.2 情感打分情感词典加否定词和程度副词的权重毕设项目的情感分析绝大多数不用深度学习一套情感词典打分发就足够撑起整条链路。原理是给每个情感词一个正负分值正面的加 1负面的减 1再叠加否定词和程度副词的影响positive_words set(open(resource/positive.txt, encodingutf-8).read().split()) negative_words set(open(resource/negative.txt, encodingutf-8).read().split()) deny_words {不, 没, 无, 非, 莫, 别} degree_words {非常: 2.0, 很: 1.8, 有点: 0.7, 比较: 1.2, 太: 1.5} def sentiment_score(text): score 0 words jieba.cut(text) prev_deny False degree 1.0 for word in words: if word in deny_words: prev_deny True elif word in degree_words: degree degree_words[word] elif word in positive_words or word in negative_words: base 1 if word in positive_words else -1 if prev_deny: base -base score degree * base prev_deny False degree 1.0 return score这里边界要清楚词典法判断不了反讽和反语「这电影太好了」带着明显阴阳怪气的时候打出来可能还是正分。毕设答辩时能说清楚这个局限比硬吹模型准确率要加分得多。出发点不是追求完美而是用可解释的方式让老师和同学看得懂整个分析过程。4.3 Flask 路由与前端图表接口怎么把数据喂给 ECharts后端和前端之间通过 JSON 接口衔接app.py 里注册几个路由就能串起来from flask import Flask, render_template, jsonify, request app Flask(__name__) app.route(/) def index(): return render_template(index.html) app.route(/api/hotword) def hotword_api(): keyword request.args.get(keyword, 微博) hotwords extract_hotwords_by_keyword(keyword) sentiment sentiment_stats_by_keyword(keyword) return jsonify({ hotwords: hotwords, sentiment: sentiment }) app.route(/api/weibo) def weibo_api(): keyword request.args.get(keyword, 微博) rows query_weibo_by_keyword(keyword) return jsonify({list: rows}) if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)前端页面在 static 目录里引入 ECharts通过 fetch 拿到 /api/hotword 返回的数组再画成词云和柱状图。这里有个跨域陷阱要提醒如果前端页面和后端不在同一个端口上跑浏览器的 fetch 会被同源策略拦住。最省事的办法是让 Flask 同时负责渲染页面和提供接口前端页面直接请求相对路径而不是写死 http://localhost:8080 这样的绝对地址。5. 部署避坑微博爬虫与 Flask 项目最常见的五个问题5.1 现象压缩包解压到一半报错文件不全原因下载平台偶尔会出现 zip 传输不完整的情况另外有些压缩工具生成的 zip 带有伪加密标记解压时会误报需要密码导致代码目录缺失。解决先看压缩包体积和下载页显示的是否一致不一致就重新下载解压工具换成 7-Zip 或新版 WinRAR右键解压而不是双击预览。解压完成后核对 myProject 目录是否包含 app.py如果缺少这个文件说明解压不完整直接换工具重来。5.2 现象爬虫请求全部返回 401 或者 403原因Cookie 过期、失效或者某个关键词短时间内请求太频繁触发了平台风控。spider 代码里的 headers 写死了一个 Cookie你直接运行的时候用的还是作者当时的登录态。解决用浏览器登录微博账号打开开发者工具从 Network 面板里把当前请求的 Cookie 完整复制出来替换代码里 headers 的 Cookie 字段。替换后不要急着连续跑多个关键词先单关键词跑 10 条试试接口通不通通了再放开跑。跑的过程中看到 403 就停下来等几分钟而不是加大请求量。5.3 现象热词排行全是「我们」「什么」「就是」核心关键词一个看不到原因resource 目录里的停用词表不匹配你的数据场景或者分词后没有过滤非中文词汇。很多毕设项目自带的停用词表是直接从网上扒的通用版本覆盖不到口语化的微博文本。解决把 extract_hotwords 里 len(word) 2 的判断改成同时过滤纯符号和数字再补充停用词。我自己习惯的调试方式是先打印原始分词结果的前 500 个词人工识别高频干扰词追加到 stopwords.txt 里。追加过程重复两轮热词表基本就干净了。5.4 现象Flask 页面能打开但图表区域空白原因前端 fetch 接口报错或者返回的数据格式跟图表库预期不一致。最常见的是 JSON 里包含 Python 的 tupleECharts 收到后解析不出 [{name: ..., value: 123}] 这样的结构。解决先按 F12 打开浏览器开发者工具看 Console 和 Network 标签页里的报错。如果是 tuple 序列化问题在 Flask 接口里把返回数据强制转成 list 再交给 jsonify。另外确认 static/js 里的 ECharts 脚本有没有正确引入路径大小写都会导致加载失败。5.5 现象项目标签写的是 java以为要用 Spring Boot 和 Maven 环境原因资源平台上的检索标签通常是平台统一打的java 和 python 经常混标。拿到手的人按 Java 项目部署环境全部装错自然跑不起来。解决先打开 myProject 目录看文件后缀.py 为主就是 Python 项目只有一个 app.py 起步文件。环境上只需要 Python 3.8 以上版本装好 requirements.txt 里的 Flask、requests、jieba 依赖就够了不需要装 JDK 和 Maven。提示依赖安装慢是另一个高频问题。pip install 超时的换成清华源pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple。如果项目里没有 requirements.txt手动装三个包就够flask、requests、jieba。6. 验证技巧用一条热搜把整套链路冒烟测一遍部署完项目先别急着跑几十个关键词我习惯用一个固定热搜词做冒烟测试验证整条链路是通的再放量。比如拿「郑州暴雨」这类既有明确讨论度、又容易判断情感倾向的事件跑一遍完整流程。第一步用网站页面手动触发爬虫抓 50 到 100 条微博观察采集层是否有报错。确认数据入库后去 SQLite 里数一下记录数正常情况下 keywords 字段能查到对应标签的数据。第二步调出热词接口看 top20 结果里是否包含事件核心词。如果核心词不在大概率是分词或停用词表问题回到第 4 章的方法去补词。第三步检查情感分析结果。拿人工看过的一批微博比对比如明显正面的「感动」「致敬」类文本打分应该为正明显负面的「谴责」「愤怒」类文本打分应该为负。我的习惯是抽 20 条人工标注结果跟系统打分做一次粗略比对准确率能到百分之七八十就说明整个分析链路是能自洽的。最后写一个最简单的接口自检脚本把上述步骤固化import requests def smoke_test(keyword郑州暴雨): hot_resp requests.get(http://127.0.0.1:5000/api/hotword, params{keyword: keyword}, timeout10) assert hot_resp.status_code 200 hot_data hot_resp.json() assert len(hot_data[hotwords]) 0, 热词为空检查分词层 print(热词接口正常前5个热词:, hot_data[hotwords][:5]) weibo_resp requests.get(http://127.0.0.1:5000/api/weibo, params{keyword: keyword}, timeout10) assert len(weibo_resp.json()[list]) 20, 微博数据少于20条检查采集层 print(微博数据接口正常共获取, len(weibo_resp.json()[list]), 条记录) if __name__ __main__: smoke_test()这套冒烟测试脚本跑通了再换其他关键词放量采集就有把握了。从那以后我每次拿到这类毕设源码都会强制走一遍这个过程先冒烟测接口再验证分词质量最后抽查情感打分。不少项目在单独模块上看着没问题一旦串起来就暴露接口字段对不上、数据格式不匹配的毛病提前跑一遍比排查到半夜强得多希望帮到你。本文还有配套的精品资源点击获取