返回 Skill 列表
extension
分类: 数据与分析无需 API Key

金融类广告公关辅助工具

金融机构专属公告广告监控与分析(v10.4)。监控 151 家金融 APP + 机构官网 + 财经媒体 + 财经论坛 + 自媒体的广告投放、产品推荐与舆论信息(基金/银行/券商/保险/第三方销售/媒体/论坛等)。无需登录直接爬取公开 Web/H5。图片广告(轮播逐帧 OCR+视觉)、文字广告三种形式全覆盖;视频广告轻量实装(v10:video poster+src 提取 + 海报帧下载 + iframe 播放器;v10.3:--with-video 海报 OCR 填充摘要)。媒体新闻稿件 + 论坛舆论 + 情感分析;多机构×多平台横向对比(谁投放多、哪个平台活跃)+ v9.1 新增同类别竞品对比矩阵 + 跨平台投放对比 + 广告语 TF-cosine 相似度 + 多维投放强度排行榜 + 素材复用检测。Word 报告 12 大板块(v10 新增竞品投放对比;v10.2 新增源健康度与广告强度多期趋势);轮播抓取强化(v10.1:全页背景图/伪元素/iframe/shadow DOM/canvas 连拍/dHash 去重;v10.4:srcset/data-srcset 高清候选提取 + CDN 缩放参数剥离拿高清原图 + avif 自动转 PNG);广告图分享能力(v10.4 新增 --share:ZIP 分享图包 + 自包含 HTML 画廊 + 单图分享卡片);爬取健壮性强化(v10.2:UA 指纹池轮换 / --proxy 代理 / 爬取错误七类分类 / SPA 域名外置;v10.3:JPEG/GIF 魔数嗅检修复 / vision 校验按帧配对 / --schedule 参数透传 / --with-video 实装 / 句柄与浏览器泄漏修复 / 注册表数据修正),支持一次性 / 增量 / 定时采集 / 时间范围查询(--query);交互模式为 3 步对话式向导(范围→浏览器模式→附加能力)。仅爬取非登录公开页面,合规安全。 触发词:监控 APP 首页推荐 / 轮播广告监控 / APP 首页广告爬取 / 爬取轮播图 / 基金销售 APP 推荐 / 银行 APP 首页 / 券商 APP 推荐 / 保险 APP 首页 / 天天基金 / 蛋卷基金 / 京东金融 / 和讯 / 蚂蚁基金 / 小白套餐 / 对比趋势 / 金融 APP 广告采集 / 理财推荐监控 / 首页推荐产品 / 公告广告监控 / 机构官网监控 / 财经媒体新闻爬取 / 基金公司新闻稿 / 财经论坛舆论 / 股吧舆情 / 自媒体监控 / 视频广告监控 / 文字广告 / 广告投放对比 / 多机构对比 / 时间范围查询 / 舆情分析 / 情感分析 / 交互模式 / 对话式向导 / 竞品分析 / 投放强度 / 广告相似度 / 跨平台对比 / 视频海报 / 热度评分 / 源健康度 / 采集成功率 / 连续失败 / 降级源 / 广告强度趋势 / 代理爬取 / UA 轮换 / 广告图分享 / 分享包 / 分享图包 / HTML 画廊 / 分享卡片 / 导出广告图 / 高清广告图 / srcset 提取。

person作者: user_9d5a2a39hubcommunity

金融机构公告广告监控与分析(v10.4)

总览

面向金融从业者/竞品分析师/合规审计,监控中国 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 语言包)+ --guide 5 分钟上手
  • 增量采集: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

会自动发生的事:

  1. 检测 pip 依赖 → 缺哪个装哪个
  2. 下载 Playwright 浏览器内核(约 150MB)
  3. 检测 Tesseract 文字识别工具 → 缺则尝试 winget/choco 自动装
  4. 下载思源字体到 assets/fonts/
  5. 下载OCR中文语言包到 assets/tessdata/
  6. 跑 8 家APP:天天基金、京东金融、蚂蚁财富、和讯、蛋卷基金、雪球、东方财富、同花顺
  7. 出 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

广告图分享包(v10.4:跑完后生成可直接分享的产物):

!python "scripts/run.py" --apps "{范围}" --share                       # 默认 ZIP 图包 + HTML 画廊
!python "scripts/run.py" --apps "{范围}" --share --share-format all    # 再加单图分享卡片
!python "scripts/run.py" --apps "{范围}" --share --share-format card   # 只要单图卡片

