5.3 实战:网页测试与内容监控 本节摘要:第三役把镜头从"一次任务"拉长到"天天要跑":每天巡检一组页面,核查关键要素在不在、价格文案变没变,变化落成记录、异常即时上报。本役的核心是把 3.3 的复核判定升级成"模型自评加程序比对"的双保险,并给出最小可用的巡检骨架。 背景:单次任务和巡检体系差在哪 第三役的需求来自测试与运营的交界:"上线前回归查一遍关键页,平时每天盯一遍竞品页。"单次巡检和一次提取任务的区别只有两个字:基准。监控的本质是"今天的结果和上次的记录比"——所以体系里有四个部件:巡检器(跑一次核查)、基准库(上次的快照)、比对器(程序化 diff)、上报器(有异常就喊人)。模型负责前半段(把页面现状取回来),后半段是纯程序的天下——这个分工就是双保险的落点。
本节摘要:第三役把镜头从"一次任务"拉长到"天天要跑":每天巡检一组页面,核查关键要素在不在、价格文案变没变,变化落成记录、异常即时上报。本役的核心是把 3.3 的复核判定升级成"模型自评加程序比对"的双保险,并给出最小可用的巡检骨架。
第三役的需求来自测试与运营的交界:"上线前回归查一遍关键页,平时每天盯一遍竞品页。"单次巡检和一次提取任务的区别只有两个字:基准。监控的本质是"今天的结果和上次的记录比"——所以体系里有四个部件:巡检器(跑一次核查)、基准库(上次的快照)、比对器(程序化 diff)、上报器(有异常就喊人)。模型负责前半段(把页面现状取回来),后半段是纯程序的天下——这个分工就是双保险的落点。

巡检器,一次核查多要素,字段合同管取证:
from pydantic import BaseModel from browser_use import Agent, Browser from langchain_openai import ChatOpenAI class 页面体检(BaseModel): 页面名: str 标题: str # 页面主标题现值 会员价: float | None = None # 有价格位就取,没有给空 报名按钮在: bool # 核心转化按钮是否存在可点 公告文案: str = "" # 顶部公告原文,监控用 llm = ChatOpenAI(model="gpt-4o", temperature=0) browser = Browser() 巡检单 = [ ("首页", "https://site.example.com/"), ("课程页", "https://site.example.com/course"), ("会员页", "https://site.example.com/vip"), ] def 巡一次(页面名, 地址): agent = Agent( task=( f"打开 {页面名}({地址}),如实记录页面主标题、" "会员价数字、报名按钮是否存在、顶部公告原文;" "只记录不做任何点击提交" ), llm=llm, browser=browser, structured_output=页面体检, ) return agent.run(max_steps=8)
比对器与上报器,纯 Python,不花一分模型钱:
import json, os BASE = "base.json" # 基准库:一个 JSON 文件起步够用 def 巡检一轮(): today = {} for 名, 地址 in 巡检单: r = 巡一次(名, 地址) today[名] = r.model_dump() # 模型产出转普通字典 if os.path.exists(BASE): with open(BASE, encoding="utf-8") as f: base = json.load(f) diffs = [] for 名, cur in today.items(): old = base.get(名, {}) for k in cur: if old.get(k) != cur[k] and cur[k] not in (None, ""): diffs.append((名, k, old.get(k), cur[k])) for 名, k, old, cur in diffs: print(f"[变更] {名} 的 {k}:{old} -> {cur}") if diffs: print("触发上报:推送值班群") # 上报接你的通知渠道 with open(BASE, "w", encoding="utf-8") as f: json.dump(today, f, ensure_ascii=False, indent=2)
预期输出(第二天运行,示意):
[变更] 会员页 的 会员价:299.0 -> 349.0 [变更] 会员页 的 公告文案:双十一延长 -> 年中促开启 触发上报:推送值班群
两行变更与一次上报,就是这套骨架的全部日常产出。三处设计值得点破:比对在程序不在模型——"有没有变化"是确定性判断,交给模型等于花钱买随机;模型只负责"如实取证",程序负责"和昨天比"。字段级 diff 而非整页 diff——公告文案变了不该惊动价格看门人,按字段比对让每条告警自带语义。基准库就是最简形态——一个 JSON 文件够用很久,等你需要看历史曲线再升级存储,别第一天就上数据库。
另外注意巡检单的失败语义:某页打不开时巡一次会异常退出——骨架里没做捕获,这是留给你的第一道练习。正确的姿势是 per 页 try、失败页记"巡检失败"也落进基准,让"页面打不开"本身成为一条告警。
变式一,回归测试:把巡检单换成发布前的验收页集合,字段合同换成验收标准(按钮文案、跳转地址),比对基准换成需求预期——巡检骨架原样变成回归工具,这是本役最值钱的迁移。变式二,定时触发:把巡检一轮挂进系统定时器,工作日早九晚六各一次,注意错开业务高峰。变式三,告警分级:价格类变更发紧急群、文案类发日报,在比对器里给字段配级别即可。变式四,快照留证:把模型取回的关键区域截图一并落盘(视觉模式顺路产出),追溯时证据链更硬。
三役打完,任务会越跑越多,问题也会越攒越厚——下一章进入边界与排错:红线画在哪、翻车怎么修。
巡检体系上线后第一个问题往往是告警太多没人看。两个旋钮控制告警疲劳:频率对齐变化速度——价格小时级变就小时巡,页面周级变就日巡,用变化速度反推巡检频率,别拍脑袋;分级投递——紧急变更进值班群,普通变更进日报,无变化不打扰任何人。判定一条告警的级别有个实用问法:"这条消息凌晨三点发到你手机上,你会起来处理吗?"会,就进紧急组;不会,就进日报。
第二个追问:**巡检本身怎么监控?**巡检器挂了谁喊人?最低配置是心跳日志——每轮巡检结束写一行"本轮 N 页,M 变更,耗时 T",值班侧盯这行日志的出现时间,超过两个周期没出现就是巡检器自身故障。监控者也需要被监控,这条规则没有例外。