No description
  • Python 91%
  • Vue 4.3%
  • TypeScript 3.1%
  • JavaScript 0.7%
  • Batchfile 0.6%
  • Other 0.1%
Find a file
HiZQP ab98925fdf feat: 配置持久化——登录态/LLM密钥迁出程序目录,升级换机仅拷用户数据目录
背景:绿包升级=整包替换程序目录,原散落其中的 browser_data(各平台
扫码登录态)、LLM 密钥(仅存前端 localStorage)、微博 Cookie(写死在
MediaCrawler base_config.py)、历史库全部随版本丢失。

方案:个人数据收敛到程序目录外的用户数据目录(默认 %APPDATA%\Yujian,
开发态回落 backend/data,env YUJIAN_USERDATA_DIR 可覆盖):
- backend/app/runtime_paths.py:新增 userdata_dir(),区分可再生组件 data_dir
- backend/app/services/userdata.py(新):目录入口 + config.json(LLM/微博
  Cookie)+ migrate_legacy_state() 幂等一次性迁移旧版散落数据
- backend/app/config.py / login_state.py:*.db 与登录注册表改落用户数据目录
- backend/app/api/settings.py(新):GET/PUT/DELETE /api/llm/config
- analyze._resolve_llm:请求密钥优先、回落存储配置(无密钥不再 422 语义卡死)
- crawler_runner:spawn 子进程注入 YUJIAN_BROWSER_DATA_DIR/YUJIAN_SQLITE_DB;
  微博 Cookie 经 config.json 显式 --cookies 传递,不再回写程序目录 base_config
- MediaCrawler:base_config.BROWSER_DATA_DIR / db_config.SQLITE_DB_PATH 支持
  env 覆盖;各平台 core 与 cdp_browser 的 browser_data 硬编码路径统一改之
- 前端:App.vue/api/analysis.js 将 LLM 配置真源从 localStorage 迁到后端
  config.json(启动 sync + 保存即上传),提示文案/徽标展示 config.json 路径

测试与文档:conftest 增加重置模块级限流桶夹具(修复全量跑顺序污染导致的
429);新增 test_llm_config_api 3 用例(往返/回落/无密钥 422);后端 174 项
全绿;README 增「数据持久化与迁移」节并同步接口/环境变量/测试数。
2026-09-09 17:04:30 +08:00
.vscode upload 2026-09-01 17:22:56 +08:00
backend feat: 配置持久化——登录态/LLM密钥迁出程序目录,升级换机仅拷用户数据目录 2026-09-09 17:04:30 +08:00
branding fix(branding): 图标圆角透明化 + 强制重嵌 EXE 图标 2026-09-09 00:47:22 +08:00
docs Merge branch 'main' of http://49.233.169.94:51234/202400507129/my_project 2026-09-02 17:24:14 +08:00
MediaCrawler-main feat: 配置持久化——登录态/LLM密钥迁出程序目录,升级换机仅拷用户数据目录 2026-09-09 17:04:30 +08:00
public upload 2026-09-01 17:22:56 +08:00
src feat: 配置持久化——登录态/LLM密钥迁出程序目录,升级换机仅拷用户数据目录 2026-09-09 17:04:30 +08:00
tools 浏览器自动化 2026-09-03 16:03:16 +08:00
.gitignore feat: 配置持久化——登录态/LLM密钥迁出程序目录,升级换机仅拷用户数据目录 2026-09-09 17:04:30 +08:00
build-app.bat fix(build): 绿包排除 MediaCrawler 爬取残留库 sqlite_tables.db(隐私干净出包) 2026-09-09 12:20:50 +08:00
docker-compose.yml upload 2026-09-01 17:22:56 +08:00
Dockerfile upload 2026-09-01 17:22:56 +08:00
index.html upload 2026-09-01 17:22:56 +08:00
nginx.conf upload 2026-09-01 17:22:56 +08:00
package-lock.json upload 2026-09-01 17:22:56 +08:00
package.json upload 2026-09-01 17:22:56 +08:00
README.md feat: 配置持久化——登录态/LLM密钥迁出程序目录,升级换机仅拷用户数据目录 2026-09-09 17:04:30 +08:00
start-local.bat feat: 话题跟踪(后台定时爬取 + 手动优先抢占)与交付收尾 2026-09-07 21:07:00 +08:00
start-local.sh feat: 话题跟踪(后台定时爬取 + 手动优先抢占)与交付收尾 2026-09-07 21:07:00 +08:00
start-prod.bat upload 2026-09-01 17:22:56 +08:00
start-tracker.bat feat: 话题跟踪(后台定时爬取 + 手动优先抢占)与交付收尾 2026-09-07 21:07:00 +08:00
vite.config.js bug fix 2026-09-04 17:00:33 +08:00
yujian.bat fix(launcher): 根目录误用系统 Python 的友好引导 + 根级 yujian.bat 入口 2026-09-08 16:02:17 +08:00

