领取地址:通过网盘分享的文件:源码获取.txt
链接: https://pan.baidu.com/s/157q4QdD9HT_Yl13iqEJY-g?pwd=mw4q 提取码: mw4q

项目效果:

# 微博舆情分析可视化系统 — 系统设计文档

## 1. 项目概述

本系统以微博平台为数据源,针对热点话题(就业、经济、疫情、房价、教育、AI 等)

进行全流程的舆情分析与可视化展示。系统采用前后端分离架构,后端以 Flask 提供

RESTful API,前端以 Vue 3 构建交互界面,结合自然语言处理与机器学习算法,从

文本内容、情感倾向、地域分布、传播规律等多个维度对舆情数据进行深度挖掘,为

舆情研判提供量化数据支撑。

**数据概况:** 当前数据集(`data.xlsx`)共 17,506 条微博记录,覆盖经济、

疫情、房价、AI、就业、新能源等 21 个话题,时间跨度为 2025-03-09 至

2026-03-01,包含文本内容、用户信息、IP 归属地、互动数据等 27 个字段。

---

## 2. 技术架构总览

系统分为前端展示层、后端服务层、数据处理层三个层次,各层之间通过 HTTP

RESTful 接口通信。

```

┌────────────────────────────────────────────────────────┐

│                    前端展示层(Vue 3)                   │

│                                                        │

│   可视化大屏   情感分析   关键词   地域分布   主题聚类    │

│   ScreenView  Sentiment Keywords  GeoMap   TopicView   │

│                        ↕ Axios                         │

│              全局筛选状态(Pinia Store)                 │

└──────────────────────────┬─────────────────────────────┘

                           │ RESTful API(JSON)

                           │ 统一前缀 /api/v1

┌──────────────────────────▼─────────────────────────────┐

│                    后端服务层(Flask)                   │

│                                                        │

│  路由层(Blueprint)    服务层(Services)               │

│  ┌──────────────┐      ┌──────────────────────────┐    │

│  │ /posts       │ →→→  │ 数据预处理  情感分析       │    │

│  │ /analysis/*  │      │ 关键词提取  主题聚类       │    │

│  │ /export/*    │      │ 地域解析    缓存管理       │    │

│  └──────────────┘      └──────────────────────────┘    │

└──────────────────────────┬─────────────────────────────┘

                           │ pandas / SQLAlchemy

┌──────────────────────────▼─────────────────────────────┐

│                      数据处理层                         │

│   jieba 分词  SnowNLP 情感  TF-IDF 关键词  LDA 主题     │

│   wordcloud 词云  pandas 数据操作  MySQL 存储            │

└────────────────────────────────────────────────────────┘

```

---

## 3. 技术选型

### 3.1 前端技术栈

| 技术 | 用途 |

|------|------|

| Vue 3 + Vite | 前端框架,Composition API,快速构建与热更新 |

| Vue Router 4 | 单页应用路由管理,支持路由懒加载 |

| Pinia | 全局状态管理,统一维护筛选条件与用户状态 |

| Element Plus | UI 组件库,提供表格、表单、弹窗等基础组件 |

| ECharts 5 | 核心图表库,支持折线图、饼图、地图、词云等 |

| Axios | HTTP 请求封装,统一处理请求拦截与错误处理 |

| vue-echarts | ECharts 的 Vue 组件封装,简化图表与数据绑定 |

### 3.2 后端技术栈

| 技术 | 用途 |

|------|------|

| Flask 3 | Web 框架,提供 RESTful API 服务 |

| Flask-CORS | 跨域资源共享,支持前后端分离开发 |

| SQLAlchemy 2 + PyMySQL | ORM 框架,连接 MySQL 数据库 |

| pandas | 读取 Excel 数据,执行数据清洗与统计聚合 |

| jieba | 中文分词,支持精确模式与自定义词典 |

| SnowNLP | 中文情感分析,输出 0~1 情感分值 |

| scikit-learn | TF-IDF 关键词权重计算 |

| gensim | LDA 主题模型训练与推断 |

| wordcloud | 生成词云图片(PNG/Base64) |

| openpyxl | 导出 Excel 文件 |

---