产物落在 data/share/:ZIP(按 APP 分目录 + manifest.json + index.csv)、自包含 HTML 画廊(单文件可直接发微信/钉钉/邮件)、单图卡片(广告图+来源/广告语信息栏)。

模型级文本/情感分析(需 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-DDYYYY-MM-DD HH:MM) | | --query | (不加) | 时间范围查询模式(读库出报告,配合 --since/--until) | | --no-headless | (不加) | 默认无头模式;调试时加此参数显示浏览器 | | --output | 自动生成 | 输出文件名(不含扩展名) | | --collect | (不加) | 增量模式(写数据库 + 后续可对比) | | --db | data/monitor.db | 数据库路径 | | --with-vision | (不加) | 低置信度OCR帧自动调视觉模型 | | --with-video | (不加) | 视频广告增强:视频海报帧 OCR 提取广告语(v10.3 实装;完整下载→抽帧→ASR 仍规划中) | | --with-llm-analysis | (不加) | 文本/情感分析启用模型级(无 key 降级词典) | | --share | (不加) | v10.4:跑完后生成广告图分享包 | | --share-format | zip,html | v10.4:分享格式 zip/html/card 逗号组合或 all | | --strict | (不加) | 严格模式:任何环境缺失都抛错(持续集成用) |

流程说明(脚本内部自动完成):

  1. 按 source_type 分派:app→scraper、website→官网深爬、media→新闻、forum→帖子、social→自媒体公开部分
  2. 提取各自内容(产品/轮播/文字广告/新闻/帖子/视频),产出归一化结果
  3. OCR(Tesseract 中文简体 + 英文)提取图片广告语;低置信度帧调视觉模型校验
  4. 视频广告深度:下载→抽帧→OCR帧内容→ASR转文字(全部可选降级)
  5. 文本/情感分析(词典级兜底,可选模型级)
  6. 增量模式:写数据库 + 计算与上次的差异(20 类变化:帧/产品/模块/新闻/帖子/文字广告/视频)
  7. 生成汇总 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:输出结果

