让 Claude Code 替运营同事更新竞品监控表:46 个 Amazon / Walmart 链接的一个下午

运营同事有一张按系列分页的竞品监控表,每天要手工抄 44 个 Amazon / Walmart 链接的价格、星级、评论数。我在 1688 采集那个目录里让 Claude Code 用 Chrome DevTools MCP 一页一页读,75 分钟写回了 46 条数据。Amazon 一路顺,Walmart 卡在人机验证;事后核对发现运费没抓到、有一页只更新了一半。

让 Claude Code 替运营同事更新竞品监控表:46 个 Amazon / Walmart 链接的一个下午

去年 11 月 6 日下午,运营同事发来一张 Excel,叫"旺季待开发竞品监控表"。第一页是总清单,后面五页按系列分:200 MINI BIKE、EDB、Tuttio、125CC-140CC GDB、E MINI BIKE,一共 44 行链接,每行要维护售价、运费、coupon、星级、星级数量,最后一列总售价是个公式。这张表之前是人盯着 Amazon 和 Walmart 的商品页一行一行抄的。

前两天我刚在 C:\diaoY\01 这个目录里用 Claude Code 加 Chrome DevTools MCP 抓过 1688 的搜索列表(那是另一篇)。工具链现成,我就在同一个目录里把这张表丢给它。结果是:从下午三点零七分开始,到四点十九分写回最终文件,46 条数据进了表,Amazon 那边没什么波折,Walmart 的 8 条被"Robot or human?"卡了二十多分钟。写这篇的时候我重新打开那张表核对了一遍,还发现了几处当时没注意到的漏洞,一并写在后面。

用户的任务描述,以及 Claude 读出的表结构
图 1:任务就是一句话说清楚的。Claude 先用 openpyxl 把表读了一遍,认出 6 个标签页,第一页是总清单不用动。文件名里同事的名字打了码。

先读表,再写脚本

我给它的原话是:这个文件第一个标签页不是,后面几个标签页是需要爬取的产品的列表和链接以及旧的售价和星级等等信息,更新后写入回这个文件。

它先用 openpyxl 把工作簿读了一遍,列出 6 个 sheet,顺手指出日期列全是 2025-10-30,问我是不是测试数据。然后给了两个方案,我回了"用方案 1",也就是用 Chrome DevTools 一个页面一个页面打开。

它写了两个脚本。第一个 update_competitor_monitor.py 其实是个壳:里面有解析价格、星级、评论数的正则,有回写 Excel 和建备份的逻辑,但真正抓页面的函数是空的,注释写着"实际实现需要调用 Chrome DevTools"。这是 Claude Code 干活时常见的形态:能在 Python 里做的事放脚本里,需要浏览器的那一步留给 MCP 工具。

第二个 scrape_competitor_products.py 才是主干。它从第二个 sheet 开始逐行读型号、平台、链接、旧售价、旧星级,把 44 条导出成 urls_to_scrape.txt,抓到的结果存进 scraped_data.json,最后按链接把数据对回每一行,先存一份带时间戳的备份再覆盖原表。

选方案 1 之后,Claude 写出抓取脚本并加载了 44 个产品
图 2:脚本跑起来导出 44 条链接。终端里中文乱码是 Windows 控制台编码的老毛病,不影响文件内容。

真正读页面的是一段 JS

抓取本身不走 HTTP 请求,而是 Chrome DevTools MCP 控制一个真实的 Chrome:navigate_page 打开商品页,再用 evaluate_script 在页面里跑一段 JS。那段 JS 等两秒让页面渲染完,然后按选择器取字段:标题取 #productTitle,价格从 .a-price-whole、.a-offscreen 这一串候选里取第一个能解析出数字的,星级从 rating-out-of-text 的文本里正则出一个不超过 5 的数,评论数从 #acrCustomerReviewText 里取出来并去掉千分位逗号,库存看 #availability 的文字里有没有 unavailable。结果以 JSON 返回给 Claude。

第一条 Coleman B100 回来的是 $501、3.4 星、114 条评论。我后来手动开页面对了一下,对得上。

evaluate_script 里的抽取脚本和进度
图 3:抓到第 24 条时的终端。整段抽取 JS 就这么长,每个字段都准备了几个备选选择器,Amazon 改版的时候不至于全军覆没。
Amazon 商品页和叠在上面的 Claude Code 窗口
图 4:被自动化控制的 Chrome 开着 ABYANK 那条商品页,Claude 窗口里正往 scraped_data.json 追加记录。注意页面右侧写着 $89.99 运费,而 JSON 里 shipping 是 0,这一列这次根本没抓,后面会说。