## 4. 前端模块设计

前端共包含 **6 个页面模块** 和若干公共组件,通过侧边导航栏在各页面之间切换。

其中可视化大屏(`ScreenView`)为系统核心展示入口,以全屏沉浸式布局呈现

舆情全貌;其余五个页面为深度分析功能页。

### 4.1 路由结构

```

/screen         →  可视化大屏(默认首页,全屏无导航栏)

/dashboard      →  数据总览看板

/sentiment      →  情感分析页

/keywords       →  关键词词云页

/geo            →  地域分布页

/topics         →  主题聚类页

/data           →  数据明细页

```

### 4.2 公共组件

所有分析页共享以下公共组件:

- **`FilterBar.vue`(全局筛选栏)**

  固定在非大屏页面的顶部,提供话题关键词多选、时间范围选择、情感倾向单选、

  省份下拉四个筛选维度。筛选状态通过 Pinia 的 `filterStore` 全局共享,

  各图表组件 `watch` 状态变化后自动发起 API 请求刷新。

- **`ChartCard.vue`(图表容器卡片)**

  统一的图表外壳,封装标题、加载骨架屏、空数据占位、全屏展开等通用行为。

- **`BaseChart.vue`(ECharts 基础图表)**

  对 `vue-echarts` 的二次封装,统一主题色、字体、响应式 resize 逻辑。

### 4.3 模块一:可视化大屏(`ScreenView.vue`)

大屏为系统的核心门面,采用深色科技风主题,使用 CSS Grid 将屏幕划分为

左、中、右三栏布局,适配 1920×1080 全屏展示。

**布局区划与图表内容:**

```

┌────────────┬──────────────────┬────────────┐

│  左栏       │     中栏          │  右栏      │

│            │                  │           │

│ ① 情感分布  │ ③ 中国地图热力图   │ ⑤ 话题热度 │

│   环形饼图  │   (省级发帖量)   │   水平柱状  │

│            │                  │           │

│ ② 情感趋势  │ ④ 核心指标卡       │ ⑥ 热门微博 │

│   堆叠折线  │  总量/话题/省份    │   滚动列表 │

│            │                  │           │

│            │ ⑦ 关键词词云       │           │

│            │                  │           │

└────────────┴──────────────────┴────────────┘

```

- **① 情感分布环形图**:实时展示正面 / 中性 / 负面三类情感占比

- **② 情感趋势折线图**:近 30 天三类情感数量的时序变化

- **③ 省级热力地图**:各省发帖量以色阶深浅呈现,鼠标悬停显示详情

- **④ 核心指标卡**:总微博数、覆盖话题数、覆盖省份数、平均情感分四个数字卡

- **⑤ 话题热度柱状图**:21 个话题的发帖量横向对比排行

- **⑥ 热门微博滚动列表**:互动总量 Top-10 的帖文自动滚动播放

- **⑦ 关键词词云**:TF-IDF 全局词云图片,背景透明嵌入大屏

大屏顶部设有实时时间显示与「进入详情」按钮,可跳转到各深度分析页。

### 4.4 模块二:数据总览看板(`DashboardView.vue`)

为普通分析人员提供带筛选功能的综合概览页,与大屏数据联动但支持条件过滤。

- 顶部统计指标卡(总量、均值互动数、话题数、时间跨度)

- 发帖量按天折线图

- 互动数据(转发/评论/点赞)三线对比折线图

- 情感分布饼图(与大屏一致,支持筛选后动态更新)

### 4.5 模块三:情感分析页(`SentimentView.vue`)

深度聚焦于情感维度,包含四个图表组件:

- **情感趋势堆叠面积图**:按日期展示三类情感数量的堆叠变化,

  直观体现情感转折时间节点

- **各话题情感对比柱状图**:以分组柱状图展示每个话题正/中/负面占比,

  支持按情感类型过滤高亮

- **情感分值散点图**:以情感分值(y 轴)vs. 互动总量(x 轴)散点展示,

  辅助识别低分高热的负面舆情帖文

- **负面舆情预警列表**:情感分值低于 0.3 的帖文摘要、发布时间、

  互动数、链接,支持导出