向用户报告:

  1. Word 报告路径data/output/APP首页监控报告_YYYYMMDD_HHMMSS.docx
  2. 数据库(增量模式)data/monitor.db
  3. 爬取统计:成功数 / 总数、推荐产品数、轮播广告帧数
  4. 截图目录data/screenshots/
  5. 轮播图目录data/carousel_images/{APP名}/
  6. 分享产物(--share)data/share/(ZIP 图包 / HTML 画廊 / 单图卡片)
  7. 可爬性说明:蚂蚁财富不可爬(无公开网页版首页,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,运行时不生成 .pyc
  • conftest.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/share_exporter.py -- v10.4 广告图分享导出(ZIP/HTML 画廊/单图卡片)(何时查看:定制分享产物格式时)
  • 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/ -- 单元测试(638 个用例,含 v7.4/v7.5/v8/v9/v10.x 缺陷修复防回归)

📝 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_runlist_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 beginner 8 家)
    • 人话报错(友好错误)
    • 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 统一数据源抽象AppConfigsource_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 存储迁移_migratePRAGMA 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 | PostItemurl 字段,论坛采集器传 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_sources
    • test_news_collector_logic.py(12)— 新闻标题清洗/日期/正文提取
    • test_forum_collector_logic.py(12)— parse_count 万/亿/k + 热度启发式
    • test_storage_v8.py(20)— 新表 CRUD/bulk/迁移/时间范围/七表 UNION
    • test_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_hint
    • test_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 passed
  • python 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_italicfpath 永远 Nonefont_manager.addfont 从未被调用 → 图中的中文标签(时间/标题/轴)全是豆腐框(□□□) | 抽出 _register_mpl_chinese_fonts() 模块级缓存函数,正确遍历 4 个权重键调 addfontrcParams["font.sans-serif"] 用实际 family name(Source Han Sans SCNoto 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.APPSlen(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 后报诡异错误;用 NamedTemporaryFiletry 之外 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.pytest_word_exporter_v8.pytest_storage.py 全部替代 |

合计删除 411 行 无用代码 + 同步清理 SKILL.mdregistry_social.pysocial_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_chartprint(" 趋势图渲染: 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.pytest_word_exporter_v8.pytest_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/ -q299 passed, 3 skipped, 151 subtests passed
  • python scripts/cleanup_cache.py:清理 11 个 .pyc 缓存项

后续可能跟进(v9 没做、值得跟)

  1. 装 matplotlib 后跑一次现状报告,肉眼验证中文标签正常(当前环境 matplotlib 未装,bug-1 测试 skip)
  2. set_cell_font 进一步走 style.font + add_run 批量模式(python-docx 支持;先 benchmark 再决定)
  3. 视频广告深度采集(--with-video)阶段 2 实装——删除 video_extractor.py 后该能力彻底未接;后续要做时建议先补 stub + 测试再写实现,避免再次变成永久占位
  4. 交互模式向导目前是纯 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 N
  • full_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.py81 个测试):
    • 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_videos producer 实装

分析升级(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.py31 个测试):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.py27 个测试):多 url 拆分 / dHash 去重(同图/异图/缺失 fail-open)/ 扫描 JS 常量(伪元素/多url/data-bg/shadow/性能上限)/ 容器定位 JS / slideNext JS / 箭头指示器 / 连拍参数 / swiper 稳定等待 / 配置精配覆盖(key 存在性+模板生效+未精配不变)/ 失败帧重试 / vision 页面模式
  • 全套 499 passed 1 skipped(472 + v10.1 新增 27)

📝 v10.2 优化升级记录:爬取健壮性 + 分析深化(2026-08-16)

爬取强化(4 项)

  • 🚀 爬取-A UA 指纹池轮换:v10.1 全部 210 源共用同一对静态 UA(iPhone 17_2 / Chrome 120), 指纹极易被站点聚类识别 → MOBILE_UA_POOL(6 个 iOS/Android 真机 UA)+ DESKTOP_UA_POOL (4 个 Chrome/Edge/macOS UA),pick_user_agent() 按 context 随机轮换;scraper 与 website/media/forum/social 四采集器共 6 处接入;旧常量保留在池首向后兼容
  • 🚀 爬取-B 代理支持--proxy http://host:port(或 socks5://;缺省 scheme 补 http; 非法/空值静默忽略)+ 环境变量 MONITOR_PROXY 回退 → app 路径与共享浏览器路径均 launch 级 代理(对全部 context 生效)
  • 🚀 爬取-C 爬取错误分类classify_crawl_error() 把失败信息归为 7 类 (anticrawl/network/browser/playwright_missing/no_page/parse/unknown,优先级先具体后宽泛), ScrapeResult.error_type 字段 + scrape_apps/collect_sources 全部失败分支统一回填 (旧调用方缺 error_type 时 crawl_health 自动按 error 文本补分类)
  • 🚀 爬取-D SPA 域名外置:硬编码子串匹配 → SPA_DOMAIN_PATTERNS 模块级列表 + is_spa_url() 主机名精确/后缀匹配(?ref=jr.jd.com 等路径伪域名不再误判)+ AppConfig.spa=True 单源声明扩展位

分析强化(2 项)

  • 📊 分析-E 源健康度(新模块 crawl_health.py + 新表 source_status): --collect 增量模式逐源入库采集状态;build_source_health() 汇总本次成功率、 失败原因分布、连续失败 ≥3 次的降级源清单、按错误类型的处置建议(反爬→开代理/加大间隔、 browser→重装内核、parse→查选择器等);Word 报告新增板块 12「源健康度与采集质量」 (12.1 失败原因分布 + 12.2 连续失败降级源表);控制台汇总打印
  • 📊 分析-F 广告强度多期趋势:四维强度公式抽取为 intensity_score_from_counts() 纯函数(内存版 compute_metric 与 DB 版 compute_metric_from_counts 同公式同分); storage.get_intensity_counts() 按 run 聚合四维计数;intensity_trend() 输出近 N 期 逐源分数序列 + 净变化 + 升/降/平稳趋势 + 升降榜;Word 报告板块 11 新增 11.6 广告强度多期趋势(升降榜 + 逐源各期分数表)

接线与兼容

  • run.py--proxy 参数(缺省读 MONITOR_PROXY)→ 两条采集路径透传; run_scrape_and_export 出单次健康度、collect_mode 写 source_status + 出历史健康度 + 强度趋势, 两者均传入 create_word_report 新参数 health_report / intensity_trend_report(None 安全)
  • create_word_report 新增两个可选参数,旧调用零改动;空数据时板块 12/11.6 整节跳过

测试覆盖

  • ✅ 新增 tests/test_v102.py64 个测试):UA 池(非空/合法/去重/轮换多样性/可注入 rng/ 旧常量兼容)、代理解析(6 形态+非法拒绝)、错误分类(7 类+优先级+提前返回分支)、 SPA 匹配(后缀/大小写/路径伪域名/extra_patterns)、crawl_health(连续失败/成功率/降级判定/ 建议/汇总渲染/异常吞并/入库记录)、storage(source_status 读写过滤截断/强度计数聚合/空 run)、 强度公式(零值/手算值/内存-DB 等价性)、趋势分类与多期结构、Word 板块空安全与渲染、 collector/run 接线签名
  • 全套 563 passed 1 skipped(499 + v10.2 新增 64),v10.1 存量测试零回归
  • ✅ 离线端到端验证:3 期历史 + 当前 run → 健康度(降级源识别/建议生成)→ 强度趋势 (42→46→54→58 判"上升")→ Word 板块 12/11.6 渲染断言全过

