金融机构公告广告监控与分析(v10.1)
总览
面向金融从业者/竞品分析师/合规审计,监控中国 210 个数据源的公告广告与舆论:
- 151 家金融 APP 首页:推荐产品清单 + 轮播广告图逐帧(OCR/视觉提取广告语)
- 机构官网(website):banner 广告图 + 文字广告 + 产品 + 公告/资讯页
- 财经媒体(media):权威媒体/门户上各家基金公司的新闻稿件
- 财经论坛(forum):股吧/基金吧/雪球/知乎的舆论帖子 + 热度
- 自媒体(social):公开可爬部分(B站/美篇)+ 登录墙手动补充
三种广告形式全覆盖:图片(轮播逐帧)、文字(页面广告文案)、视频(下载→抽帧→OCR/ASR)。
通过 Playwright 模拟浏览器访问公开 Web/H5(无需登录),最终生成一份嵌入思源字体的 Word 报告。
适用场景:
- 竞品监测:跟踪同类机构(银行/券商/基金)的推广策略和新品节奏
- 广告投放对比:横向对比各机构广告投放量、各平台活跃度
- 媒体舆情:基金公司新闻曝光量、论坛舆论热点、情感倾向
- 趋势追踪:隔周/隔月重跑,看广告语、产品、新闻、帖子变化
- 合规审计:收集非登录公开页面的展示信息作为证据
不适用:
- 需要登录才能看的个人化内容(资产/持仓/交易记录)
- 强反爬+登录墙的自媒体(微信/抖音/快手/小红书/视频号),标注
none并给出手动补充指引
核心能力(v10.1)
🆕 v10.1 新增:banner 轮播抓取与分析强化
抓取侧(修复 7 大盲区)
| 盲区 | v10.0 | v10.1 |
|---|---|---|
| background 轮播 | 只扫 3 类 class + 单 url() | 全页面大尺寸块级启发式 + 多 url() 拆分(url(a),url(b) 全取)+ 伪元素 ::before/::after + data-bg 懒加载 + 60% 页面高度 |
| iframe 内轮播 | 完全不可见 | 遍历 page.frames 逐帧扫描 |
| shadow DOM 轮播 | 完全不可见 | shadowRoot 递归 pierce |
| canvas 绘制轮播 | 无指示器仅截 1 帧 | 自动连拍(2s×8 次 + 字节去重,捕获 autoplay 切换帧) |
| JS 动态 swiper | data-src 拷贝 | slide 数量 3 次采样稳定等待 + Swiper 实例读取 |
| 指示器 | 仅 pagination 圆点 | + 左右箭头(.swiper-button-next/prev)+ JS slideNext() 兜底 |
| 配置 | 151 家全模板 | 15 家精配覆盖(天天基金 .banner_box/#top_banner 等文档选择器落地) |
分析侧(修复 3 大瓶颈) | 瓶颈 | v10.0 | v10.1 | |---|---|---| | 帧级去重 | 仅 URL 归一化 | dHash 感知哈希内容去重(同素材变体/多页重复/截图重复剔除,保护 30 帧上限、省 OCR/vision 费用) | | 截图质量 | 无指示器截整页 400px | JS 精确定位轮播容器 clip(_CAROUSEL_BOX_JS) | | vision 误判 | 截图帧按"单张广告图"分析 | is_page_shot 页面截图模式(专用 PAGE_SHOT_PROMPT) |
链路强化
- 失败帧重试通道:采集阶段下载失败的帧(image_url 保留)在 OCR 阶段按 URL 重试下载再入 OCR
- OCR 并发:两处 OCR 循环 ThreadPoolExecutor 并发(6 线程,与 vision 一致)
核心能力(v10.1)
🆕 v10.0 新增:广告爬取 / 广告图 / 分析能力全面强化
广告爬取强化
| 强化项 | v9.1 | v10.0 |
|---|---|---|
| ad_fetcher_enhance 集成 | 158 词库/意图分类/视频海报为死代码(零调用) | 全面接入 scraper + website_collector 主路径,文字广告入库附 ad_score + 意图 |
| 视频广告 | media 资源被拦截、无 producer | 轻量实装:解除 media 全拦(白名单放行站内视频)+ extract_videos(video poster/src + iframe 播放器 + 海报帧下载) |
| 懒加载/iframe/弹窗 | 产品不滚动、iframe 广告不处理 | 产品提取前滚动触发懒加载;全屏广告弹窗([class*='ad'] fixed 层)清理 |
| 反爬检测 | 15 词 + 2000 字符采样 | HTTP 状态码 + 验证码 iframe/img + 多轮采样 + headless 特征自检 |
| 产品提取 | yield_rate/risk_level 永远为空 | 正则提取 + products 表加列入库 |
广告图获取强化 | 强化项 | v9.1 | v10.0 | |---|---|---| | 下载方式 | 串行(30 帧最坏 15 分钟) | ThreadPoolExecutor 并发(4 线程) | | 原始 URL | frames 表无 image_url 列(入库即丢) | image_url 列迁移 + 下载失败标记可重试 | | 截图帧编号 | DOM/截图帧 frame_index 冲突丢帧 | 统一编号器 | | 指示器点击 | 直接 click + 固定 1.2s | 拟人化(scroll_into_view + 随机延时 + 像素验证重试) | | 图片质量 | webp 不转换 | webp→PNG 自动转换 + >5MB 跳过 |
广告分析强化
| 强化项 | v9.1 | v10.0 |
|---|---|---|
| 竞品分析接入 | full_competitor_report 从未被调用(最大断点) | 接入报告流水线:Word 新增板块 11(强度 TOP10 柱状图 / 品类矩阵 / 相似对 / 素材复用) |
| 投放强度分 | 线性数量堆叠 | 四维加权(数量 40% + 素材多样性 20% + vision 质量 20% + 意图覆盖 20%)+ 品类内 z-score 归一化 |
| 素材复用 | 无 | detect_shared_assets:同图多投检测(image_hash 聚类) |
| 广告语相似度 | 全文本 bigram Jaccard(稀释) | TF 加权 cosine + n-gram 共现短语抽取 |
| diff 检测 | text_changed 无阈值(OCR 抖动误报);video_changed 死类型 | 相似度阈值(≥0.8 不算变) + 空文本转换检测 + frame_image_changed(同位置图变)+ video_changed 实装 + 换序降误报 |
| 时间趋势 | 仅最近两次 diff | diff_trend:N-run 序列环比(帧数/产品数/主题热度) |
| OCR | 无方向检测/竖排/缓存 | OSD 方向回正 + PSM 多通道重试 + 逐词置信度 + NFKC 归一化 + image_hash 缓存 |
| 视觉校验 | 串行、无缓存、原图直传 | verify_batch 并发(5 线程)+ 结果缓存 + 图片压缩(长边≤1568)+ 指数退避重试 + schema 校验 |
| LLM 整页点评 | 复用 banner prompt(语义错位) | 专用四段式 prompt(布局/主推产品/营销策略/风险提示) |
| 情感词典 | 20+19 词、无否定处理 | 200+ 金融词 + 否定词翻转("未出现违规"不再误判负面)+ 模型并发+缓存 |
性能提升
- 图片并发下载 + vision 并发校验 + OCR/vision/文本三处 hash 缓存(跨 run 复用)
save_results_to_storage主路径统一 bulk 单事务(200 帧 200 事务 → 1 事务)- 单 APP 软超时保护(默认 180s,防一个卡死拖垮整批)
🆕 v9.1 新增:广告/公告获取增强(ad_fetcher_enhance.py)
| 增强项 | 原版 | v9.1 |
|---|---|---|
| 广告话术关键词 | 30 个 | 100+ 个(促销/拉新/福利/收益/行动/节日/品牌/教育/投资 9 大类) |
| 视频海报帧提取 | 未实装 | v9.1 部分实装(<video poster> + .video-cover img 两种来源) |
| 背景图 CSS 解析 | 单引号/无引号 | 三引号兼容 + data:URI 过滤 + 关键字过滤 |
| 热度评分 | 无 | 综合评分(点赞×1 + 回复×5 + 浏览×0.1,4 档 cold/warm/hot/viral) |
| 日期解析 | ISO 格式 | 相对+绝对("刚刚"/"X 分钟前"/"X 小时前"/"昨天"/"X 天前"/"X 月前") |
| 广告意图分类 | 无 | 4 类意图(拉新/促活/留存/挽回) |
🆕 v9.1 新增:竞品分析对比(competitor_comparator.py)
| 对比维度 | 说明 |
|---|---|
| 同类别横向对比矩阵 | 同组内各家投放强度排行 + 推广主题偏好 + 强度差距分析 |
| 跨平台投放对比 | APP / 官网 / 媒体 / 论坛 / 自媒体 5 类平台投放量/活跃度对比 |
| 广告语相似度 | Jaccard 系数(bigram + 关键词)+ TOP 5 相似对 |
| 投放强度排行榜 | 全市场 TOP 10 投放最强 APP(含轮播/产品/文字广告/模块数明细) |
| 完整竞品报告 | full_competitor_report(results) 一键产出 4 大板块 |
📊 11 大板块 Word 报告
📊 11 大板块 Word 报告
| 板块 | 内容 | 适用对象 | |------|------|---------| | ① Banner 汇总清单 | 跨 APP/官网全部轮播帧缩略图 + 广告语 + 跳转链接 | 整体速览 | | ② 页面模块 | 导航 / 卡片 / 活动入口汇总 | 运营参考 | | ③ 元信息 + 整页截图 | 采集时间 / 数据源列表 / 成功率统计 + 首页截图 | 合规留痕 | | ④ 多时点对比趋势 | diff 文字摘要 + matplotlib 折线图(20 类变化,v8 增新闻/帖子/广告) | 趋势追踪 | | ⑤ 自动点评 | 统计型 + 趋势型 + 跨源对比 + 舆情热点 + 情感分析 + 可选 LLM | 决策参考 | | ⑥ 媒体新闻监测(v8) | 跨源新闻表格 + 各机构报道量排行 | 媒体监控 | | ⑦ 舆论监控(v8) | 情感分布 + 舆情热点 + 热帖榜 | 舆情分析 | | ⑧ 文字广告汇总(v8) | 跨源文字广告表格 | 广告监控 | | ⑨ 视频广告(v8) | 视频列表 + 关键帧 + 字幕/OCR 摘要 | 视频广告 | | ⑩ 跨源横向对比(v8) | 机构×平台投放量/新闻量矩阵 | 竞品分析 |
🤖 自动点评引擎(commentary_engine.py + v9.1 competitor_comparator.py)
- 统计型(默认开启,无依赖):同类别横向对比、OCR 关键词聚类(10 大推广主题)、产品类型分布
- 趋势型(自动开启):基于 diff 数据归纳(变化最频繁 APP、营销节奏判断)
- 竞品对比型(v9.1 新增):同类别对比矩阵、跨平台投放对比、广告语相似度、投放强度榜
- LLM 点评(
--with-llm-comment启用,需 VISION_API_KEY):整页一句话点评;未配 key 自动降级
🛠️ 工程能力
- APP 名单 151 家 / 14 类别:第三方销售/基金销售/互联网理财/互联网保险/财富管理/券商/保险/期货/国有大行/股份制/政策性银行/城商行/农商行/民营银行
- 小白友好:
--preset beginner一键跑 8 家 +python scripts/setup.py自动装齐依赖(pip / Chromium / Tesseract / 字体 / OCR 语言包)+--guide5 分钟上手 - 增量采集:SQLite 持久化 + 多时点 diff(8 类变化:轮播帧增删 / 广告语变化 / 产品增删 / 页面模块增删改)+ 趋势图
- 真定时任务(
--schedule "0 9 * * 1"):croniter + 指数退避 + 健康探活 + 死信保护 - 反爬 6 级降级链:UA 伪装 → stealth → 资源拦截 → 反爬关键词检测 → 退避重试 → 降级标注
- 合规边界:仅爬非登录公开 Web 页;不破解验证码;不存登录态/个人信息
完整清单:python scripts/run.py --list-apps(秒回,不触发依赖安装)
五分钟上手(小白必看)
# 1. 第一次跑:自动装齐所有依赖 + 跑小白套餐(8 家基金销售类APP)
python scripts/run.py --preset beginner
# 2. 查看上手向导
python scripts/run.py --guide
# 3. 列出全部APP
python scripts/run.py --list-apps
会自动发生的事:
- 检测 pip 依赖 → 缺哪个装哪个
- 下载 Playwright 浏览器内核(约 150MB)
- 检测 Tesseract 文字识别工具 → 缺则尝试 winget/choco 自动装
- 下载思源字体到
assets/fonts/ - 下载OCR中文语言包到
assets/tessdata/ - 跑 8 家APP:天天基金、京东金融、蚂蚁财富、和讯、蛋卷基金、雪球、东方财富、同花顺
- 出 1 份嵌入思源的 Word 报告(约 1-3 MB)
如果中途出错: 错误会用中文告诉你为什么以及下一步该做什么,不用看堆栈。
步骤 1:检测运行环境(可选)
!python "scripts/run.py" --check-env
如果跳过上一步就开跑,run.py 会自动检测并补齐所有依赖。
步骤 2:选择监控范围
5 种方式(v8 多数据源):
- 预设套餐(小白友好):
--preset beginner(8 家)/--preset fund_sales(基金销售类)/--preset third_party(第三方销售类) - 指定数据源(中文名、简称、英文标识):
--apps "天天基金,京东金融,和讯"/--apps "招行,工行,农行" - 按类别:
--apps 基金销售/--apps 第三方销售/--apps 银行 - v8 新增类别:
--apps 财经媒体(媒体)/--apps 财经论坛(论坛)/--apps 基金公司(官网)/--apps 自媒体/--apps 官网 - 全部:
--apps all(210 个数据源,约 30-60 分钟)
步骤 3:执行爬取与提取
一次性跑(默认):
!python "scripts/run.py" --apps "{用户指定的范围}" --output "公告广告监控报告_{日期}"
增量跑(写数据库,第二次跑能看差异):
!python "scripts/run.py" --collect --apps "{范围}" --db data/monitor.db
带视觉模型(OCR 看不懂的字自动调AI):
!python "scripts/run.py" --apps "{范围}" --with-vision
时间范围查询(--query,读数据库不爬取):
!python "scripts/run.py" --query --since "2026-08-01" --until "2026-08-31" --db data/monitor.db
视频广告深度采集(需 yt-dlp/ffmpeg 可选):
!python "scripts/run.py" --apps "{范围}" --with-video
模型级文本/情感分析(需 VISION_API_KEY,无 key 自动降级词典):
!python "scripts/run.py" --apps "{范围}" --with-llm-analysis
参数默认值(小白可全部省略):
| 参数 | 默认值 | 说明 |
|------|--------|------|
| --apps | (无) | 必须指定;或用 --preset beginner |
| --preset | (无) | 小白套餐 |
| --source-type | (不加) | 数据源过滤:app/website/media/forum/social |
| --since / --until | (不加) | 时间范围(YYYY-MM-DD 或 YYYY-MM-DD HH:MM) |
| --query | (不加) | 时间范围查询模式(读库出报告,配合 --since/--until) |
| --no-headless | (不加) | 默认无头模式;调试时加此参数显示浏览器 |
| --output | 自动生成 | 输出文件名(不含扩展名) |
| --collect | (不加) | 增量模式(写数据库 + 后续可对比) |
| --db | data/monitor.db | 数据库路径 |
| --with-vision | (不加) | 低置信度OCR帧自动调视觉模型 |
| --with-video | (不加) | 视频广告深度采集(下载→抽帧→OCR/ASR) |
| --with-llm-analysis | (不加) | 文本/情感分析启用模型级(无 key 降级词典) |
| --strict | (不加) | 严格模式:任何环境缺失都抛错(持续集成用) |
流程说明(脚本内部自动完成):
- 按 source_type 分派:app→scraper、website→官网深爬、media→新闻、forum→帖子、social→自媒体公开部分
- 提取各自内容(产品/轮播/文字广告/新闻/帖子/视频),产出归一化结果
- OCR(Tesseract 中文简体 + 英文)提取图片广告语;低置信度帧调视觉模型校验
- 视频广告深度:下载→抽帧→OCR帧内容→ASR转文字(全部可选降级)
- 文本/情感分析(词典级兜底,可选模型级)
- 增量模式:写数据库 + 计算与上次的差异(20 类变化:帧/产品/模块/新闻/帖子/文字广告/视频)
- 生成汇总 Word(10 板块)+ 嵌入思源字体
步骤 4:定时监控(可选)
!python "scripts/run.py" --schedule "0 9 * * 1" --apps all
特性:
- 真定时(基于定时表达式库,不是循环等待)
- 指数退避(失败 1分钟 → 2分钟 → 4分钟 → ... 上限 60分钟)
- 健康探活(
data/scheduler_logs/health.json) - 死信保护(连续失败 10 次自动停服)
- 可优雅停止
常用定时表达式:
| 表达式 | 含义 |
|--------|------|
| 0 9 * * * | 每天 9:00 |
| 0 9 * * 1 | 每周一 9:00 |
| 0 */6 * * * | 每 6 小时 |
| 0 9 1 * * | 每月 1 号 9:00 |
步骤 5:输出结果
向用户报告:
- Word 报告路径:
data/output/APP首页监控报告_YYYYMMDD_HHMMSS.docx - 数据库(增量模式):
data/monitor.db - 爬取统计:成功数 / 总数、推荐产品数、轮播广告帧数
- 截图目录:
data/screenshots/ - 轮播图目录:
data/carousel_images/{APP名}/ - 可爬性说明:蚂蚁财富不可爬(无公开网页版首页,Word 中有手动截图补充指引);部分APP降级处理说明
注意事项
- 仅爬取非登录公开网页页面,不破解验证码,不存储登录态或个人敏感信息
- 蚂蚁财富无公开网页版首页,自动跑手动指引占位节(可手动截图后放入
data/carousel_images/蚂蚁财富/重新生成报告) - 视觉模型校验为可选(需配置视觉模型接口密钥),缺失时降级为纯OCR
- 部分APP(工行基金、保险需登录;建行、交行轮播纯图片)会降级处理并在报告中标注
- 各APP的页面元素选择器基于调研初步配置,实际页面结构变化时可能需调试
scripts/app_registry.py
安装指引(已自动化,无需手动)
# 自动检测 + 补齐所有依赖(pip 依赖、浏览器内核、文字识别工具、字体、语言包)
python scripts/setup.py
# 或:跑任意 run.py 命令时自动调用
v7.4 缓存防御(上传/分发前必跑):
# 清理 __pycache__/*.pyc(部分同步工具按扩展名拒收 .pyc 二进制)
python scripts/cleanup_cache.py
scripts/run.py/scripts/setup.py顶部已设sys.dont_write_bytecode = True,运行时不生成 .pycconftest.py已让 pytest 不生成源码 .pyc(仅 pytest 自身的 conftest.pyc 仍会生成)- 上传/分发前跑一遍
cleanup_cache.py即可彻底干净
如果自动装失败(winget 不可用 / 无管理员):
- Tesseract 手动安装:https://github.com/UB-Mannheim/tesseract/wiki (勾选简体中文)
- 字体手动:从 https://github.com/adobe-fonts/source-han-sans/releases 下载 4 个 OTF 字体放到
assets/fonts/ - 设置
TESSERACT_CMD=<tesseract.exe路径>环境变量
视觉模型接口(可选):
set VISION_API_KEY=<你的接口密钥>
set VISION_API_BASE=https://open.bigmodel.cn/api/paas/v4
set VISION_MODEL=glm-4v
小白词典(10 行速查)
- 轮播图:APP 首页顶部那张会自己滚动切换的大广告图;本工具把每一帧都抓下来
- 轮播:上面的轮播图通常 3-5 张为一组,按时间自动切换,叫"轮播图组"
- OCR:把图片里的中文读成文字的技术(这里用 Tesseract);读不准的字会再请AI看一眼
- 视觉模型:能"看图说话"的AI(这里默认GLM-4V),作为OCR的兜底
- 字体嵌入:把字体文件塞进Word文档里,对方打开不会缺字体(思源黑体、思源宋体)
- 浏览器身份标识:浏览器身份证,决定你看到的是移动H5还是电脑网页版
- 隐身模式:反反爬技术,让网站尽量看不出我们是机器人
- 降级:某一步失败时自动改用更简单但更稳的方式(如截屏代替页面元素解析)
- 对比差异:两次抓取之间"什么变了",是第 4 板块(对比趋势)的核心
- 定时表达式:定时任务的写法,如
"0 9 * * 1"等于每周一早上 9 点
参考文件
references/scrapability_report.md-- 可爬性调研报告(首批 15 家深度调研,其余按类别模板推断;何时查看:了解各APP可爬性依据)references/app_selectors.md-- 各APP页面元素选择器配置说明(何时查看:选择器失效需调试时)references/word_font_embedding.md-- OOXML字体嵌入技术说明(何时查看:字体嵌入相关问题)scripts/app_registry.py-- 151家APP配置表(何时查看:增减APP或调整网址、选择器时)scripts/deps.py-- 依赖清单唯一真源(何时查看:增减 pip 依赖时;必需 vs 可选分开)scripts/storage.py-- SQLite 增量存储(何时查看:差异算法、调数据库时)scripts/diff_engine.py-- 多次爬取对比算法 +CHANGE_TYPE_CN变化类型中文名真源(何时查看:自定义对比类型时)scripts/_auto_install.py-- 首次运行自动安装逻辑(何时查看:自定义安装项时)scripts/setup.py-- 一键环境准备(何时查看:手动安装时)scripts/cleanup_cache.py-- 清理 pycache/*.pyc(何时查看:上传/分发前必跑)conftest.py-- pytest 全局配置(禁用 .pyc 生成)scripts/run.py --check-env-- 环境检测(何时查看:排查依赖问题时)scripts/registry_websites.py/registry_media.py/registry_forums.py/registry_social.py-- v8 多数据源注册表(何时查看:增减官网/媒体/论坛/自媒体源时)scripts/collector.py-- v8 多数据源统一分派入口(何时查看:新增 source_type 时)scripts/news_collector.py/forum_collector.py/website_collector.py/social_collector.py-- v8 各数据源采集器(何时查看:某类源爬取异常时)scripts/text_analysis.py-- v8 文本/情感分析(词典+模型两级)(何时查看:情感分析调优时)scripts/query_engine.py-- v8 时间范围查询(--query 模式)(何时查看:窗口报告定制时)tests/-- 单元测试(299 个用例,含 v7.4/v7.5/v8/v9 缺陷修复防回归)
📝 v7.3 优化与缺陷修复记录
v7.3 重大升级:从小白"装半天跑不起来"变成"装好就开跑"。
修复的真实缺陷
| 编号 | 文件 | 现象 | 修复 |
|-----|------|------|------|
| 修复-1 | agents/openai.yaml:3 | 描述写"15家"陈旧 | 改为"130+家" |
| 修复-2 | scripts/storage.py:331 | get_diffs 返回的载荷字段是原始字符串而非字典,调用方 .get() 会返回默认值 | 反序列化载荷JSON,损坏时降级为空字典 |
| 修复-3 | scripts/diff_engine.py:74 | 仅在模块表有数据时,差异项的应用名称错误地用标识当作值 | 改为合并时按标识集合去重,仅作兜底 |
| 修复-4 | scripts/storage.py:339 | get_latest_run 和 list_runs 用连接查询帧表过滤,只有产品没有帧的运行找不到 | 改用联合查询三表 |
| 修复-5 | scripts/_auto_install.py:119 | 写死浏览器无头外壳-1228 路径,浏览器升级后检测失败 | 改为动态扫描 chromium_headless_shell-* 目录 |
| 修复-6 | scripts/run.py:90 | --strict 严格模式标志定义了但永远没被使用(死参数) | 把标志传给自动安装逻辑 |
| 修复-7 | scripts/scheduler.py:85 | 循环等待阻塞非真定时 | 重写为真定时 + 指数退避 + 健康文件 + 死信保护 |
| 修复-8 | scripts/word_exporter.py | 4 板块缺"对比趋势" | 新增 4 个板块添加函数 |
| 修复-9 | scripts/run.py | 无数据库持久化,无增量采集模式 | 新增加量模式(写数据库 + 对比差异) |
| 修复-10 | scripts/app_registry.py | 和讯未在册;基金销售类 9 家缺主流 | 补 9 家(和讯 + 诺亚 + 宜人 + 嘉实 + 易方达 + 华夏 + 南方 + 博时 + 富国) |
| 修复-11 | scripts/_auto_install.py | 首次跑需手动装 | 首次 run 命令自动装齐所有依赖 |
| 修复-12 | scripts/errors.py | 通用异常打印不友好 | 替换为友好错误(原因 + 下一步 + 自动修复入口) |
新增能力
- 能力-1 SQLite 存储(
scripts/storage.py):运行 / 帧 / 产品 / 页面模块 / 差异 5 张表 - 能力-2 对比趋势板块(
scripts/diff_engine.py):广告语变化、新增帧、消失帧、新增产品、消失产品 - 能力-3 Word 自定义章节(预留接口
extra_sections) - 能力-4 趋势折线图(matplotlib 嵌入思源字体,避免中文乱码)
- 能力-5 OCR 低置信度自动视觉(
--with-vision开关) - 能力-6 小白友好 7 件套:
- 一键环境(
scripts/setup.py) - 预设套餐(
--preset beginner8 家) - 人话报错(友好错误)
- 5 分钟向导(
--guide) - 默认全开(无头模式、字体嵌入、含趋势 三者默认均为真)
- 进度可视化(待 rich 库接入)
- 小白词典(10 行术语表)
- 一键环境(
修复 v7.2 历史缺陷防回归
(v7.2 修复保留:修复-1 字体嵌入死代码 / 修复-2 爬虫失败标志 / 修复-3 简称映射 / 修复-4 未使用变量 / 修复-5 文档对齐)
测试统计
- 单元测试 95 个用例(v7.2 时代 47 → v7.3 时代 95;最新统计见文末 v7.5 记录段)
- 新增 v7.3 回归测试 9 个(
test_bugfix_v73.py):覆盖载荷反序列化、产品独占运行查找、模块独占运行查找等
测试模块清单:
test_storage.py(8 用例)— SQLite 增删改查 + 索引 + 事务test_diff_engine.py(6 用例)— 5 种差异类型test_page_module_extractor.py(4 用例)— 模块分类test_friendly_errors.py(5 用例)— 5 个错误码test_word_exporter.py(14 用例)— 5 板块断言(v7.5 补齐板块 5「自动点评」6 子节 + 模块 diff 渲染)test_scheduler.py(5 用例)— 定时解析 + 退避test_bugfix_v73.py(9 用例)— v7.3 缺陷修复回归test_commentary_engine.py(23 用例,v7.4 新增)— 点评引擎test_scraper_logic.py(18 用例)— scraper 纯逻辑- 保留 v7.2 47 用例(应用注册 22 + 字体嵌入 7 + 爬虫逻辑 18)
📝 v7.4 升级与缺陷修复记录(2026-07-31)
v7.4 重大升级:① 修复阻断性 SyntaxError ② Word 报告新增第 5 板块「自动点评」③ APP 名单从 137 → 151 家。
修复的真实缺陷
| 编号 | 文件 | 现象 | 修复 |
|-----|------|------|------|
| 修复-13 | scripts/scraper.py:797 | _scrape_with_browser 的 try/finally/except 嵌套错,导致整个模块无法 import,run.py 全流程崩溃(阻断性 P0) | 重构为单层 try/except/finally:外层管异常+关 context,内层 try-finally 删除 |
| 修复-14 | scripts/run.py:386/415 | 视觉校验逻辑混乱:未指定 --with-vision 也会调视觉模型(与参数语义不符) | 统一为 if with_vision and vision_available and ocr["needs_vision_verify"] |
| 修复-15 | scripts/diff_engine.py:80 | 模块表 app_name 兜底用 key 当显示名,导致 diff 输出"tdx_zq"等丑陋 key | 改为 app_registry.get_app(k).name 查中文名,注册表中无则降级 |
| 修复-16 | SKILL.md:189/237/253 | 测试数写"95"陈旧 | 改为"118"(v7.4 实际) |
| 修复-17 | agents/openai.yaml:3 | 描述写"130+家"陈旧 | 改为"150+家" |
| 修复-18 | references/app_selectors.md:6 | "第一轮 15 家深度调研"已过时 | 改为"150+ 家,按类别自动填充选择器模板" |
| 修复-19 | references/scrapability_report.md:3 | "全量清单 python scripts/app_registry.py"与实际 CLI 命令不符 | 改为 python scripts/run.py --list-apps |
新增能力
- 能力-7 APP 名单扩展(137 → 151):
- 互联网保险(4 家):众安保险、水滴保、慧择、微保WeSure
- 券商补充(4 家):东方财富证券、华鑫证券、湘财证券、中银证券
- 期货补充(3 家):海通期货、银河期货、徽商期货
- 财富管理(3 家,新类别):钜派、恒天财富、普信资产
- 类别数 12 → 14
- 能力-8 自动点评引擎(
scripts/commentary_engine.py):- 统计型:同类别横向对比(股份制 vs 国有大行的推广热点)+ OCR 关键词聚类(10 大推广主题)+ 产品类型分布
- 趋势型:基于 diff 数据归纳(变化最频繁 APP、变化类型分布、营销节奏判断)
- LLM 点评:
--with-llm-comment启用,需 VISION_API_KEY;未配置自动降级
- 能力-9 Word 报告 5 板块化:原 4 板块基础上新增第 5 板块「自动点评」,含 6 个子节(人话要点/推广热点/产品类型/横向对比/趋势/LLM)
- 能力-10 CLI 增强:新增
--with-llm-comment参数;run_scrape_and_export / collect_mode 均支持 - 能力-11 测试增强:新增
test_commentary_engine.py(23 用例),覆盖统计/趋势/LLM 三个点评来源 + 综合入口
修复 v7.3/v7.2 历史缺陷防回归
(v7.3 修复保留:修复-1~12;v7.2 修复保留:字体嵌入死代码 / 爬虫失败标志 / 简称映射 / 未使用变量 / 文档对齐)
测试统计
- 单元测试 118 个用例(v7.2 时代 47 → v7.3 时代 95 → v7.4 时代 118)
- 新增 v7.4 测试 23 个(
test_commentary_engine.py) - 因阻断性 P0 修复,2 个之前 collect error 的测试文件(test_scraper_logic.py 18 用例 + test_word_exporter.py 8 用例)现在全跑通
运行测试:
cd D:\claude 开发\skill of me\app-home-monitor
python -m pytest tests/ -v
# 目标:>= 161 个测试通过(最新统计见文末 v7.5 记录段)
📝 v7.5 升级与缺陷修复记录(2026-08-01)
v7.5 重大升级:集中修复 P0×5 / P1×10 / P2×7 共 22 项已核实缺陷(含 5 项数据丢失级 P0),新增页面模块 diff(模块增删改),单元测试从 118 → 161。
修复的真实缺陷
P0(数据丢失 / 功能失效)
| 编号 | 文件 | 现象 | 修复 |
|-----|------|------|------|
| 修复-20 | scripts/scraper.py | 多页采集时 frame_index 每页从 1 重新编号 → 跨页重复,写库撞键、diff 静默丢帧 | 按已收集帧数做全局偏移 index_offset,保证跨页唯一 |
| 修复-21 | scripts/scraper.py | BLOCKED_URL_KEYWORDS 误含 advertising → 把要采的广告横幅 CDN 自己拦掉 | 移出拦截词;保留 doubleclick / google-analytics 等真实广告联盟 |
| 修复-22 | scripts/app_registry.py | heavy_spa 含不存在的 key(cmbchina / huatai)→ 31 家券商渲染等待不足采不到 | 改为真实 key:招商证券 cmschina、华泰证券 htsc |
| 修复-23 | scripts/run.py | --list-apps / --guide / --check-env 分派排在 auto_install 之后 → 纯信息命令卡几分钟下浏览器 | 信息命令分派提到 auto_install 之前 |
| 修复-24 | scripts/carousel_extractor.py | _filter_decorative 异常时 fail-closed → 整页真实轮播帧被当装饰图丢弃 | 改为 fail-open:取不到尺寸时保留帧 |
P1(输出失真 / 开关失效)
| 编号 | 文件 | 现象 | 修复 |
|-----|------|------|------|
| 修复-25 | scripts/commentary_engine.py | 视觉模型识别出的 product_type 分支是 pass 死代码 → 产品类型分布丢视觉结果 | 补全统计逻辑;'其他'/空不计入 |
| 修复-26 | scripts/commentary_engine.py | success_count 用恒不存在的 __all__ 键 → 失败样本不反映到"数据完整度" | 改为真实统计键,失败时人话要点体现完整度 |
| 修复-27 | scripts/run.py | --strict 异常被外层 except 吞掉 → 承诺的"环境缺失即 raise"失效 | strict 分支显式 raise |
| 修复-28 | scripts/errors.py | check_fonts 硬编码 CN 命名,与 font_embedder 的 SC 别名集不一致 → 误报 FONT_MISSING | 同步支持 SourceHanSansSC-* 命名,空目录仍报错 |
| 修复-29 | scripts/deps.py | 依赖清单三份不一致,auto_install 漏装 openai → --with-llm-comment 运行时崩 | deps.py 单一真源;openai 归 OPTIONAL;auto_install 装 ALL_DEPS;requirements 去掉无 import 的 schedule |
| 修复-30 | scripts/app_registry.py | resolve_apps 从不查 PRESET_ALIASES → 口语化别名(推荐/小白/主流)解析失败 | 补预设别名解析,且不劫持类别名('基金销售' 仍返回整类) |
| 修复-31 | scripts/app_registry.py | dfzq_zq 与 eastmoney URL 相同 → 同页抓两遍出重复帧 | 注册表 URL 去重(回归测试强制无重复 URL) |
| 修复-32 | scripts/page_module_extractor.py | [role='tab'] 同时在 NAV/TAB 选择器 → 同一元素模块双计 | role=tab 只留在 TAB_SELECTORS,两列表强制无重叠 |
| 修复-33 | scripts/page_module_extractor.py | extract_modules_safe 的 timeout 声明后从未使用(死参数) | 真正 set_default_timeout 生效 |
| 修复-34 | scripts/vision_verify.py | is_vision_available 未 strip → 空白 key 判为可用,每帧吃 401 | strip 后判空 |
P2(健壮性 / 性能)
| 编号 | 文件 | 现象 | 修复 |
|-----|------|------|------|
| 修复-35 | scripts/word_exporter.py | detail_url=None(DB NULL 回读)时 len(None) 崩 | 判空兜底 |
| 修复-36 | scripts/diff_engine.py | 产品比对各按 app 重复查库,多打 2×N 条 SQL | 复用已取全量结果,内存过滤 |
| 修复-37 | scripts/storage.py | bulk_insert_* 每条一个事务 → 慢 + 写放大 | 改 executemany 单事务,空输入不报错 |
| 修复-38 | scripts/storage.py | frames 对 OCR 全文整列建索引 → DB 膨胀且无查询用得上 | 收窄为 substr(ocr_text, 1, 64) 前缀索引 |
| 修复-39 | scripts/carousel_extractor.py | 图片去重不归一化 URL(?v=1 与 ?v=2 算两张) | _normalize_image_url 去 query / 协议 / 片段后判重 |
| 修复-40 | scripts/vision_verify.py | 视觉返回空内容仍标 verified=True → 空结果被当已校验、不重试 | 空返回不标 verified |
| 修复-41 | scripts/storage.py | _hash_image 失败路径全部返回 "" → 不同失败帧互相碰撞 | 失败返回空,成功哈希加宽到 32 位 |
新增能力
- 能力-12 页面模块 diff:对比维度从帧/产品扩展到页面模块,新增
module_added/module_removed/module_changed(同名同类但跳转地址变,如活动换期)三类变化;中文名统一走CHANGE_TYPE_CN单一真源;word_exporter 板块 4 趋势文本与 commentary_engine 同步渲染,不吐英文 key - 能力-13 测试增强:新增
test_bugfix_v75.py(37 用例)逐条对应已核实缺陷 + 模块 diff 6 用例;test_storage.py补齐事务化批量/前缀索引/哈希加宽回归
修复 v7.4/v7.3/v7.2 历史缺陷防回归
(v7.4 修复保留:修复-13~19;v7.3 修复保留:修复-1~12;v7.2 修复保留:字体嵌入死代码 / 爬虫失败标志 / 简称映射 / 未使用变量 / 文档对齐)
测试统计
- 单元测试 161 个用例(v7.2 时代 47 → v7.3 时代 95 → v7.4 时代 118 → v7.5 时代 161)
- 新增 v7.5 回归测试 37 个(
test_bugfix_v75.py):覆盖 22 项缺陷 + 页面模块 diff
测试模块清单(当前准确):
test_storage.py(8)— SQLite 增删改查 + 事务化批量 + 前缀索引 + 哈希加宽test_diff_engine.py(8)— 5 类差异 + v7.5 页面模块 diff 3 类test_page_module_extractor.py(4)— 模块分类test_friendly_errors.py(6)— 6 个错误码test_word_exporter.py(14)— 5 板块断言(板块 5 6 子节 + 模块 diff 渲染)test_scheduler.py(5)— 定时解析 + 退避test_bugfix_v73.py(9)— v7.3 缺陷修复回归test_bugfix_v75.py(37)— v7.5 缺陷修复回归test_commentary_engine.py(23)— 点评引擎test_scraper_logic.py(17)— scraper 纯逻辑test_app_registry.py(23)— 应用注册test_font_embedder.py(7)— 字体嵌入
运行测试:
cd D:\claude 开发\skill of me\app-home-monitor
python -m pytest tests/ -v
# 目标:>= 161 个测试通过
📝 v8 升级与新增能力记录(2026-08-03)
v8 重大升级:从「金融 APP 首页监控」扩展为「金融机构专属公告广告监控与分析」。数据源从 151 家 APP 扩展到 210 个(+ 机构官网 + 财经媒体 + 财经论坛 + 自媒体),广告形式从图片扩展到图片 + 文字 + 视频,新增跨源横向对比、时间范围查询、舆情与情感分析。
新增能力(v8.0 / v8.1)
多数据源架构
- 能力-14 统一数据源抽象:
AppConfig加source_type(app/website/media/social/forum)+ 可选字段(website_of/list_selector/item_selector/content_selector/date_selector/search_url/max_items/ad_types/account),全部带默认值 → 现有 151 条配置零改动 - 能力-15 统一采集管线:
collector.py按 source_type 分派 → 各采集器产出归一化ScrapeResult→ 下游 OCR/存储/diff/点评/报告共用一条管线 - 能力-16 官网深爬(
website_collector.py):banner 轮播 + 文字广告 + 产品 + 公告/资讯页,website_of复用既有 151 家 URL 避免重复 - 能力-17 财经媒体新闻(
news_collector.py):12 家权威媒体 + 门户财经,列表→详情抓新闻标题/摘要/时间/作者 - 能力-18 财经论坛舆论(
forum_collector.py):股吧/基金吧/雪球/知乎/贴吧,帖子 + 回复/浏览热度 +parse_count("1.2万"→12000) - 能力-19 自媒体公开部分(
social_collector.py):B站/美篇公开端点 + 登录墙manual_hint手动补充(复用蚂蚁财富模式)
广告形式扩展
- 能力-20 文字广告(
text_ads表 + 提取器):页面广告话术关键词命中提取 - 能力-21 视频广告深度(v9 状态:计划,未实装;v9 已删除
video_extractor.py占位脚本,待阶段2 接入采集主链路):yt-dlp/浏览器下载 → ffmpeg/opencv 抽帧 → OCR 帧内容 → whisper ASR 转文字(工具全部可选,缺失降级)
分析能力
- 能力-22 跨源横向对比(
cross_source_summary):公司维度(广告投放量=帧+文字+视频)vs 平台维度(APP/官网/媒体/论坛/自媒体活跃度) - 能力-23 舆情热点(
public_opinion_hotspots):帖子关键词聚类 + 热帖榜 - 能力-24 情感分析(
sentiment_analysis+text_analysis.py):词典级离线兜底 + 模型级(OpenAI 兼容,复用 VISION_API_KEY),--with-llm-analysis - 能力-25 时间范围查询:
--query --since/--until+query_engine.py,从数据库读窗口数据出对比报告 - 能力-26 diff 扩展:CHANGE_TYPE_CN 从 8 → 20 类(news_added/removed/changed、post_added/removed/post_hot_changed、text_ad_added/removed/changed、video_added/removed/changed)
- 能力-27 Word 10 板块:新增六(媒体新闻)/七(舆论监控)/八(文字广告)/九(视频广告)/十(跨源横向对比)
工程
- 能力-28 存储迁移:
_migrate用PRAGMA table_info守卫ALTER TABLE幂等加列(兼容老 db);news/posts/text_ads/videos 4 张新表 + bulk 单事务;list_runs/get_latest_run 三表 UNION → 七表 - 能力-29 依赖/错误扩展:deps.py OPTIONAL 加 cv2/yt_dlp/whisper;errors.py 加 VIDEO_TOOL_MISSING/MEDIA_BLOCKED/SOCIAL_LOGIN_WALL
修复的真实缺陷(v8 实测发现)
| 编号 | 文件 | 现象 | 修复 |
|-----|------|------|------|
| 修复-42 | scripts/scraper.py | PostItem 缺 url 字段,论坛采集器传 url 直接崩 | 加 url 字段(posts 表同步加列) |
| 修复-43 | scripts/word_exporter.py | 新闻表格用 n.source_name,而 NewsItem 无此属性 → Word 生成崩 | 改 getattr(n, "source_name", "") or r.app_name |
| 修复-44 | scripts/commentary_engine.py | v8 新函数直接 r.source_type,旧 FakeResult 测试无此属性 → 旧测试崩 | 改 getattr(r, "source_type", "app") |
| 修复-45 | scripts/storage.py | save_results 直接访问 n.url 等属性,字段不全的桩数据崩 | 全改 getattr 兜底 |
| 修复-46 | scripts/registry_websites.py | 6 家基金公司官网 URL 与既有 151 家 APP 重复,触发 URL 唯一断言 | 改 website_of 关联复用(如 nffund→southernfund) |
测试统计
- 单元测试 313 个用例(v7.5 时代 161 → v8 时代 311,新增 150 + v8.2 回归 2)
- v8 测试文件 12 个:
test_source_registry.py(26)— 多数据源注册表 + resolve_sourcestest_news_collector_logic.py(12)— 新闻标题清洗/日期/正文提取test_forum_collector_logic.py(12)— parse_count 万/亿/k + 热度启发式test_storage_v8.py(20)— 新表 CRUD/bulk/迁移/时间范围/七表 UNIONtest_diff_v8.py(14)— 新闻/帖子/文字广告/视频 diff + 热度阈值test_commentary_v8.py(16)— 跨源对比/舆情热点/情感分析test_word_exporter_v8.py(9)— 10 板块空安全 + 各数据源渲染test_run_query_mode.py(12)— --since/--until/--query 窗口查询test_text_analysis.py(14)— 词典情感/主题/批量/无 key 降级test_video_extractor_logic.py(5)— 视频采集 mock 全链路test_social_collector_logic.py(6)— 自媒体注册表 + manual_hinttest_cli_dispatch.py(2)— collector APP 分派 + --query 不触发自动安装
运行测试:
cd D:\claude 开发\skill of me\app-home-monitor
python -m pytest tests/ -v
# 目标:>= 313 个测试通过
📝 v8.2 实测优化记录(2026-08-03)
本轮通过完整单元测试 + 真实 CLI 冒烟(媒体源、APP 源、查询模式、环境检测)发现并修复:
| 编号 | 文件 | 现象 | 修复 |
|-----|------|------|------|
| 修复-47 | scripts/collector.py | collector.py 把 APP 分组传成 list,scrape_apps 期望 dict → 任何 APP 采集直接崩溃 | 分派时改传 {c.key: c for c in cfgs},其他采集器仍传 list |
| 修复-48 | scripts/run.py | --query 是纯读库命令,却在 auto_install 之后分派 → 空查询实测卡 100 秒并尝试下载字体 | 把 --query 提前到 auto_install 之前,实测降至约 0.2 秒 |
| 修复-49 | scripts/_auto_install.py / scripts/errors.py | Tesseract 已装在默认目录但不在 PATH,环境检测误报缺失 | 检测逻辑增加 Windows 常见安装路径兜底,--check-env 实测识别为 5.4.0 |
验证结果
python -m pytest tests/ -q:313 passed + 151 subtests passedpython scripts/run.py --apps 天天基金 --skip-auto-install:正常出 Word,32 个产品、3 帧python scripts/run.py --query ...:0.19 秒返回,不触发自动安装python scripts/run.py --check-env:Tesseract OCR 识别成功
另发现:--with-video 与 --with-llm-analysis 目前仍是 v8 阶段2 预留参数,尚未真正接入采集主链路;本轮按最小范围未扩展该功能。
📝 v9 升级与缺陷修复记录(2026-08-03)
本轮承接同一日的 v8:用户报告 Word 报告 字体 与 图表显示错误,同时要求 增强与用户的互动对话能力,并补充 优化性能 + 清理无法使用的文件。
修复的真实缺陷
| 编号 | 文件:行 | 现象 | 修复 |
|---|---|---|---|
| 修复-50 | scripts/word_exporter.py:_add_trend_chart | 趋势图注册中文字体用 fcfg.get("path") 取路径,但 font_embedder.get_default_font_configs() 返回的 dict 键是 regular/bold/italic/bold_italic → fpath 永远 None → font_manager.addfont 从未被调用 → 图中的中文标签(时间/标题/轴)全是豆腐框(□□□) | 抽出 _register_mpl_chinese_fonts() 模块级缓存函数,正确遍历 4 个权重键调 addfont;rcParams["font.sans-serif"] 用实际 family name(Source Han Sans SC、Noto Sans CJK SC);已注册的思源字体下也兼容 Noto 命名 |
| 修复-51 | scripts/word_exporter.py:884 | 封面写死 "130+家金融APP(12类别:...)",但 v8 已扩到 151 家 + 5 类 source_type(app/website/media/forum/social) | 改为动态文案:从 app_registry.APPS 取 len(APPS) + len({cfg.source_type for cfg in APPS.values()}),输出形如 "监控范围:151 家金融APP(5 类数据源:APP首页、机构官网、财经媒体、财经论坛、自媒体)" |
| 修复-52 | scripts/word_exporter.py:_add_trend_chart | _add_trend_chart 对空 runs 入参会进 plt.subplots 后报诡异错误;用 NamedTemporaryFile 在 try 之外 close 偶发 Windows unlink 失败 | 加 empty-timestamps 守护;改 tempfile.mkstemp + os.close(fd),finally 强制 unlink;dpi 120→150 |
| 修复-53 | scripts/word_exporter.py:set_cell_font | 原实现 cell.text = "" 销毁默认段落并新建,151 APP × 5 表 × N 单元格时累计浪费可观 | 改为对默认段落 cell.paragraphs[0] 直接清旧 runs 再 add_run,省掉段落重建开销 |
清理的死代码
| 文件 | 类型 | 删除理由 |
|---|---|---|
| scripts/video_extractor.py(188 行) | 生产脚本占位 | v8 标为"阶段2 计划",整库 0 生产调用(collector.py 不分派到它);social_collector.py 仅以 docstring 提及 |
| tests/test_video_extractor_logic.py(76 行) | 上述脚本的测试 | 母文件删除后测试失效 |
| tests/test_bugfix_v73.py(147 行) | 旧回归测试 | 其覆盖的载荷反序列化/产品查找/模块查找 9 个用例已被 test_bugfix_v75.py、test_word_exporter_v8.py、test_storage.py 全部替代 |
合计删除 411 行 无用代码 + 同步清理 SKILL.md、registry_social.py、social_collector.py 中对 video_extractor 的引用(改为"阶段2 计划"措辞)。
新增能力
- 能力-22 趋势图字体注册独立模块化:
_register_mpl_chinese_fonts()配合模块级_MPL_FONTS_REGISTERED缓存,第一次跑注册一次字体,所有后续 trend chart 复用,避免 matplotlib fontmanager 反复 IO + 重建。_register_mpl_chinese_fonts()返回已注册字体文件名列表(用于诊断) - 能力-23 对话式交互模式:完整重写
scripts/run.py:interactive_mode()为 3 步向导(范围→浏览器→附加能力),关键设计:- 每步都附「📋 等价命令」:用户可直接复制到命令行运行,减少学习成本
- CATEGORY_ALIASES 别名映射:内置"基金销售/银行/券商/保险/期货/第三方销售/互联网理财/财富管理"中英文别名
- 输入兜底识别:用户随便输入(逗号/类别/套餐名)都能识别
─表格框 + emoji:让终端易扫读- 启动前摘要:范围/模式/附加 三项先确认再跑
- 能力-24 趋势图运行时埋点:
_add_trend_chart加print(" 趋势图渲染: X.YYs (N KB)")耗时输出,便于后续 profile
性能优化(汇总)
| 项 | 文件 | 效果 |
|---|---|---|
| matplotlib 字体注册模块级缓存 | word_exporter.py | 多次生成趋势图免重 IO + 避免 fontmanager 重建 |
| 单元格写入微优化 | word_exporter.py:set_cell_font | 干掉 cell.text = "" 段落重建,151 APP × N 单元格累计可观 |
| 趋势图 dpi 120→150 | 同上 | 视觉清晰度提升 |
| 趋势图临时文件强清理 | 同上 | mkstemp + finally 保证 PNG 留不下 |
| 趋势图耗时埋点 | 同上 | 输出每次渲染耗时,便于后续分析 |
基准(Python 3.11 + python-docx):30 APP × 5 产品 × 3 帧 Word 生成 ~1.7s;151 APP 等比 ~8s——网络爬取才是真正瓶颈。
修复 v8/v8.2/v7.5/v7.4/v7.3/v7.2 历史缺陷防回归
(v8 修复保留:修复-42~49;v7.5 修复保留:修复-20~41;v7.4 修复保留:修复-13~19;v7.3 修复保留:修复-1~12;v7.2 修复保留:字体嵌入死代码 / 爬虫失败标志 / 简称映射 / 未使用变量 / 文档对齐)
测试统计
- 单元测试 299 passed / 3 skipped / 151 subtests(v8.2 时代 313 → v9 时代 299,删除 16 个 v7.3 老用例被重复覆盖的,新增 5 个 v9 回归 + 3 个依赖 matplotlib 的用例在未装环境 skip)
- v9 测试文件新增 + 删除:
- 新增
tests/test_word_exporter_v9_bugfix.py(5 用例):test_register_uses_regular_key_not_path—— 守住修复-50(addfont 必须被调到,键必须是regular/bold/italic/bold_italic)test_register_handles_no_fonts—— 空fc时不崩(修复-50 守护)test_add_trend_chart_handles_empty_runs—— 修复-52(空 runs 不崩)test_word_scope_text_not_hardcoded—— 修复-51(不再含 "130+家" 字面量)test_word_scope_text_reflects_real_source_types—— 修复-51(含真实 source_type 集合)
- 删除
tests/test_bugfix_v73.py(9 用例,其覆盖的载荷反序列化/产品查找/模块查找 9 个用例已在test_bugfix_v75.py、test_word_exporter_v8.py、test_storage.py等更现代测试中) - 删除
tests/test_video_extractor_logic.py(5 用例,母文件video_extractor.py已删)
- 新增
当前测试模块清单(22 个文件,299 用例):
| 文件 | 用例数 | 说明 |
|---|---|---|
| test_storage.py | 8 | SQLite 增删改查 + 事务化批量 + 前缀索引 + 哈希加宽 |
| test_storage_v8.py | 20 | 新表 CRUD / bulk / 迁移 / 时间范围 / 七表 UNION |
| test_diff_engine.py | 8 | 5 类差异 + v7.5 页面模块 diff 3 类 |
| test_diff_v8.py | 14 | 新闻/帖子/文字广告/视频 diff + 热度阈值 |
| test_page_module_extractor.py | 4 | 模块分类 |
| test_friendly_errors.py | 6 | 6 个错误码 |
| test_word_exporter.py | 14 | 5 板块断言(板块 5 6 子节 + 模块 diff 渲染) |
| test_word_exporter_v8.py | 9 | 10 板块空安全 + 各数据源渲染 |
| test_word_exporter_v9_bugfix.py | 5(新) | v9 修复回归:字体注册 + 动态文案 + 空 runs 守护 |
| test_scheduler.py | 5 | 定时解析 + 退避 |
| test_bugfix_v75.py | 37 | v7.5 缺陷修复回归 |
| test_commentary_engine.py | 23 | 点评引擎 |
| test_commentary_v8.py | 16 | 跨源对比/舆情热点/情感分析 |
| test_scraper_logic.py | 17 | scraper 纯逻辑 |
| test_app_registry.py | 23 | 应用注册 |
| test_source_registry.py | 26 | 多数据源注册表 + resolve_sources |
| test_news_collector_logic.py | 12 | 新闻标题清洗/日期/正文提取 |
| test_forum_collector_logic.py | 12 | parse_count 万/亿/k + 热度启发式 |
| test_social_collector_logic.py | 6 | 自媒体注册表 + manual_hint |
| test_text_analysis.py | 14 | 词典情感/主题/批量/无 key 降级 |
| test_font_embedder.py | 7 | 字体嵌入 |
| test_run_query_mode.py | 12 | --since/--until/--query 窗口查询 |
| test_cli_dispatch.py | 2 | collector APP 分派 + --query 不触发自动安装 |
| 删除 ~~test_bugfix_v73.py~~ | ~~9~~ | v9 移除(已被 v7.5/v8 测试覆盖) |
| 删除 ~~test_video_extractor_logic.py~~ | ~~5~~ | v9 移除(母文件已删) |
运行测试:
cd D:\claude 开发\skill of me\app-home-monitor
python -m pytest tests/ -v
# 目标:>= 299 个测试通过(matplotlib 装好后 302 全过)
验证结果
python -m pytest tests/ -q:299 passed, 3 skipped, 151 subtests passedpython scripts/cleanup_cache.py:清理 11 个.pyc缓存项
后续可能跟进(v9 没做、值得跟)
- 装 matplotlib 后跑一次现状报告,肉眼验证中文标签正常(当前环境 matplotlib 未装,bug-1 测试 skip)
set_cell_font进一步走style.font+add_run批量模式(python-docx 支持;先 benchmark 再决定)- 视频广告深度采集(
--with-video)阶段 2 实装——删除video_extractor.py后该能力彻底未接;后续要做时建议先补 stub + 测试再写实现,避免再次变成永久占位 - 交互模式向导目前是纯
input()串行,未来可考虑走AskUserQuestion提升体验
📝 v9.1 升级记录(2026-08-10)
聚焦「广告/公告信息获取增强 + 竞品分析对比能力」。
新增模块(2 个)
1. scripts/ad_fetcher_enhance.py(325 行)
AD_HINT_KEYWORDS_V2:广告话术关键词 30 → 100+(9 大类:促销/拉新/福利/收益/行动/节日/品牌/教育/投资)is_ad_text()/extract_ad_score():广告强度识别与打分extract_video_posters_from_html():视频海报帧提取(v8 阶段 2 部分实装)extract_bg_images_from_css()/extract_bg_images_from_html():背景图 CSS 解析增强compute_hot_score()/classify_hot_level():综合热度评分(点赞×1 + 回复×5 + 浏览×0.1)parse_date_flex()/format_relative_date():灵活日期解析(相对+绝对)classify_ad_intent():4 类广告意图分类(拉新/促活/留存/挽回)
2. scripts/competitor_comparator.py(380 行)
compute_metric():单竞品指标计算compare_by_category():同类别横向对比(成员数 < min_members 跳过)compare_by_platform():跨平台投放对比cross_platform_summary():跨平台汇总(Word 报告用)compute_ad_similarity()/compare_ad_similarity():广告语 Jaccard 相似度intensity_leaderboard():全市场投放强度 TOP Nfull_competitor_report():完整竞品分析报告(一键产出 4 大板块)
数据类(4 个)
CompetitorMetric:单竞品指标(轮播/产品/文字广告/模块/新闻/帖子 + 推广热点 + 产品类型 + 强度分)CategoryComparison:同类别对比报告(含 hotsales_top3 / product_types_top3 / intensity_leader / highlights)PlatformComparison:跨平台对比报告AdSimilarityReport:广告语相似度(含 jaccard / common_phrases / only_a / only_b)
BUG 修复(6 类)
- 🐛 BUG-001 广告关键词不足:30 → 100+
- 🐛 BUG-002 视频海报帧未实装(v8 阶段 2 遗留)→ v9.1 部分实装
- 🐛 BUG-003 背景图 CSS 仅支持单引号 → 三引号 + data:URI/关键字过滤
- 🐛 BUG-004 日期解析只支持 ISO 格式 → 新增相对时间("X 分钟前"/"昨天")
- 🐛 BUG-005 帖子热度无综合评分 → 点赞×1 + 回复×5 + 浏览×0.1 加权
- 🐛 BUG-006 广告意图无分类 → 4 类意图(拉新/促活/留存/挽回)
测试覆盖
- ✅ 新增
tests/test_v91.py(81 个测试):- ad_fetcher_enhance:关键词/视频海报/背景图/热度/日期/意图 6 个 TestClass
- competitor_comparator:单指标/同类别/跨平台/相似度/排行榜/完整报告 6 个 TestClass
- BUG 修复回归:6 个 BUG
- 集成测试:增强→对比完整链路
- ✅ 全套 441 passed 1 skipped(v9 360 + v9.1 新增 81)
使用示例
from competitor_comparator import full_competitor_report
# 完整竞品分析报告
report = full_competitor_report(scrape_results)
for h in report["highlights"]:
print(h)
# 同类别对比
for cat_rpt in report["by_category"]:
print(f"{cat_rpt['category']}: {cat_rpt['member_count']} 家,强度第一 {cat_rpt['intensity_leader']}")
# 投放强度 TOP 10
for m in report["intensity_leaderboard"][:10]:
print(f"{m['app_name']}: {m['intensity_score']:.0f}")
# 广告语相似度
for pair in report["similarity_pairs"]:
print(f"{pair['app_a']} ↔ {pair['app_b']}: Jaccard={pair['jaccard']:.2f}")
from ad_fetcher_enhance import (
is_ad_text, extract_ad_score,
compute_hot_score, parse_date_flex,
classify_ad_intent,
)
# 广告强度打分
score = extract_ad_score("限时抢购 新户专享 立减100")
# → 6(命中 6 个关键词)
# 热度综合评分
hot_score = compute_hot_score(like_count=10, reply_count=20, view_count=5000)
# → 610.0
# 灵活日期解析
dt = parse_date_flex("3 小时前")
# → 当前时间 - 3 小时
# 广告意图分类
intent, score = classify_ad_intent("新户专享 立减100")
# → ("拉新", 2)
📝 v10.0 优化与缺陷修复记录
核心修复(4 大断点)
- 🐛 v10-BUG-001 ad_fetcher_enhance(158 词库/意图/视频海报/bg 解析)是死代码,零调用 → 全面接入 scraper + website_collector 主路径;文字广告入库附 ad_score + ad_intent
- 🐛 v10-BUG-002 competitor_comparator(竞品强度榜/相似度/品类矩阵)从未被 run.py 调用 → 接入报告流水线,Word 新增板块 11「竞品投放对比」(强度 TOP10 柱状图/品类矩阵/相似对/素材复用)
- 🐛 v10-BUG-003 frames 表无 image_url 列(原始广告图 URL 入库即丢) → 迁移补列 + insert/bulk SQL 修正 + 下载失败帧可重试
- 🐛 v10-BUG-004 视频广告被 BLOCKED_RESOURCE_TYPES 的 "media" 全拦(素材加载被拦死)
→ 移除 media 全拦,改为第三方广告域白名单拦截 +
extract_videosproducer 实装
分析升级(10 项)
- 强度分四维加权(数量 40% + 素材多样性 20% + vision 质量 20% + 意图覆盖 20%)+ 品类内 z-score
- 素材复用检测
detect_shared_assets(image_hash 跨 APP 聚类"同图多投") - 广告语相似度 Jaccard → TF 加权 cosine + n-gram 共现短语
- diff:text_changed 相似度阈值防 OCR 抖动误报、frame_image_changed(同位置图变)、 video_changed 实装、换序降误报(frame_added 标注"疑似轮播换序")
- 时间趋势
diff_trend(N-run 序列环比:帧数/产品数/主题热度) - OCR:OSD 方向回正 + PSM 多通道重试 + 逐词置信度 + NFKC 归一化 + image_hash 缓存
- 视觉校验:verify_batch 并发(5 线程)+ 图片压缩(长边≤1568)+ 指数退避重试 + 结果缓存 + schema 校验
- LLM 整页点评专用四段式 prompt(布局/主推产品/营销策略/风险提示)
- 情感词典 200+ 金融词 + 否定词翻转("未出现违规"不再误判负面)+ 模型并发 + 文本缓存
- 平台对比口径统一(total_items 不再混入 news/posts,与强度分一致)
性能提升(3 项)
- 图片并发下载(4 线程)替代串行(30 帧最坏 15 分钟 → 秒级)
save_results_to_storage主路径统一 bulk 单事务(200 帧 200 事务 → 1 事务)- 单 APP 软超时保护(默认 180s,防一个卡死拖垮整批)
测试覆盖
- ✅ 新增
tests/test_v10.py(31 个测试):ad_fetcher 集成 / 存储迁移 / 图片质量 / 强度分多维 / 素材复用 / TF-cosine / diff 阈值与帧图变 / diff_trend / OCR 归一化与缓存 / vision 压缩与并发 / 文本否定词 / Word 竞品板块 / 视频结构 - ✅ 全套 472 passed 1 skipped(441 + v10 新增 31)
📝 v10.1 优化与缺陷修复记录
轮播抓取盲区修复(7 项)
- 🐛 v10.1-BUG-001 background 轮播只扫 3 类 class + 单 url()(多背景
url(a),url(b)丢第 2 张) → 重写_CAROUSEL_SCAN_JS:全页面大尺寸块级启发式 +_split_bg_urls多 url 拆分 - 🐛 v10.1-BUG-002 CSS 伪元素 ::before/::after 背景图完全不可见
→ 扫描 JS 增加
getComputedStyle(el, '::before'/'::after')分支 - 🐛 v10.1-BUG-003 iframe / shadow DOM 内轮播完全不可见 → page.frames 遍历 + shadowRoot 递归 pierce
- 🐛 v10.1-BUG-004 canvas 绘制轮播无指示器时仅截 1 帧顶部 400px
→
_autoplay_burst_shots自动连拍(2s×8 + 字节去重)+_CAROUSEL_BOX_JS容器精确定位 - 🐛 v10.1-BUG-005 JS 动态渲染 swiper(IO 懒渲染/虚拟列表)帧缺失
→
_wait_swiper_stable(slide 数量 3 次采样稳定) - 🐛 v10.1-BUG-006 指示器缺失/不可点时无切换手段
→ INDICATOR_SELECTORS 增加左右箭头 +
_SWIPER_NEXT_JS(slideNext 驱动) - 🐛 v10.1-BUG-007 151 家 carousel_selector 全模板,文档 15 家精配从未进代码
→
_CAROUSEL_OVERRIDES字典落地(天天基金 .banner_box/#top_banner 等)
分析强化(3 项)
- 🐛 v10.1-BUG-008 帧去重只到 URL 归一化,内容级重复帧全链路浪费
→
_dhash_image/_dedup_frames_by_dhash(dHash 汉明距离 ≤4 视为同素材) - 🐛 v10.1-BUG-009 截图兜底帧整页 400px 噪声大
→
_CAROUSEL_BOX_JS精确定位轮播容器 clip - 🐛 v10.1-BUG-010 截图帧 vision 按"单张广告图"prompt 误判
→
verify_image(is_page_shot=True)+ PAGE_SHOT_PROMPT
链路强化(2 项)
_retry_download_frame:下载失败帧 OCR 阶段按 URL 重试- run.py 两处 OCR 循环并发化(6 线程)
测试覆盖
- ✅ 新增
tests/test_v101.py(27 个测试):多 url 拆分 / dHash 去重(同图/异图/缺失 fail-open)/ 扫描 JS 常量(伪元素/多url/data-bg/shadow/性能上限)/ 容器定位 JS / slideNext JS / 箭头指示器 / 连拍参数 / swiper 稳定等待 / 配置精配覆盖(key 存在性+模板生效+未精配不变)/ 失败帧重试 / vision 页面模式 - ✅ 全套 499 passed 1 skipped(472 + v10.1 新增 27)
微信扫一扫