放弃像素对比,我用 MCP 实现了真正结构化的竞品定价监控
最开始我走的是最传统的路:写 Python 脚本配合 Cron Job 定时抓取,然后用 BeautifulSoup 写 Parser。这在监控竞品 Blog 或者 Changelog 时还算好用,因为这些页面的 HTML 结构相对稳定。但一旦涉及到 Pricing Page(定价页),这套逻辑就彻底崩了。每个站点的 DOM 结构乱七八糟,有的用 div 嵌套,有的用 table,甚至有的价格是通过 JS 异步加载的。我尝试写一套通用逻辑去适配所有站点,结果发现解析率低得离谱,只要对方稍微改一下 CSS 类名,我的 Parser 就会直接报错。
后来我尝试走“暴力路线”,直接把整个页面的 HTML 源码塞给 LLM,让它帮我提取价格。结果发现这不仅贵,而且极其不稳定。最头疼的是 LLM 的输出格式随机性太强,同样的输入,这次返回 JSON,下次可能返回一段 Markdown 表格,典型的 Garbage in, Garbage out,根本没法直接对接下游的数据库。
甚至我也试过 Visualping 这种成熟的商业工具,但它本质上是像素级比对。这导致我每天会被推送大量毫无意义的通知,比如对方改了一个按钮的圆角、更新了一个 Cookie Banner 的颜色,或者某个 CSS 边框变了 1px,这些在像素比对看来都是“变化”,但对我来说全是噪音。
为了彻底解决这个问题,我花了一个月时间重构了逻辑,核心思路是:放弃原始像素比对 → 强制提取结构化字段 → 仅对字段值进行 Diff。
目前的实操流程是这样的:
首先,输入竞品首页 URL,通过一套预设的路径探测逻辑,自动寻找 /pricing、/docs、/blog 或 /changelog 等关键页面。
其次,在定时抓取阶段,我加入了一层噪音过滤机制。在将内容交给 LLM 处理前,先用正则和简单的 DOM 过滤剔除掉所有 Cookie Banner、弹窗提示以及页脚的版权信息。
最后,将提取出的结构化字段(如 plan_name、price、features)存储在本地。只有当这些具体数值或文本发生变化时,才会触发推送摘要。
为了进一步提升效率,我给这套逻辑写了一个 MCP server。这个改动非常关键,因为之前我需要频繁在浏览器和编辑器之间切换,现在我直接在 Cursor 内部调用这个 Tool。当我正在编写功能代码,需要参考竞品最近是否更新了某个 API 或调整了定价策略时,直接在 Chat 窗口问一句,MCP server 就会实时调用监控数据并返回结果,极大地减少了上下文切换的成本。
如果你也在构建类似的 AI Agent 工作流,可以参考我目前的配置逻辑:
{
"monitor_config": {
"target": "competitor_url",
"fields": ["plan_name", "price", "features"],
"noise_filter": ["css_changes", "cookie_banners"],
"alert_trigger": "field_value_diff"
}
}当然,这套方案目前依然存在一些 Edge Cases。最核心的痛点在于不同网站的反爬策略(比如 Cloudflare 的验证)以及极端的 DOM 结构变动,偶尔还是会干扰提取精度。但我认为,从“监控像素”转向“监控数据字段”,才是自动化竞品分析的正确方向。