📝 v10.3 优化升级记录:正确性修复 + 资源泄漏清理 + 死参数实装(2026-08-16)

本轮由 5 路并行代码审查(scraper/轮播、存储/diff、报告/分析、编排/采集器链路、 分析工具/注册表)+ 人工逐条验证产出 24 项已核实修复/升级,其中含 2 项数据正确性 P0、6 项资源泄漏、2 项死参数实装、2 项注册表数据错误。

修复的真实缺陷(按危害排序)

数据正确性(P0/P1)

| 编号 | 文件:位置 | 现象 | 修复 | |---|---|---|---| | v10.3-1 | run.py 单次+增量两处 | vision 校验结果按 OCR 完成顺序收集(as_completed),回填却按帧枚举顺序 idx 消费 → 并发下 vision 结果贴到错误的帧(广告语张冠李戴) | vision_pending 携带 frame 引用,verify_batch 返回后按 zip 严格配对回填 | | v10.3-2 | run.py:_retry_download_frame | 魔数校验 body[:8] 对比 4 字节 JPEG/6 字节 GIF 常量永不相等 → JPEG/GIF 失败帧重试下载永远被拒(轮播图最常见格式直接丢) | 新增 scraper.sniff_image_format() 统一嗅检(JPEG 全变体含 DQT/Adobe、GIF/WEBP/BMP/AVIF) | | v10.3-3 | carousel_extractor.py:_download_image | 同型魔数切片 bug → JPEG/GIF 帧每次都误判"非图片",白耗 max_retries 次重试下载(带宽×3 + 每次 sleep 2s)且日志误导 | 同上改用 sniff_image_format | | v10.3-4 | run.py --schedule 分派 | 定时模式只透传 3 个参数,--proxy/--with-vision/--with-llm-*/--with-video 全部静默丢弃 | Scheduler 新增 run_options 透传(scheduler.py 签名向后兼容) | | v10.3-5 | diff_engine.py:diff_runs | run_id 校验用 list_runs(limit=1000) 拉全量 → 历史 run 超 1000 条后(每日一跑约 3 年)合法 run_id 被误判不存在直接 raise | 改用 storage.get_run() 精确查询 | | v10.3-6 | diff_engine.py 帖子热度 | b_hot > 0 短路 → 基线热度 0 的新帖(首轮采集 reply/view 为 0)热度飙升永远不报 post_hot_changed | b_hot=0 时按绝对阈值判定 | | v10.3-7 | word_exporter.py:779 | f"{v.duration_sec:.0f}" 在 duration_sec 为 None(DB NULL 回读)时抛 TypeError 使整个 Word 生成失败 | f"{(v.duration_sec or 0):.0f}" | | v10.3-8 | scraper.py/collector.py error_type 回填 | 成功源也被 classify_crawl_error(None) 标成 "unknown",污染内存对象错误语义 | 仅失败源回填 |

资源泄漏(P1)

| 编号 | 位置 | 现象 | 修复 | |---|---|---|---| | v10.3-9 | competitor_comparator.py:703 | 素材复用检测 md5(open().read()) 不关句柄 | with 管理 | | v10.3-10 | collector.py 共享浏览器 | 采集器抛异常时 browser.close() 被跳过 → Chromium 进程残留 | 循环包 try/finally | | v10.3-11 | vision_verify.py:147/ocr_extractor.py:211/text_analysis.py:169 | 三处缓存/回退路径 open() 不关句柄(并发场景堆积) | with 管理 | | v10.3-12 | scraper.py:1455 批量路径 | 为拿 browser 建完整 context(UA/stealth 初始化)又立刻 close,每次浏览器重建白费一次 | 抽出 _launch_browser() 供批量路径直用 |

健壮性(P1/P2)