### 4.6 模块四:关键词词云页(`KeywordsView.vue`)

- **全局 TF-IDF 词云**:基于全量数据计算词权重生成,词汇大小映射权重值

- **分话题词云**:Tab 切换,为每个关键词单独生成一个词云

- **词频 Top-30 水平柱状图**:展示词汇频次排行,与词云同步联动

- 支持下载当前词云为 PNG 图片

### 4.7 模块五:地域分布页(`GeoMapView.vue`)

- **省级热力地图**:基于 ECharts `map` 组件,以发帖量映射颜色深浅

- **情感气泡叠加层**:在地图上叠加散点,气泡颜色表示该省平均情感

  (蓝色→正面,红色→负面),大小表示发帖量

- **省份数据排行表**:发帖量 Top-15 省份,含总数、正面率、负面率列

- 点击省份高亮后,右侧联动显示该省的帖文样本列表

### 4.8 模块六:主题聚类页(`TopicView.vue`)

展示 LDA 模型抽取的 8 个潜在主题及其分布:

- **主题气泡图(Bubble Chart)**:每个气泡代表一个主题,气泡面积正比于

  该主题的帖子数量,气泡内显示 Top-5 特征词

- **主题词条形图**:选中某主题后,右侧展示该主题前 15 个词汇的权重条形图

- **主题比例饼图**:各主题占全量数据的比例

- **主题帖文样本列表**:点击气泡后展示该主题下的 10 条代表性帖文

### 4.9 模块七:数据明细页(`DataTableView.vue`)

提供原始数据的可搜索、可筛选、可导出的表格视图:

- 分页数据表格(Element Plus `el-table`),每页 20 条

- 支持全文搜索(内容关键词)+ 全局筛选联动过滤

- 表格列:发布时间、话题、内容摘要、情感标签(彩色标签)、

  互动数(转/评/赞)、发布地区、原帖链接

- 顶部操作栏:导出当前筛选结果为 Excel 或 CSV

---

## 5. 后端模块设计

后端由 **5 个服务模块** 和 **4 类 API 接口** 组成,各服务模块在 Flask

应用启动时初始化,接口模块通过 Blueprint 注册到应用。

### 5.1 数据预处理模块(`services/preprocessor.py`)

负责将原始 `data.xlsx` 清洗为可分析的结构化数据,在系统首次启动时运行一次,

结果写入 MySQL,后续从数据库读取。

**主要职责:**

- 读取 Excel,标准化字段类型(时间格式转换、空值填充)

- 清洗微博正文:去除 HTML 标签、`@用户`、`#话题#`、URL、表情符号

- 从 `ip_location`(如"发布于 辽宁")提取省份名称

- 使用 jieba 精确模式分词,加载 `stopwords.txt` 过滤停用词和单字

- 将清洗后的数据批量写入 `weibo_posts` 表

**技术:** pandas、jieba、SQLAlchemy、正则表达式

### 5.2 情感分析模块(`services/sentiment.py`)

对清洗后的微博正文进行情感评分与分类标注。

**主要职责:**

- 调用 SnowNLP 对每条文本输出 0~1 的情感分值

- 按阈值划分三类标签:≥0.65 为正面,≤0.35 为负面,其余为中性

- 批量处理并将结果写入 `sentiment_labels` 表,与主表通过 `post_id` 关联

- 提供增量分析接口,支持对新增数据单独触发情感标注

**技术:** SnowNLP、pandas、SQLAlchemy

### 5.3 关键词提取模块(`services/keyword.py`)

基于 TF-IDF 算法从分词结果中提取高权重关键词,支持全局和按话题两种粒度。

**主要职责:**

- 将所有帖文的分词结果组织为文档集合,训练 TF-IDF 向量化模型

- 全局词云:对全部文档的词汇累加 TF-IDF 分值,取 Top-100 词

- 分话题词云:按 `keyword` 分组,对每组分别计算 TF-IDF,取 Top-50 词

- 使用 wordcloud 库生成词云图片(返回 Base64 编码)

**技术:** scikit-learn(TfidfVectorizer)、wordcloud、pandas

### 5.4 主题聚类模块(`services/topic.py`)

