网页变动盯梢
成品公式:用户给一个网址 → 拿到一份"哪一行变了"的差异报告(不是教程,不是"建议你用某某监控工具")。
解决的问题:竞品调价、官网条款悄悄改写、招聘页挂出新岗位、开源项目改了安装说明——这些都发生在老页面上,没有新文章、没有新链接,搜索引擎和 RSS 都不会提醒你。只能靠"把上次的样子存下来,这次再比一遍"。
全程本机运行:抓取、存档、比对都在用户电脑上,不经过任何第三方服务,不需要注册。
功能
| 子命令 | 用途 | 典型场景 |
|---|---|---|
add |
登记一个网址并立刻存下第一份快照 | "帮我盯着这个价格页" |
check |
全部(或指定)抓一遍,跟上次比 | 每天/每周定时执行 |
list |
看现在盯了哪些、上次什么状态 | 用户问"我都在盯啥" |
show |
看某页最近一份快照;--diff 看最近两份差异 |
"它上次写的是啥" |
rm |
删掉盯梢项 | "别盯这个了" |
脚本内置的判断(agent 不用操心):
- 自动解压 gzip/deflate。很多站点默认压缩响应,不解压拿到的就是乱码——更麻烦的是两次乱码完全一样,会让"零变化"变成永久静默失败。这是本技能最容易翻车的地方,已内置处理。
- 正文抽取:去掉 script/style/nav/footer 等,按段落分块成纯文本行,比对的是文字而不是 HTML,避免改了版式就报一堆差异。
- 噪声过滤:
--drop-noise丢掉访问量、时间戳、"3分钟前"这类每次都不一样却毫无意义的行;--ignore 正则丢掉指定内容(如页脚版权)。 - 只看在意的地方:
--match 正则只保留命中行。盯价格页时--match "元/月",页面上其他任何改动都不会打扰你。 - 纯数字变动加权:如果这次差异只是数字不同,报告里会标"⚠️ 只差数字",因为那通常就是价格、名额、版本号变了,最该先看。
- 单个失败不影响其他:一个网址被墙或改版,其余照常检查,报告里单独列出没抓成的及原因。
工作流程
- 问清两件事:①盯哪个网址 ②盯它的哪一部分。第二问很关键——整页比对噪声大,问出"你主要是怕价格变还是怕条款变",就能用
--match把范围收窄。 - 登记并建基线(路径一律绝对路径):
bash
SKILL_DIR="$HOME/.workbuddy/skills/nhao-page-sentinel"
[ -f "$SKILL_DIR/scripts/watch.py" ] || SKILL_DIR="$PWD/.workbuddy/skills/nhao-page-sentinel"
W="$SKILL_DIR/scripts/watch.py"
python3 $W add "竞品A-价格页" "https://example.com/pricing" --match "元/月|美元|收费" --drop-noise
- 立刻验一次:
add成功后马上check一次,应该是"无变化"。这一步能证明抓取和比对是通的;如果这时就报变化,说明页面里有每次访问都变的内容,需要用--ignore排掉。 - 出报告:
check -o 报告路径,报告是 Markdown,含一张状态总表 + 每个变化页的 diff 代码块。 - 替用户判断"这算不算真变了"——这是本技能的核心价值,别把 diff 原样丢给用户。看完差异后按下表给结论:
| 差异内容 | 怎么说 |
|---|---|
| 价格、费率、套餐额度、名额、版本号 | 「实质变化」,直接说改了从多少到多少 |
| 条款里的义务/期限/违约金/退款规则 | 「实质变化」,指出改了哪一句,建议用户自己再看一眼原文 |
| 招聘页新增岗位 | 「实质变化」,列出新增的岗位名 |
| 页脚版权年份、备案号、访问量、"最后更新"时间 | 「格式变动,不影响判断」,一句话带过 |
| 大段乱序、整页重排 | 「疑似改版」,说明比对结果不可靠,建议重新 add 建基线 |
- 要定时执行就配自动化:跟用户说清"每天几点看一次",用 WorkBuddy 的定时任务跑
check --quiet -o <每日报告>。--quiet只输出一行,没变化时不会刷屏;check的退出码 2 表示有变化、1 表示有失败、0 表示全部无变化,可以据此决定要不要打扰用户。 - 交付:报告文件路径 + 一句结论("3 个页面里 1 个变了,是价格从 99 改成 129")。用户没要文件时,直接把结论和那几行 diff 说清楚即可。
命令参考
W="$SKILL_DIR/scripts/watch.py"
# 1) 登记(必填:名字 和 网址)
python3 $W add "竞品A-价格页" "https://example.com/pricing"
# --match 正则 只看命中行,可重复:--match "元/月" --match "会员"
# --ignore 正则 忽略命中行,可重复:--ignore "版权|备案|浏览"
# --drop-noise 丢掉访问量/时间戳/"3分钟前"这类易变行
# --mask-time 把日期时间抹掉再比(比 --drop-noise 更温和,保留行本身)
# --timeout 25 单页超时秒数
# 2) 检查
python3 $W check # 全部
python3 $W check "竞品A-价格页" # 只查一个
python3 $W check -o ./盯梢报告/2026-10-27.md # 写 Markdown 报告
python3 $W check --quiet # 定时任务用:只打一行
# --context 2 差异上下各显示几行
# --delay 1.0 每页之间的停顿(默认 1 秒,别调太小)
# 3) 查看
python3 $W list
python3 $W show "竞品A-价格页" # 最近一份快照全文
python3 $W show "竞品A-价格页" --diff # 最近两份之间的差异
# 4) 删除
python3 $W rm "竞品A-价格页" # 只删登记,快照留着
python3 $W rm "竞品A-价格页" --purge # 连快照一起删
快照存放位置:~/.page-sentinel/(可用环境变量 PAGE_SENTINEL_HOME 改到别处)。每个盯梢项保留最近 30 份快照,更早的自动清掉。
示例
例 1:盯竞品价格
> 用户:帮我盯着这几个竞品的价格页,一改就告诉我,别整页都报
> →
> bash
> python3 $W add "竞品A-价格" "https://a.example.com/pricing" --match "元|¥|\$|月|年" --drop-noise
> python3 $W add "竞品B-价格" "https://b.example.com/plans" --match "元|¥|\$|月|年" --drop-noise
> python3 $W check
>
> 报告里出现 +专业版 249 元/月、-专业版 199 元/月 → 告诉用户「竞品A 专业版从 199 涨到 249,涨幅 25%,发布时间是本次检查前」。
例 2:盯政策/条款页
> 用户:这个平台的商家协议会不会偷偷改?帮我盯着
> →
> bash
> python3 $W add "平台-商家协议" "https://example.com/terms" --ignore "版权所有|ICP备|最后更新" --mask-time
>
> 条款页通常整篇都是有效内容,别用 --match 收窄(会漏掉新加的条款),改用 --ignore 排掉页脚。
例 3:盯招聘页新岗位
> 用户:看看他们还在招什么岗位
> →
> bash
> python3 $W add "竞品C-招聘" "https://c.example.com/jobs" --drop-noise
> python3 $W check
>
> 招聘页列表会增删,差异里 + 开头的行就是新挂出来的岗位,逐条念给用户。
边界(这些情况先说清,别硬做)
- JS 渲染的页面抓不到。脚本看到的是服务器返回的 HTML;靠浏览器执行 JavaScript 才有内容的页面(大量 SPA、部分电商详情页),抓下来几乎是空的。脚本会明确拒绝并提示,这时建议改用该站提供的 RSS、开放 API 或静态详情页。
- 要登录的页面不行。命令行没有用户的浏览器登录态。需要登录的页面会返回 401/403 或跳登录页,报告里会写清原因,不要反复重试,也不要尝试绕过。
- 不绕验证码、不伪装身份。默认串行抓取、每页间隔 1 秒,属于正常访问强度。用户若要求"高频刷"(几次/分钟),要提醒这对目标站不友好,且容易被封 IP。
- 不做全站爬取。这是"盯少数几个已知页面",不是爬虫。用户要抓整站列表,说明需求不匹配。
- 不替用户判断商业影响。能说"价格从 199 变 249",不替用户说"所以你该降价"。判断留给用户。
- 和"行业动态监控简报"分工:那个技能是找新内容(今天行业出了什么新闻);这个技能是盯老页面(已知的东西有没有被改)。用户说"最近有什么新消息"用前者,说"这个页面改了没"用后者。
注意事项
| 现象 | 原因与处理 |
|---|---|
刚 add 完第一次 check 就报变化 |
页面含每次访问都变的内容。加 --drop-noise,或用 --ignore "浏览\|在线人数\|库存" 排掉 |
| 每次都报同一段无意义差异 | 该段含随机推荐/广告。--ignore 那一段的关键词 |
| 报"正文抽取为空" | JS 渲染或需登录,见上文边界 |
| 报"HTTP 403/401" | 站点要求登录或拒绝脚本访问,放弃这个页面 |
| 报"Tunnel connection failed / 502" | 网络或代理问题。若用户机器走代理,确认目标站可达;内网地址脚本已自动不走代理 |
| 中文变成乱码 | 站点编码声明缺失。脚本已按 响应头 → meta → BOM 顺序尝试,若仍乱码,把网址反馈给维护者 |
| 想改盯的范围 | 不用重建。rm 掉再 add 一次即可,旧快照会保留,show --diff 仍可看历史 |
更细的排错见 @references/troubleshooting.md,各类页面的参数配方见 @references/watch-playbook.md。