舆见 · 舆情速读

面向普通网民的舆情速读工具 —— 输入一个想关注的事件,几分钟看懂「发生了什么 / 大家怎么看 / 接下来会怎样」。可把话题加入后台跟踪,定时自动更新。

技术栈 技术栈 技术栈 技术栈

特性

  • 真实多平台爬取:微博 / B站 / 小红书 / 抖音 / 贴吧MediaCrawler 驱动本机浏览器,登录态持久化;平台失败自动跳过,全失败才报错)
  • 双模同跑管线 + 档位分层轻量扫描sweep列表级元数据+ 深度增强enrich头部博文评论分阶段并发。手动普通分析走 fast 档5 平台广度 + 削深度,目标 3-5 分钟);话题跟踪后台轮次走 full 档(深度累积)。请求间隔按平台分档(宽松平台快、严格平台慢),兼顾速度与风控
  • 话题跟踪 + 近期缓存:搜索框勾选「跟踪话题」即注册后台周期爬取(默认 60 分钟/轮,独立 worker 进程,仅 1 个话题,手动分析优先抢占)。近期话题冷热分层7 天内再分析 → 爬新 + 读库全窗合并(趋势跨天);超 30 天未用且不在跟踪 → 惰性 GC 物理释放
  • LLM 强制依赖:用户关键词直接爬取 → 传统统计 → 末端 LLM 基于参考集 A 生成 4W 要素 + 概述 / 舆论总结 / 观点标签 / 演化阶段 / 走势预判OpenAI 兼容密钥,无传统兜底;无 LLM 前置检索规划)
  • 真实统计口径:声量 = Σ平台真实评论数;趋势 = 按抓取到的时间戳真实分桶(篇/天,覆盖率 ≥70% 才启用细分情绪8 类词典命中,按带情绪样本占比);高频词 TF-IDF 带权
  • 可视化零依赖:全部图表原生 SVG 手绘——高频词云形词云螺旋铺排椭圆云、8 色彩盘、字号随权重)、情感环图、趋势曲线;平台单字品牌徽标体系;暖纸底设计系统,无 UI/图表库

🧱 架构