使用 LDA(Latent Dirichlet Allocation)对全量微博文本进行无监督主题发现。

**主要职责:**

- 基于预处理后的分词语料构建词典与词袋模型

- 训练 LDA 模型,默认提取 8 个主题,每个主题输出 Top-15 特征词

- 为每条微博推断主题分布,将主导主题编号写回数据库

- 模型训练完成后序列化为文件,API 调用时直接加载模型推断,不重复训练

**技术:** gensim(LdaModel、Dictionary、corpus)、pandas

### 5.5 地域统计模块(`services/geo.py`)

解析 IP 归属地字段,统计各省的发帖量、情感分布,为地图可视化提供数据。

**主要职责:**

- 维护省份名称映射字典,从 `ip_location` 字符串中提取标准省份名

- 按省份聚合计算:发帖总量、平均情感分、正/负面帖文数

- 提供省份下钻接口,返回指定省份的帖文列表

**技术:** pandas、SQLAlchemy

### 5.6 API 接口层

接口按职责分为四组 Blueprint,均以 `/api/v1` 为前缀,统一返回

`{ code, msg, data }` 格式的 JSON 响应。

**数据查询接口组(`api/data.py`):**

| 接口 | 说明 |

|------|------|

| `GET /posts` | 分页查询微博列表,支持关键词/日期/情感/省份筛选 |

| `GET /posts/stats` | 返回总量统计指标(总数、话题数、时间跨度等)|

| `GET /keywords` | 返回所有话题关键词列表 |

**分析数据接口组(`api/analysis.py`):**

| 接口 | 说明 |

|------|------|

| `GET /analysis/sentiment` | 情感三分类占比统计 |

| `GET /analysis/sentiment/trend` | 按日情感趋势数据(堆叠面积图数据源)|

| `GET /analysis/wordcloud` | 返回词云图片 Base64 + 词频 JSON |

| `GET /analysis/geo` | 各省发帖量与平均情感数据 |

| `GET /analysis/topics` | LDA 主题列表及各主题帖子数与关键词 |

| `GET /analysis/interaction` | 转发/评论/点赞的时序趋势与均值 |

| `GET /analysis/hotposts` | 互动量 Top-20 的热门微博列表 |

**大屏数据接口组(`api/screen.py`):**

| 接口 | 说明 |

|------|------|

| `GET /screen/overview` | 大屏所需的全量聚合数据(一次性返回所有卡片数据)|

**导出接口组(`api/export.py`):**

| 接口 | 说明 |

|------|------|

| `POST /export/excel` | 按当前筛选条件导出 Excel 文件 |

| `POST /export/csv` | 按当前筛选条件导出 CSV 文件 |

| `GET /export/wordcloud-img` | 导出词云为 PNG 图片文件 |

---

## 6. 系统整体流程(伪代码)

### 6.1 后端启动与数据初始化

```

程序入口 run.py:

    启动 Flask 应用

    IF 数据库文件不存在:

        连接 MySQL,执行 db.create_all() 建立数据表结构

        // ① 数据导入与清洗

        raw_data = 读取("data/raw/data.xlsx")

        FOR 每一条记录 in raw_data:

            content = 清洗文本(record.content)

                // 去除 HTML、@、#话题#、URL、表情

            province = 解析省份(record.ip_location)

                // "发布于 辽宁" → "辽宁"

            tokens  = jieba分词(content) - 停用词

            写入数据库(record + province + tokens)

        // ② 情感分析批处理

        FOR 每条已入库记录:

            score = SnowNLP(record.content).sentiments

            label = IF score >= 0.65 THEN "正面"

                    ELIF score <= 0.35 THEN "负面"

                    ELSE "中性"

            写入情感标注表(post_id, score, label)

        // ③ TF-IDF 关键词提取

        corpus = [record.tokens FOR record IN 全量数据]

        tfidf_model = TfidfVectorizer().fit(corpus)

        global_word_scores = 累加每个词的TF-IDF权重

        序列化保存(tfidf_model, global_word_scores)

        // ④ LDA 主题模型训练

        dictionary = 构建词典(corpus)

        bow_corpus  = [doc2bow(doc) FOR doc IN corpus]

        lda_model   = LdaModel(bow_corpus, num_topics=8, passes=15)

        FOR 每条记录:

            topic_dist = lda_model.推断主题(record.bow)

            record.dominant_topic = argmax(topic_dist)

        序列化保存(lda_model)

    ELSE:

        // 数据库已存在,跳过预处理直接启动

        加载缓存的 tfidf_model 和 lda_model

    注册 Blueprint: data, analysis, screen, export

    启动服务器(host="0.0.0.0", port=5000)

```

