月底的周五下午,老李盯着屏幕上那张竞品价格监控表,脸比窗外的乌云还黑。二十个竞品网站,每个要找到产品页面、记录价格、截图存档,两天时间全耗在这上面。他正把保温杯往嘴边送,突然看见小王对着屏幕咧嘴笑。
“笑什么呢?还不帮我整理报价单?”老李没好气。
“老李,我刚让 Agent 帮你把竞品价格全爬下来了,连截图都存好了。”小王把笔记本转过来,一个漂亮的表格赫然在目,最后一列是整齐的价格截图缩略图。
老李差点把枸杞喷出来:“你让 AI 去点网页?你不怕它手滑把我们产品全买了?还是用爬虫写的?”
“不是爬虫。就是让 AI 像人一样打开浏览器,一页一页看,找到价格,复制下来,还知道避开‘立即购买’按钮。它全程录屏,你要不要看回放?”
老李放下杯子,将信将疑地凑了过去。
浏览器 Agent 是怎么“看”网页的?
小王打开一段录屏:浏览器自动打开竞品 A 的官网,鼠标指针在页面上缓缓移动,停在“产品”导航栏上,精准点击,进入列表页,逐一滚动,找到价格元素,高亮、截图、记录。整个过程像一个看不见的手在操作。
“这后面是 Playwright 驱动浏览器,再加上一个视觉理解模型。”小王敲了几下键盘,调出架构图。
“传统爬虫靠 HTML 标签定位,但网站一改版,爬虫就抓瞎。浏览器 Agent 不一样——它真‘看’页面截图,用视觉模型理解内容。‘价格通常在 ¥ 符号附近’‘立即购买按钮通常是橙色大按钮’,这些人类靠视觉判断的东西,Agent 也能学会。”
图:浏览器 Agent 的感知-行动循环——视觉理解 + 自动化操作
元素定位:点哪里,怎么点?
“那它怎么知道这个按钮是‘产品’而不是‘关于我们’?”老李指着录屏问。
“三种定位方式,按优先级来。”小王掰着手指。
第一,语义定位。 视觉模型看完截图后,用自然语言描述目标元素:“页面顶部导航栏中,从左数第二个链接,写着‘产品中心’。” Agent 再调用 Playwright 通过文本或角色定位。它不是说“点坐标(300, 50)”,而是说“点那个写着‘产品中心’的链接”,即使页面布局变了也能自适应。
第二,CSS 选择器回退。 如果视觉模型找不到,它会去翻源码,用 .nav > li:nth-child(2) > a 这种标准选择器。这是传统爬虫的看家本领,作为保底。
第三,坐标兜底。 前两招都不行?那就真的算坐标。视觉模型输出元素在截图中的相对位置,换算成页面绝对坐标点击。这最像人类“看着点”,也最容易因为分辨率变化而出错。
“三种方式结合,准确率就上去了。而且 Agent 操作前会先 hover 过去高亮,确认对了才点击,点错了还能回退——比你当年手滑删库靠谱多了。”小王笑道。
老李白了他一眼。
操作序列规划:从开网页到下单,要几步?
“就算能点按钮,那它怎么知道先点哪个后点哪个?抓价格可不是一步操作。”
“这就用上我们上次聊的任务分解了。”小王打开 Agent 的执行日志,是一系列 Thought 和 Action。
[Thought] 用户要求获取产品 X 的今日售价。我需要:1. 打开网站 2. 搜索产品 3. 进入详情页 4. 找到价格元素 5. 记录。
[Action] goto("https://example.com")
[Observation] 页面加载完成。
[Thought] 首页已打开,顶部有搜索框。我需要点击搜索框输入产品名称。
[Action] click("搜索框", method="semantic")
[Action] type("产品X")
[Action] press("Enter")
...小王解释道:“浏览器 Agent 内部用的是 ReAct 循环。但它多了一个‘观察’维度——每次操作后的页面截图变化。它不会盲目执行预先写好的步骤,而是根据当前页面状态动态调整。比如搜索后跳到了促销页,它会自己判断‘这不是详情页,需要再点一次’。”
老李若有所思:“这不就是给人写操作手册吗?‘打开网站,搜索产品,点进去,找价格’——只不过看手册的是 AI。”
“对!你给它的指令就是一份高级操作手册,它自己拆成具体动作。”
错误恢复:弹窗、加载慢、验证码
“那网页弹了个广告怎么办?或者突然要登录?”老李的担忧一个接一个。
“这就是浏览器 Agent 最考验工程能力的地方。它有一整套异常处理策略。”
小王在代码里演示了安全回退:
# 浏览器 Agent 的安全操作包装(示意)
def safe_click(agent, element_desc, max_retries=3):
for attempt in range(max_retries):
try:
# 执行点击,并等待页面稳定
agent.click(element_desc)
agent.wait_for_load_state("networkidle", timeout=5000)
return True
except TimeoutError:
# 可能弹窗拦截,尝试关闭弹窗
if agent.visible("弹窗关闭按钮"):
agent.click("弹窗关闭按钮")
continue
except Exception:
# 遇到意外,截图并暂停等待人工指示
agent.screenshot(f"error_{attempt}.png")
if attempt == max_retries - 1:
return False“遇到弹窗,Agent 会优先找关闭按钮;遇到登录墙,它会暂停并通知你‘需要人工登录’;如果同一个操作失败三次,就放弃这个网站,记录异常,接着跑下一个。绝对不会在同一个坑里死循环。”
老李追问:“验证码呢?”
“目前所有浏览器 Agent 的阿克琉斯之踵。遇到图片验证码,Agent 会自动截图保存,然后暂停,等你人工识别一次。识别过一次后,它会把这段操作录下来,下次遇到类似情况可以回放。但完全自动绕过验证码——现在还没有安全又合法的方案。”
安全模式:防手滑的最后防线
老李最担心的还是那个问题:“你怎么保证它不会点‘购买’?万一它真下单了怎么办?”
小王点开 Agent 的安全配置,里面列着几条铁律。
“第一,视觉黑名单。模型训练时学会了识别‘立即购买’‘提交订单’‘确认支付’这些高危按钮,Agent 在任何页面都不会点击它们。第二,操作拦截。Playwright 层面拦截所有包含 buy、checkout、payment 的 HTTP 请求。第三,金额阈值。只要页面包含 ¥ 符号且后面跟着大于 0 的数字,Agent 会暂停并请求人工确认。”
# 浏览器 Agent 安全配置示例
SAFETY_RULES = {
"forbidden_text": ["立即购买", "提交订单", "确认支付", "删除"],
"forbidden_urls": ["*/checkout", "*/payment", "*/delete"],
"require_approval_on": {
"amount_detected": True, # 页面包含金额时暂停
"form_submit": True, # 提交任何表单前暂停
"redirect_external": True # 跳转到外部域名前暂停
},
"read_only_mode": True # 全局只读,禁止任何修改操作
}“如果你把它设为‘只读模式’,它连表单都不会填,只能获取文本和截图。你那个竞品价格抓取,跑的就是只读模式,绝对安全。”
老李终于放心了,但又问:“那帮我抢特价机票是怎么回事?”
小王眨眨眼:“抢票用的是写模式,但我开了操作日志和二次确认。它选好航班后会截图发给我,我点一下‘确认’它才下单。等于我才是最后拍板的人,它只是帮我填了信息、选了座。”
从竞品抓取到政府申报
老李指着那份已经填好的竞品价格表:“这个表,以后每个月自动跑一次?”
“可以。我已经把配置写成了定时任务,每个月一号凌晨自动执行,早上你就能在邮箱里看到新报表。”
老李沉默了一会儿,又想起一件事:“上周行政说有个政府补贴申报,要在政务网上填一堆表格,格式复杂得要命,能搞定不?”
小王打开另一个测试记录:“已经跑通了。Agent 先读取咱们公司的基本信息文件,然后打开申报网站,一页一页填表,遇到不清楚的字段会暂停,问你‘社保编号填哪个’。填完后生成预览截图让你确认,你点一下‘提交’,它才点提交。”
老李靠在椅背上,拧开保温杯,喝了一口已经微凉的枸杞水。
“嗯……还有点意思。以前我总觉得 AI 只能聊天写诗,没想到它真能干活。”
“老李,你这就是认可了?”
“我没说认可。我是说——下不为例啊。以后有这种机械重复的网页操作,先让 Agent 试,别再让我手动点两天了。”
他站起来走到门口,又折回来:“那什么,你刚才说它视觉理解用的是截图,那如果网页有动画、或者价格是用 Canvas 画的,它还能认出来吗?那个视觉模型是通用的还是专门训练过识别网页元素的?给我看看你的 prompt。”
小王笑着把调试界面的截图调出来,老李端着保温杯,又拉了把椅子坐下。窗外已是黄昏,竞品价格表静静地躺在共享文件夹里,第一次没有带着老李的怨气。