┌───────────────────────────────────────────────────────────────┐
│  前端 Vue3 + Vite原生 SVG                                   │
│  SearchPanel跟踪开关· LoadingState分平台进度+平台徽标)    │
│  TrackStatusBar跟踪状态卡/细条)· 结果三步结构 + 参考集/评论    │
├───────────────────────────────────────────────────────────────┤
│  FastAPI 后端backend/app/                                   │
│  /api/analyze[/stream] · /api/tracker/* · /api/crawl            │
│  ┌─────────────────────────────────────────────────────┐       │
│  │ run_dual手动分析fast 档)                         │       │
│  │   Stage① sweep 平台并发轻扫24 条/平台)             │       │
│  │   Stage② enrich 并发深析3 篇 × 20 评论/平台)       │       │
│  │   → 统计(趋势/声量/情感/词云) → LLM 汇总              │       │
│  ├─────────────────────────────────────────────────────┤       │
│  │ tracker_worker独立进程话题跟踪 full 档)          │       │
│  │   每 60min 空闲抢占 run_staged_crawl → 记录轮次       │       │
│  │   手动分析优先preempt 信号 → worker 让出           │       │
│  │   跨进程互斥crawl_gateSQLite BEGIN IMMEDIATE   │       │
│  ├─────────────────────────────────────────────────────┤       │
│  │ topic_cache近期话题索引 + 惰性 GCTTL/LRU 释放)   │       │
│  └─────────────────────────────────────────────────────┘       │
│  数据MediaCrawler SQLitevendored· tracker.db 状态库       │
└───────────────────────────────────────────────────────────────┘

结果页(三步看懂 + 真实素材)

  1. 发生了什么 —— 事件概述 + 四要素Who/What/When/Where
  2. 大家怎么看 —— 情感环图(正/中/负占比与主导情绪)+ 细分情绪(愤怒/质疑/担忧/祈福/支持等 8 类,按极性三色绿/灰/红条形);核心观点标签 + 高频词云形词云(字号=讨论热度)
  3. 接下来会怎样 —— 近 3 天热度预测曲线 + 舆论演化阶段

下方附参考集 A(真实检索内容,官方权威置顶)、来源分布(分平台 icon 徽标与占比)、真实网友评论(高赞排序,卡片内滚动收纳不拉长页面)。

🚀 快速开始

方式 A本地一键脚本推荐完整功能

start-local.bat            REM 开发模式vite dev :5173
start-local.bat prod       REM 生产形态build + preview :4173
  • 自动检查/安装依赖(仅首次)、自动清理 8000/5173/4173 端口占用
  • 弹出 三个 cmd 窗口yujian-backend:8000yujian-tracker(话题跟踪 workeryujian-frontend
  • 关闭方式:关掉这三个 yujian-* 窗口
  • 脚本为纯 ASCII 英文输出,任何 Windows 代码页均可运行

方式 B手动开发

# 后端(依赖 Python 3.11+
cd backend
python -m venv .venv
.venv/Scripts/python.exe -m pip install -r requirements.txt
.venv/Scripts/python.exe -m uvicorn app.main:app --reload --port 8000

# 话题跟踪 worker新终端需要跟踪功能时才起
.venv/Scripts/python.exe -m app.services.tracker_worker

# 前端(新终端,仓库根)
npm install
npm run dev        # 访问 http://localhost:5173vite 代理 /api → :8000

方式 CDocker仅 API 展示形态)

start-prod.bat      # 等价 docker compose up -d --build访问 http://localhost:8080

⚠️ Docker 容器内没有宿主机浏览器与扫码登录态MediaCrawler 真实爬取与话题跟踪 worker 需在宿主机运行。跑完整功能请用方式 A。

📡 话题跟踪(核心用法)

  1. 搜索框输入话题关键词 → 点击下方「跟踪话题 · 后台定时更新」开关(主按钮变为「开始跟踪」)
  2. 提交即注册后台跟踪:立即首轮爬取,此后每 60 分钟自动更新一轮(间隔可用环境变量调整)
  3. 搜索框下方出现跟踪状态卡片(最近一轮篇数/评论 / 错误 / 下次更新倒计时);分析结果页顶部有细条入口
  4. 点卡片「查看最新分析」→ 汇总该话题已爬取的数据走读库直出分析(不再触发新爬取,趋势用全窗历史)
  5. 点「停止跟踪」随时结束

约束与并发:

  • 仅允许跟踪 1 个话题(新话题自动替换旧话题)——避免多任务叠加触发平台风控
  • 手动分析优先:手动输入话题分析时,若后台 worker 正在爬取会发送抢占信号worker 让出(最多等约 60 秒),随后手动任务立即开始
  • worker 进程与 API 服务跨进程互斥由 crawl_gateSQLite BEGIN IMMEDIATE 门闩)保证,崩溃后自动让锁

🗂️ 分析档位与近期话题缓存

机制 说明
fast 档(手动普通分析) 5 平台全保留,削 enrich 深度sweep 24 条 / 深析 3 篇 × 20 评论 → 目标 3-5 分钟
full 档(话题跟踪轮次) 回落 settings 深度sweep 30 条 / 深析 4 篇 × 30 评论,后台累积
活跃合并 同一话题 7 天内再次分析 → 爬新 + 读库全窗TTL 30 天内)合并,趋势跨天、样本更大
惰性 GC 超 30 天未再分析且不在跟踪的话题 → 从媒体库物理删除;同时 LRU 上限 20 个近期话题

🤖 LLM 配置(强制依赖)

  • 首页搜索框下方填写任一 OpenAI 兼容 API 密钥DeepSeek / OpenAI / 通义 / 智谱 / Kimi 预设可选)并「保存配置」
  • 密钥保存到本机用户数据目录 config.json(见下节「数据持久化与迁移」),升级版本/更换机器不丢失;保存后分析请求可不再逐次携带密钥
  • 密钥无效 / 模型失败 → 422 明确报错(无传统兜底);跟踪话题的「查看最新分析」同样需要密钥

🗄️ 数据持久化与迁移(升级不丢登录态/密钥)

个人数据(LLM 密钥、微博 Cookie、各平台登录态 browser_data、爬取历史库/快照/跟踪状态)一律收敛到程序目录的用户数据目录:

  • 开发态backend/data/绿色分发frozen%APPDATA%\Yujian(可用 YUJIAN_USERDATA_DIR 覆盖,子进程登录态目录另可用 YUJIAN_BROWSER_DATA_DIR 覆盖)
  • 目录内 config.json 统一保存 LLM 密钥/端点/模型与微博 Cookie明文仅存本机browser_data/ 为各平台 Edge profile 登录态;crawl_db/ + *.db 为爬取与状态历史库
  • 升级版本=整包替换程序目录,用户数据目录原样保留 → 免重扫码、免重填密钥;更换机器/版本=拷贝整个用户数据目录到新机同名位置即可
  • 从旧版本升级时,首次爬取前自动一次性迁移:把旧程序目录内散落的 browser_data / 爬取库 / base_config.py 中的 COOKIES 收进用户数据目录(幂等,搬完置 migrated 标记),实现「升级不重登」

🕷️ MediaCrawler唯一内容源

  • 内容与评论仅来自 MediaCrawlervendored 于仓库根 MediaCrawler-main/)爬取微博/小红书/抖音/B站/贴吧
  • 后端通过 CDP 自动拉起本机 Edge独立 profile 保存扫码登录态仅首次需扫码profile 与运行期库均落在上述用户数据目录,不入 git
  • sweep 为列表级轻扫(跳过详情/全文/图片速度优先enrich 才抓头部博文评论
  • 平台失败自动跳过继续;全失败才返回 503 提示换关键词

🔌 API 契约

接口 方法 说明
/api/analyze POST 手动分析即搜即爬body {topic, autoCrawl?}autoCrawl=false 走读库直出
/api/analyze/stream POST SSE 流式版progress / result / error 事件,实时推送各平台爬取进度(含档位/平台维度 extra
/api/crawl POST 独立触发 MediaCrawler 爬取sweep / enrich
/api/hot-topics GET 推荐话题(热搜聚合)
/api/tracker/start POST 开始跟踪话题 {topic}(自动替换旧话题,立即首轮)
/api/tracker/stop POST 停止跟踪
/api/tracker/status GET 跟踪状态(前端轮询 / worker 调度共用)
/api/cache DELETE 清空分析缓存与爬取快照
/api/llm/config GET 读取已保存的 LLM 配置(含密钥与 config.json 路径,供换机回填)
/api/llm/config PUT 保存 LLM 配置到用户数据目录 config.jsonapiKey 留空仅更新端点/模型)
/api/llm/config DELETE 清除已保存的 LLM 配置
/api/login/status GET 各平台登录态qrcode / cookie / ok
/api/login/{platform} POST 引导登录lt=qrcode|cookie可见浏览器扫码
/health GET 健康检查

⚙️ 配置(环境变量,前缀 YUJIAN_

变量 默认 说明
YUJIAN_PORT 8000 服务端口
YUJIAN_CORS_ORIGINS * CORS 白名单(生产建议收紧)
YUJIAN_CRAWL_PLATFORMS wb,bili,xhs,dy,tieba 参与双模分析的平台
YUJIAN_CRAWL_SWEEP_NOTES 30 轻扫每平台条数列表级full 档)
YUJIAN_CRAWL_ENRICH_NOTES 4 深析每平台头部博文篇数full 档)
YUJIAN_CRAWL_ENRICH_COMMENTS 30 深析每篇评论条数full 档)
YUJIAN_CRAWL_SWEEP_SLEEP_MAP wb:2,bili:2,tieba:2,xhs:5,dy:5 轻扫每平台请求间隔(秒,分档)
YUJIAN_CRAWL_ENRICH_SLEEP_MAP wb:5,bili:5,tieba:5,xhs:10,dy:10 深析每平台请求间隔(秒,分档)
YUJIAN_MANUAL_SWEEP_NOTES 24 手动 fast 档轻扫条数/平台
YUJIAN_MANUAL_ENRICH_NOTES 3 手动 fast 档深析头部博文篇数/平台
YUJIAN_MANUAL_ENRICH_COMMENTS 20 手动 fast 档每篇评论条数
YUJIAN_TOPIC_ACTIVE_DAYS 7 近期缓存活跃窗口(天内再分析=爬新+全窗合并)
YUJIAN_TOPIC_TTL_DAYS 30 话题物理释放 TTL超期且不在跟踪 → GC 删除)
YUJIAN_TOPIC_MAX_KEPT 20 同时保留的近期话题上限LRU 淘汰最旧)
YUJIAN_TRACK_INTERVAL_MINUTES 60 话题跟踪周期(分钟)
YUJIAN_TRACK_PREEMPT_WAIT 60 手动分析等 worker 让出上限(秒)
YUJIAN_TRACKER_POLL_SECONDS 30 worker 调度 tick
YUJIAN_USERDATA_DIR 见下 用户数据目录(配置/登录态/历史库);开发态默认 backend/data,绿色包默认 %APPDATA%\Yujian
YUJIAN_BROWSER_DATA_DIR 继承用户数据目录 MediaCrawler 各平台 Edge profile 目录(登录态),子进程注入
YUJIAN_SQLITE_DB 继承用户数据目录 MediaCrawler 爬取库 sqlite 文件路径,子进程注入

🧪 测试

cd backend
.venv/Scripts/python.exe -m pytest tests/
# 174 passed

覆盖双模编排、档位分层fast/full 预算)、近期缓存与 GC、跨进程门闩、跟踪状态库、worker 调度、autoCrawl 读库直出、接口契约、统计边界(真实趋势分桶 / 细分情绪占比 / 词云带权)、爬虫 runner 超时/抢占、LLM 配置持久化与回落、旧数据迁移幂等。

📦 项目结构

public opinion analysis/
├── src/                        # 前端 Vue3 源码
│   ├── App.vue                 # 状态机 idle/loading/success/error + 跟踪集成
│   ├── composables/            # platforms.js平台元数据唯一源等
│   ├── api/                    # analysis.js(SSE) · tracker.js · mockAnalysis.js(规整)
│   └── components/             # SearchPanel / TrackStatusBar / LoadingState /
│                               # PlatformIcon / SentimentDonut / OpinionTags(词云) 等
├── backend/                    # FastAPI 后端
│   ├── app/
│   │   ├── main.py             # CORS + 路由注册 + 健康检查
│   │   ├── api/                # analyze.py(SSE) · tracker.py
│   │   ├── pipeline/           # run_dual/staged · crawler_loader · prepare · stats · summarizer
│   │   ├── services/           # analyzer · crawler_runner · crawl_gate · tracker_store ·
│   │   │                       # topic_cache近期话题 GC· nlp情感/情绪/关键词)
│   │   └── config.py           # 全量设置pydantic-settingsYUJIAN_ 前缀)
│   ├── tests/                  # pytest离线夹具
│   └── Dockerfile
├── MediaCrawler-main/          # vendored 爬虫(含登录态/运行库,不入 git
├── tools/                      # MediaCrawler 手动登录/爬取脚本
├── start-local.bat / .sh       # 一键起 backend + tracker + frontend
├── start-tracker.bat           # 单独起跟踪 worker
├── start-prod.bat              # Docker 形态
├── docker-compose.yml / nginx.conf / Dockerfile
└── vite.config.js

📋 URL 参数

参数 作用
?q=话题 打开页面即自动分析该话题(分享 / 截图用)

⚖️ 合规与边界

  • 数据仅来自公开平台搜索与内容页,登录态仅用于解除平台风控,不采集私信等个人数据
  • 内容仅用于学习与研究,请遵守各平台服务条款与 robots 约束;控制频率以避免风控与打扰
  • 本工具输出由 LLM 生成,仅供信息参考,不构成任何决策依据

📄 License

实训项目,仅用于学习与研究。