44 个页面会把上下文吃光

一开始它一条一条来,每条抓完就往 scraped_data.json 里追加,并且每 5 条落盘一次。这个设计后来救了场:44 个页面快照塞进对话,上下文很快就不够了,截图里能看到"Context low (4% remaining)",整个下午 /compact 了三四次。每次压缩之后它都是靠 products_to_scrape.json、scraped_data.json 和一个算下一批的小脚本 batch_scrape_products.py 接着跑:按链接去重,找出还没抓的,取前 5 个。进度在文件里,不在对话里,这件事才能断点续跑。

第一条抓完后写入 scraped_data.json
图 5:第一条写进 JSON 的样子,以及"每 5 个保存一次进度"的决定。

Amazon 那 36 个链接大约三点四十五分抓完。中间只有一个小障碍,首次打开会弹地址选择框,JS 里顺手把它关掉了。

Walmart 的人机验证

轮到 Walmart 的 8 条,第一页就是"Robot or human?",要人按住一个按钮。Claude 检测到之后停下来提醒我去浏览器里按,这一点它做得对,但接下来的事它处理不了:一旦进入验证循环,按完还会再弹,必须把整个 Chrome 关掉重开。我当时在对话里是这么说的:沃尔玛的反爬机制是一旦进入到验证,即使一直按中间的按钮会重复让用户按这个按钮,必须重开整个 chrome。

重开之后换了个走法,从 Walmart 首页搜型号一步步点进详情页,后面几条就没再弹验证。8 条全部抓完是四点出头的事。

Walmart 页面弹出人机验证,Claude 提醒手动处理
图 6:Walmart 的验证页。这时 Amazon 36 条已经完成,上下文只剩 4%。
重开 Chrome 之后 Walmart 页面正常打开
图 7:重开浏览器后直接看到商品页,Walmart 进度 3/8。

我把这两条经验写进了项目里的 skill:第一次打开 Amazon、Walmart 这类网站可能触发真人验证,要提醒用户手动做;长任务做完必须先打开 Excel 核对,再把中间产生的一堆 xlsx 删掉。

写回和核对

最后的统计是 46 条,比表里的 44 行多 2 条,因为列表里有两个链接出现了两次;Amazon 38 条、Walmart 8 条。回写的时候四个 sheet 共 34 行全部写上了新日期和新数据,最终文件名带着时间戳,原表另存了备份。我随机开了几个页面对数:Coleman B100 的 $501 / 3.4 星 / 114 条,RiderX 的 $1,055 / 4.8 星 / 9 条,都对。

最终统计
图 8:收尾时的统计。四个 sheet、34 行,Tuttio 那一页不在这个列表里。

写这篇文章时我重新打开最终那份表,发现几件当时没看出来的事:

  • Tuttio 那一页有 10 行,只有 5 行的日期变成了 11 月 6 日,另外 5 行还停在 10 月 30 日。统计里说的"34/34"只覆盖了另外四页,这一页的数据抓到了,却没有完整写回去。
  • 运费和 coupon 两列在 JSON 里全是 0。Amazon 页面上明明印着 $89.99 的配送费,抽取脚本根本没取这个字段,表里保留的是原来的值。
  • 总售价那一列原本是公式,被更新的行写成了数字。

所以"34/34 成功更新"是真的,但不等于全表都对。这种事只有打开表一行行看才能发现,我后来把它写成了 skill 里的硬性收尾步骤。

整条流水线
图 9:这次的数据流。红框是需要人介入的环节,蓝框是让长任务能断点续跑的文件。

它适合什么规模

这套做法的本质是让一个真实浏览器替人翻页,速度大概一条两到四秒,加上等待和压缩上下文,44 条花了一个多小时,其中一半是 Walmart 的验证。几十到一两百条、一天跑一两次,是它舒服的区间。再往上就该换真正的无头方案,而且 Walmart 这种站点需要有人在旁边点验证,谈不上无人值守。

它和 1688 采集那篇用的是同一个目录、同一条 Chrome DevTools MCP 路径,区别在于那边是搜索列表页,要处理搜索框和翻页;这边是定向的详情页,链接已经在表里,难点变成了反爬、上下文和回写时的对行。

这张表后来有没有继续用这套流程更新,我没有留记录。脚本和 skill 都还在那个目录里。

← 上一篇 没有 U 盘,没有屏幕:在 WSL2 里给 AGX Thor 线刷系统的八次尝试 下一篇 → 一个分享"蓝图"的网站:7 月 5 日凌晨的构想,以及它停在了哪