### 6.2 前端启动与大屏渲染

```

前端入口 main.js:

    创建 Vue 应用实例

    注册 Element Plus、ECharts 插件

    挂载 Pinia store(filterStore 初始化空筛选)

    挂载 Vue Router → 默认重定向到 /screen

ScreenView.vue 挂载时:

    onMounted():

        data = await GET("/api/v1/screen/overview")

        渲染指标卡(data.stats)

        渲染情感饼图(data.sentiment_dist)

        渲染情感趋势图(data.sentiment_trend)

        渲染热力地图(data.geo_data)

        渲染话题热度柱状图(data.topic_heat)

        渲染热门帖文滚动列表(data.hot_posts)

        渲染词云图片(data.wordcloud_base64)

        // 大屏数据定时刷新(每 5 分钟)

        setInterval(刷新大屏数据, 5 * 60 * 1000)

```

### 6.3 筛选条件变更驱动图表刷新

```

用户在 FilterBar 中修改筛选条件:

    // 防抖 500ms

    debounce(500ms):

        filterStore.update({

            keywords: 已选话题列表,

            dateRange: [开始日期, 结束日期],

            sentiment: 已选情感标签,

            province:  已选省份

        })

各图表组件(以情感分析页为例):

    watch(filterStore):

        params = filterStore.toQueryParams()

        showLoading()

        // 并发请求当前页所需的多个接口

        [trend, compare, scatter, alerts] = await Promise.all([

            GET("/api/v1/analysis/sentiment/trend", params),

            GET("/api/v1/analysis/sentiment",       params),

            GET("/api/v1/analysis/interaction",     params),

            GET("/api/v1/posts", { ...params, sentiment: "负面" })

        ])

        hideLoading()

        堆叠面积图.setOption(trend.data)

        对比柱状图.setOption(compare.data)

        散点图.setOption(scatter.data)

        负面预警列表.render(alerts.data)

```

### 6.4 后端接口处理通用流程

```

Flask 接收请求(以 GET /api/v1/analysis/sentiment/trend 为例):

    // 参数解析与验证

    params = {

        keyword:    request.args.get("keyword"),

        start_date: request.args.get("start_date"),

        end_date:   request.args.get("end_date")

    }

    IF 参数非法:

        RETURN { code: 400, msg: "参数错误" }

    // 缓存检查

    cache_key = MD5(params)

    cached = cache.get(cache_key)

    IF cached 存在且未过期:

        RETURN cached

    // 业务逻辑执行

    query = SELECT post_id, created_at, sentiment_label

            FROM weibo_posts JOIN sentiment_labels

            WHERE 满足 params 中的过滤条件

    // 按日期聚合

    result = {}

    FOR 每一天 IN query 结果按日分组:

        result[日期] = {

            positive: 该天正面数量,

            neutral:  该天中性数量,

            negative: 该天负面数量

        }

    response = { code: 200, data: result }

    // 写入缓存(有效期 30 分钟)

    cache.set(cache_key, response, ttl=1800)

    RETURN response

```

### 6.5 数据导出流程

```

用户点击「导出 Excel」按钮:

    前端:

        params = filterStore.toQueryParams()

        response = await POST("/api/v1/export/excel", params)

        触发浏览器下载(response.blob, "舆情数据导出.xlsx")

    后端:

        query = 按 params 过滤的完整数据集(含情感标签)

        df = 转换为 DataFrame,调整列顺序与中文列名

        excel_bytes = df.to_excel(BytesIO(), index=False)

        RETURN Response(

            excel_bytes,

            mimetype="application/vnd.openxmlformats...",

            headers={"Content-Disposition": "attachment; filename=..."}

        )

```

---