| 编号 | 位置 | 现象 | 修复 | |---|---|---|---| | v10.3-13 | scraper.py networkidle 降级 | except Exception 把 DNS 失败/连接拒绝也吞掉再白等 45s 二次 goto 同一坏 URL | 仅超时类错误降级,其余上抛走既有重试链 | | v10.3-14 | scraper.py 弹窗清理 | [class*=ad] 匹配 download/header/bread 等任何含 "ad" 的类名,可能误删页面主体 | 收窄为 ad-/ad_/-ad/_ad/advert/popup 等明确广告模式 | | v10.3-15 | vision_verify.py | OpenAI 调用无 timeout(SDK 默认 600s,并发批量被慢端点拖垮) | timeout=VISION_TIMEOUT_SEC(默认 60s,环境变量可调) | | v10.3-16 | vision_verify.py | message.content 为 None(安全过滤/token 用尽)时 .strip() 抛 AttributeError | (content or "").strip() | | v10.3-17 | vision_verify.py | P/RGBA 调色板图在 resize 之后才 convert("RGB") → LANCZOS 伪影 | convert 提前到 resize 之前 | | v10.3-18 | text_analysis.py | "非常看好"被单字"非"误判为否定翻转;"并非"在词表重复 | 假否定前缀剥离(非常/非凡/非议)+ 词表去重 | | v10.3-19 | scheduler.py | 高频 cron(*/30)任务跨窗口结束时按 now() 算下次 → 跳过未执行窗口 | 基于本轮原触发时间 next_run 计算 | | v10.3-20 | carousel_extractor.py | img_url 在元素循环中不重置,get_attribute 中途异常时残留上一张图 URL(串图) | 每元素先清空 |

数据/CLI(P2)

| 编号 | 位置 | 现象 | 修复 | |---|---|---|---| | v10.3-21 | app_registry.py 微保WeSure | URL 配置为 https://www.web.com/(无关域名停放站),采集写入无关内容 | 改 none + 历史官网域名(不可爬标注) | | v10.3-22 | app_registry.py 进出口银行 | http:// 明文(该站已强制 HTTPS,白挨 301) | 改 https | | v10.3-23 | run.py --query | 不带 --since/--until 时静默返回全量数据,易误读为窗口结果 | 显式提示 | | v10.3-24 | run.py interactive_mode | 交互模式丢 proxy 参数(MONITOR_PROXY 形同虚设) | 透传环境变量代理 | | v10.3-25 | word_exporter.py 图表两处 | matplotlib Figure 在 savefig 异常时不 close(内存泄漏) | plt.close 移入 finally | | v10.3-26 | word_exporter.py 元信息表 | 表格行数硬编码 5,加元数据项漏改会越界崩溃 | rows=len(meta_data) 自动同步 | | v10.3-27 | commentary_engine.py | 占比整数除法截断(1/3 显示 33% 而非 66.7% 的整数偏差) | round(..., 1) | | v10.3-28 | storage.py | _query_range/_columns 表名/列名直接拼 SQL(当前仅内部白名单字面量,属防御性债务) | _KNOWN_TABLES 白名单 + key_col 正则校验,非法输入直接 ValueError | | v10.3-29 | diff_engine.py | 帧 diff 每 app 全量过滤列表 = O(apps×rows) | 循环外预构建按 app 分组的帧索引 → O(rows),行为等价有回归测试 | | v10.3-30 | errors.py | raise_friendlysetdefault(detail, pop(detail)) 是无操作且残留未知 kwargs 会透传给 __init__ 抛 TypeError | 显式 pop detail/auto_fix + 未知参数直接 TypeError |

死参数实装(2 项)

  • --with-video 实装(v8 起空占位 5 个版本):新增 _ocr_video_posters()—— 对采集阶段已拿到的视频海报帧逐条 OCR 填充 VideoItem.ocr_combined, Word 板块 9"字幕/OCR摘要"列自此有内容;单次与增量两模式均已接线 (完整下载→抽帧→ASR 仍按 v8 规划留待后续)
  • --schedule 参数透传(见 v10.3-4)

其他

  • Pillow 弃用 API 防御:_dhash_image 优先 get_flattened_data(Pillow 14 移除 getdata)
  • --with-video help 文本与实际能力对齐(不再承诺未实装的 yt-dlp/ffmpeg 链路)

