feat(viewer): 添加知乎数据展示标签页#878
Open
J1anYi wants to merge 28 commits into
Open
Conversation
实现了一个简洁的数据查看器前端,用于展示爬取的小红书笔记数据。
功能特性:
- 瀑布流卡片布局(CSS columns 真瀑布流)
- 关键词筛选和标题搜索
- 图片懒加载(Intersection Observer)
- 笔记详情模态框(图片画廊导航)
- 统计面板(笔记数、图片数、关键词分布)
- 实时监控(WebSocket + 5秒轮询)
- 视频类型标识和播放器支持
后端 API:
- GET /api/notes - 获取笔记列表(支持分页、关键词筛选、搜索)
- GET /api/notes/stats - 获取统计数据
- GET /api/notes/{note_id} - 获取笔记详情
- GET /api/notes/keywords - 获取关键词列表
安全改进:
- 添加 note_id 验证防止路径遍历攻击
- 添加输入参数验证(Query validators)
- 改进异常处理(使用更精确的异常类型)
- 添加类型注解
- 支持更多中文数字格式(亿、万、w、k)
新增知乎标签页,支持展示已爬取的知乎回答数据: - API: 新增 /api/zhihu 路由,支持列表、统计、创作者筛选 - 前端: 新增平台标签切换(小红书/知乎) - 卡片: 知乎采用文本优先卡片布局,品牌色 #0066FF - 模态框: 点击卡片查看完整回答内容 - 响应式: 700px 以下切换垂直布局 - ARIA: 标签导航支持键盘导航和可访问性 测试验证: - 25 条知乎回答数据正确展示 - 创作者筛选和搜索功能正常 - 模态框交互和 ESC 关闭正常
- 添加 watchdog 依赖监听 JSONL 文件变化 - 创建 FileWatcherService 服务,支持 200ms 防抖 - 通过 asyncio.run_coroutine_threadsafe 桥接线程和 asyncio - WebSocket 连接时发送初始统计数据 - 文件变化时广播 stats_update 消息 - 前端 WebSocket 连接后自动停止轮询,断开时恢复 关闭 #实时数据同步
问题根因: 1. z-index 层级问题 - modal-close 的 z-index 太低 2. 函数名冲突 - subscriptions-app.js 的 setupModalEvents 覆盖了 modal.js 3. 变量名冲突 - bilibili-app.js 的 currentSearch 与 app.js 冲突 4. 缺少 stopPropagation - 事件冒泡导致问题 修复内容: - 提高 modal-close 的 z-index 到 1000 - 统一所有平台 ESC 键关闭判断逻辑 (!== 'none') - 重命名 subscriptions-app.js 中的 setupModalEvents 为 setupSubscriptionModalEvents - 重命名 bilibili-app.js 中的全局变量避免冲突 - 为所有平台模态框添加 stopPropagation - 确保 modal-content 和 modal-overlay 的 z-index 正确分层
问题:
- /ws/status 端点只发送爬虫状态,不接收广播消息
- broadcast_platform_update() 发送的 data_update 消息无法到达前端
修复:
1. /ws/status 现在使用 manager.connect() 连接到 ConnectionManager
2. 添加 type 字段到 crawler_status 消息,前端可以正确解析
3. /ws/status 现在可以接收 data_update, stats_update 等广播消息
数据流修复后:
文件变化 → FileWatcher → broadcast_platform_update()
↓
manager.broadcast() → 所有 WebSocket 连接
↓
前端 WSClient 接收 data_update → 刷新数据
修复: - 添加内联 onclick 作为刷新按钮的临时修复方案 - 刷新后自动滚动到页面顶部 - 添加调试日志帮助排查问题 待优化: - 需要清理内联 onclick,改用正规事件绑定 - 提醒框重复弹出问题 - 提醒框内容显示优化
每个文件变更触发两个 WebSocket 消息(data_update 和 stats_update), 导致提醒框每次弹出两次。移除 stats_update 的通知触发,仅保留 console.log。 满足: BUG-02
将 else 分支改为显式处理 stats_update,跳过通知触发。 仅保留 console.log 用于调试。 满足: BUG-02
将 else 分支改为显式处理 stats_update,跳过通知触发。 仅保留 console.log 用于调试。 满足: BUG-02
将 else 分支改为显式处理 stats_update,跳过通知触发。 仅保留 console.log 用于调试。 满足: BUG-02
添加 NOTIFICATION_DEDUP 常量,包含: - recentNotifications Map 用于存储通知哈希和时间戳 - 5 秒去重窗口配置 - 30 秒清理间隔配置 Requirement: NOTIF-03
添加两个新函数: - generateNotificationHash: 基于 platform + titles + count 生成哈希 - isDuplicateNotification: 检查是否在 5 秒窗口内重复 包含过期条目清理机制,防止内存泄漏 Requirement: NOTIF-03
在通知显示前添加去重检查: - 生成通知哈希 - 检查是否在 5 秒窗口内重复 - 重复时跳过并记录日志 Requirement: NOTIF-03
修改通知内容构建逻辑: - 当 data.titles 存在时显示标题内容 - 显示最多 2 个标题,超出显示 "等N条" - 保持对 keyword 和 count 的兼容 Requirement: NOTIF-03
- 添加 new_count 字段记录新增数据数量 - 添加 titles 字段记录新增记录的标题列表 - 支持前端显示实际增量而非固定数字 Refs: BUG-03, NOTIF-01
- 添加 _previous_counts 字典追踪各平台记录数 - 添加 set_previous_count/get_previous_count 函数 - 添加 calculate_new_count 函数计算增量 Refs: BUG-03, NOTIF-01
- 添加 get_recent_notes 函数获取平台最新记录 - 添加 get_platform_notes_count 函数获取平台记录总数 - 支持 JSONL 和 JSON 两种数据格式 Refs: BUG-03, NOTIF-01
- 调用 get_platform_notes_count 获取当前记录总数 - 使用 calculate_new_count 计算新增数量 - 调用 get_recent_notes 获取最新记录标题 - DataUpdateMessage 消息包含 new_count 和 titles 字段 Refs: BUG-03, NOTIF-01
Phase 3: 数据排序与滚动刷新优化 变更内容: - 添加无限滚动状态变量和加载更多函数 - 实现 IntersectionObserver 监听滚动到底部 - 添加加载指示器和没有更多数据提示 - 添加排序选择器 UI (最新发布) - 排序偏好保存到 localStorage 技术实现: - currentOffset/currentLimit 管理分页状态 - loadMoreNotes() 增量加载更多数据 - setupInfiniteScrollSentinel() 设置滚动触发器 - sortSelect 事件绑定和 localStorage 持久化
1. 笔记卡片添加时间显示 - 新增 formatTime() 函数,支持相对时间格式化 - 卡片底部显示发布时间(刚刚/X分钟前/X小时前/X天前/日期) 2. 修复无限滚动加载完成提示未显示 - 将 showNoMoreData() 移到 finally 块中 - 只有 hasMoreData 为 true 时才调用 showLoadingMore(false) - 确保"没有更多数据了"提示不会被覆盖
1. 时间戳格式兼容 - formatTime() 同时支持秒级(10位)和毫秒级(13位)时间戳 - 修复 API 返回毫秒级时间戳导致日期错误的问题 2. 无限滚动完成提示 - showNoMoreData() 中停止 scrollObserver 监听 - 避免重复触发 loadMoreNotes() 覆盖提示内容
- renderMoreNotes 在 sentinel 之前插入新卡片 - 确保 sentinel 始终在列表末尾 - 这样滚动到底部时能正确触发下一轮加载
- Add SQLite task database service (image_task_db.py) - Add image download service (image_downloader.py) - Add message queue service (image_queue.py) - Add queue management API router (image_queue.py) - Update lifespan in main.py to initialize services on startup
Phase 7: Frontend image display optimization - API now returns local_image_url, remote_image_url, and first_image_url fields - Added /local-images static route to serve downloaded images - Frontend prefers local images and falls back to remote URLs on error - Added image loading state animations (shimmer effect) - Prevents infinite fallback loops with fallbackUsed flag
- Add asyncio import for fire-and-forget task spawning - Import image_queue_service from api.services - Enqueue image download tasks after note storage - Use try-except to isolate failures from main flow - Covers: CRAWL-01, CRAWL-02
## 主要功能 - 图片下载任务队列 (asyncio.Queue) - SQLite 任务数据库 (状态管理、重试机制) - 定时任务调度器 (超时检测、自动重试) - 图片存储服务 (hash-based 路径、格式验证) - 前端图片显示 (本地优先、远程 fallback) - 爬虫集成 (自动入队下载任务) ## Bug 修复 - notes.py: 修复 image_list 字符串格式兼容问题 ## 配置变更 - 默认端口从 8080 改为 8081 ## 日志增强 - crawler_manager: 添加行号前缀和控制台输出
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
在前端添加知乎标签页,复用小红书的卡片式布局展示已爬取的知乎回答数据。新增知乎 API 路由,支持数据列表、统计、筛选等功能。
Changes
API (Unit 1)
api/routers/zhihu.py- 知乎数据 API 路由GET /api/zhihu- 获取回答列表,支持 creator 筛选和 search 搜索GET /api/zhihu/stats- 获取统计数据GET /api/zhihu/creators- 获取创作者列表GET /api/zhihu/{content_id}- 获取回答详情api/routers/__init__.py导出 zhihu_routerapi/main.py注册 zhihu 路由Frontend (Unit 2)
viewer/static/index.htmlviewer/static/css/style.css--zhihu-primary: #0066FF.zhihu-*相关样式viewer/static/js/zhihu-api.js- 知乎 API 封装viewer/static/js/zhihu-app.js- 知乎应用逻辑viewer/static/js/zhihu-modal.js- 知乎模态框逻辑Features
Test Plan
GET /api/zhihu返回 25 条回答数据GET /api/zhihu/stats返回正确统计GET /api/zhihu?creator=xxx筛选功能正常GET /api/zhihu?search=关键词搜索功能正常Screenshots
访问 http://localhost:8080/viewer/ 查看效果:
Post-Deploy Monitoring & Validation
/viewer/页面,切换到知乎标签,确认数据展示正常