## 7. 项目目录结构

```

weibo-sentiment/

├── backend/

│   ├── app/

│   │   ├── __init__.py          # Flask 应用工厂,注册 Blueprint

│   │   ├── config.py            # 开发 / 生产环境配置

│   │   ├── api/

│   │   │   ├── data.py          # 数据查询接口 Blueprint

│   │   │   ├── analysis.py      # 分析接口 Blueprint

│   │   │   ├── screen.py        # 大屏聚合接口 Blueprint

│   │   │   └── export.py        # 导出接口 Blueprint

│   │   ├── services/

│   │   │   ├── preprocessor.py  # 数据清洗 + 分词入库

│   │   │   ├── sentiment.py     # SnowNLP 情感分析服务

│   │   │   ├── keyword.py       # TF-IDF 关键词 + 词云服务

│   │   │   ├── topic.py         # LDA 主题聚类服务

│   │   │   └── geo.py           # 地域解析 + 省份聚合服务

│   │   └── utils/

│   │       ├── cache.py         # 内存缓存工具(基于字典 + TTL)

│   │       └── response.py      # 统一响应格式工具函数

│   ├── data/

│   │   ├── raw/data.xlsx        # 原始数据源

│   │   ├── stopwords.txt        # 中文停用词表

│   │   └── models/              # 序列化的 TF-IDF / LDA 模型文件

│   │   └── models/              # 序列化的 TF-IDF / LDA 模型文件

│   ├── requirements.txt

│   └── run.py                   # 应用启动入口

└── frontend/

    ├── src/

    │   ├── api/

    │   │   ├── index.js         # Axios 实例与拦截器配置

    │   │   ├── analysis.js      # 分析接口调用函数

    │   │   ├── data.js          # 数据查询接口调用函数

    │   │   └── screen.js        # 大屏接口调用函数

    │   ├── components/

    │   │   ├── charts/

    │   │   │   ├── BaseChart.vue      # ECharts 基础封装

    │   │   │   ├── SentimentPie.vue   # 情感饼图

    │   │   │   ├── TrendLine.vue      # 趋势折线/面积图

    │   │   │   ├── GeoHeatMap.vue     # 地域热力地图

    │   │   │   ├── WordCloudImg.vue   # 词云图片组件

    │   │   │   └── TopicBubble.vue    # 主题气泡图

    │   │   └── common/

    │   │       ├── FilterBar.vue      # 全局筛选栏

    │   │       ├── ChartCard.vue      # 图表容器卡片

    │   │       └── StatCard.vue       # 数字指标卡

    │   ├── views/

    │   │   ├── ScreenView.vue         # 可视化大屏

    │   │   ├── DashboardView.vue      # 数据总览看板

    │   │   ├── SentimentView.vue      # 情感分析页

    │   │   ├── KeywordsView.vue       # 关键词词云页

    │   │   ├── GeoMapView.vue         # 地域分布页

    │   │   ├── TopicView.vue          # 主题聚类页

    │   │   └── DataTableView.vue      # 数据明细页

    │   ├── stores/

    │   │   └── filter.js              # Pinia 筛选状态 Store

    │   ├── router/

    │   │   └── index.js               # Vue Router 路由配置

    │   └── main.js

    ├── package.json

    └── vite.config.js                 # Vite 配置(含代理转发 /api → :5000)

```

---

## 8. 开发启动方式

启动前确保本地 MySQL 服务已运行,并完成数据库初始化:

```sql

CREATE DATABASE weibo_sentiment DEFAULT CHARACTER SET utf8mb4;

```

```bash

# 后端(weibo-back-end)

cd weibo-back-end

pip install -r requirements.txt

# 在 .env 或 config.py 中配置 MySQL 连接信息

python run.py          # http://localhost:5000

                       # 首次运行自动完成数据初始化(约需 2~5 分钟)

# 后台管理(weibo-background)

cd weibo-background

npm install

npm run dev            # http://localhost:5174

                       # /api/* 请求自动代理到 localhost:5000

# 前台展示(weibo-reception)

cd weibo-reception

npm install

npm run dev            # http://localhost:5173

                       # /api/* 请求自动代理到 localhost:5000

```

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