测试覆盖

  • ✅ 新增 tests/test_v103.py32 个测试):魔数嗅检 8 用例(含 DQT 变体/非图片拒绝)、 JPEG/GIF 重试下载回归(旧代码必挂)、vision 按帧配对集成测试(构造 OCR 乱序完成, 旧代码回填错位时必挂)、--with-video 单测、Scheduler 透传捕获、interactive proxy 透传、 get_run 校验、b_hot=0 热度触发、duration None 不崩、否定词 4 用例、注册表 2 用例、 P 模式大图、meta_table 行数同步、pct 四舍五入、plt.close finally、表名白名单 ×2、diff 索引等价性
  • 全套 595 passed 1 skipped(563 + v10.3 新增 32),v10.2 存量测试零回归
  • ✅ CLI 冒烟:--help / --list-apps(微保 ❌ 正确显示)/ --query(窗口提示)/ 编译检查全过

🚀 v10.4 优化升级记录:广告图爬取强化 + 分享能力(2026-08-18)

本轮围绕用户两大诉求:爬到更清晰的广告图 + 把广告图方便地分享出去

广告图爬取强化(carousel_extractor.py / run.py

| 编号 | 能力 | 说明 | |---|---|---| | v10.4-1 | srcset/data-srcset 高清候选提取 | 新增 _pick_srcset_best():w 描述符按像素宽度、x 描述符×1000 比较取最大;过滤 data: URI;协议相对/根相对/相对路径均按页面 URL 补全。懒加载触发 JS 同步 img[data-srcset]→srcset,元素循环中 srcset 命中即覆盖 src | | v10.4-2 | CDN 高清原图升级 | 新增 upgrade_image_url():剥离 x-oss-process/imagemogr2/imageview2/w/h 等 CDN 缩放参数还原原图;签名 URL 保护(含 sign/token/auth/expire 等一律不动,防 403) | | v10.4-3 | avif → PNG 自动转换 | _download_image 魔数嗅检命中 webp/avif 时统一走 _convert_webp_to_png 转 PNG,下游 OCR/报告/分享全兼容 | | v10.4-4 | 失败帧重试通道高清优先 | _retry_download_frame 先试 upgrade_image_url 高清候选,失败再回落原始 URL;帧构造记录实际下载成功的 URL(保证重试拿到的地址可用) |

分享能力(新增 share_exporter.py,约 440 行)

| 编号 | 能力 | 说明 | |---|---|---| | v10.4-5 | --share / --share-format CLI | 跑完采集生成分享包到 data/share/;格式 zip,html,card 逗号组合或 all(默认 zip,html) | | v10.4-6 | ZIP 分享图包 | 按 APP 分目录打包全部广告图,含 manifest.json(元数据清单)+ index.csv(utf-8-sig Excel 直开)+ README.txt;同名冲突自动加序号不覆盖 | | v10.4-7 | 自包含 HTML 画廊 | 单文件零依赖(大图缩放长边≤1200 JPEG q85 base64 内嵌),带 APP 筛选按钮、OCR 广告语、活动跳转链接;全文本 html.escape 防注入 | | v10.4-8 | 单图分享卡片 | 1080×1260 PNG(图区 1:1 + 信息栏:来源/时间/OCR 广告语/合规提示),思源字体逐级降级到默认字体;上限 20 张 | | v10.4-9 | fail-open 设计 | 各格式独立 try/except,分享失败/字体缺失/图片损坏均不阻断主流程;单次/增量/定时/交互四模式全接线(schedule 经 run_options 透传) |

测试覆盖

  • ✅ 新增 tests/test_v104.py43 个测试):srcset 解析 7 用例(w/x 描述符/data: 过滤/三类相对 URL 补全)、 CDN 参数剥离 7 用例(OSS/七牛/通用 w-h/签名 URL 保护)、重试通道高清优先与回落顺序(mock 捕获调用序)、 webp→PNG 转换、条目归一化(文件缺失过滤/空结果)、ZIP 结构(manifest/utf-8-sig/同名冲突/空清单)、 HTML 画廊(base64 内嵌/XSS 转义/上限截断/空结果不崩)、分享卡片(画布 1080×1260/缺图返空/长文案/字体降级)、 build_share_pack(格式解析/单格式/全格式/卡片上限)、run.py 接线 5 用例(签名/CLI 参数/Scheduler 透传)
  • 全套 638 passed 1 skipped(595 + v10.4 新增 43),v10.3 存量测试零回归
  • ✅ CLI 冒烟:--help 显示 --share/--share-format,编译检查全过

运行测试:

cd D:\claude 开发\skill of me\app-home-monitor
python -m pytest tests/ -q
# 目标:>= 638 个测试通过