首页 / 资讯中心 / 文章详情

AI驱动的浏览器自动化:用自然语言替代选择器,Stagehand实战解析

AI驱动的浏览器自动化:用自然语言替代选择器,Stagehand实战解析 ★ FEATURED ARTICLE
做网页自动化的朋友大概都有过这种体验写脚本两小时改选择器一整天。页面结构稍微换个class名整个流程就崩给你看。Stagehand这个项目我盯了挺久从它第一次在GitHub上放出预览版本就在用。简单说它把浏览器自动化从“写死每个点击坐标和选择器”拉到了“用自然语言描述你要干什么”的层次底层还是扎实的浏览器控制上层换了AI大脑来驱动。这东西能做什么一句话总结让大模型直接操作浏览器你只需要说“打开某网站搜索关键词把搜索结果整理成表格”它就能自己完成点击、输入、滚动、提取数据这一整套流程。它适合三类人搞自动化测试的、写爬虫和数据处理脚本的、以及正在做AI Agent相关原型的开发者。接下来我把实际使用中的设计思路、核心API、踩过的坑和落地建议一次说清楚。1. 先聊几个背景问题传统浏览器自动化到底卡在哪1.1 选择器地狱与脆弱的等待逻辑传统浏览器自动化最让人头疼的就是定位元素。用CSS选择器、XPath、ID这些老办法本质上是在跟页面的HTML结构较劲。今天开发把classbtn-primary改成classbtn-main你的脚本就得跟着改明天某个异步组件晚加载了300毫秒waitForSelector就超时。我经历过最夸张的一次一个脚本因为页面加了个广告位导致布局偏移点击坐标全部错位整套流程直接报废。后来才发现传统自动化框架的稳定性不是靠代码写得好而是靠页面结构“别乱动”。但现实是前端工程师不会为了你的爬虫而冻结页面。1.2 动态网页环境下脚本维护成本越来越高现在的主流网页早就不是静态HTML了。单页应用SPA盛行页面内容由JavaScript动态渲染一个按钮可能要等数据接口返回之后才出现在DOM里。再加上反爬虫策略、弹窗、登录态、懒加载传统脚本要处理的状态越来越多。每次写爬虫大量时间不是花在数据提取上而是花在“等页面出现某个元素”“判断某个操作是否成功”“处理偶尔冒出来的弹窗”这类环境适配工作。这些代码和业务逻辑毫无关系但它就是能吃掉你一半的开发时间。1.3 流程编排的笨重感传统方案里一个完整的操作流程要拆成几十个步骤每个步骤都要显式指定动作、等待条件、异常处理。如果是基本的“打开页面-点击-输入-提取”倒还好一旦碰到需要根据页面内容实时决策的场景比如“如果出现A就点A否则选B”脚本就会变得极其复杂充斥着各种if-else和状态判断。这套体系的问题在于它假设所有交互路径都是可预演的。但真实网页里一个登录弹窗、一个cookie授权条、一个随机推荐位都可能改变交互路径。传统脚本没法优雅应对这种不确定性只能打补丁补丁多了就又变成新的维护负担。2. Stagehand的核心设计把“操作步骤”换成“意图描述”2.1 三个核心APIact、extract、observeStagehand最直观的变化是暴露给开发者的API变成了一组高度语义化的方法act()用自然语言让浏览器执行操作比如“点击登录按钮”“在搜索框输入‘天气’并回车”。extract()从页面中提取结构化数据比如“获取当前页面上所有商品的价格和名称按列表返回”。observe()让模型先观察页面获取可交互元素的摘要帮助后续决策。这三个API对应了浏览器自动化最常用的三类动作操作、读取、决策。实际写起来代码长度能缩短到传统方案的五分之一甚至十分之一。import asyncio from stagehand import Stagehand async def main(): stagehand Stagehand() await stagehand.start() # 传统方式十几个步骤的选择器操作 # Stagehand方式一句话 await stagehand.act(在搜索框中输入编程书籍点击搜索按钮) # 提取结构化数据 books await stagehand.extract(列出当前页面上的所有书籍标题和价格以JSON数组返回) print(books) await stagehand.stop() asyncio.run(main())2.2 大模型如何“看懂”网页辅助功能树与指令编排这里有个关键问题大模型不能直接“看”HTML源码也不适合直接处理原始DOM。Stagehand的做法是借助浏览器的辅助功能树Accessibility Tree来感知页面。辅助功能树是浏览器为无障碍工具准备的页面信息结构它把DOM简化成“按钮”“输入框”“链接”等语义化节点去掉了布局、样式、无关包装元素。Stagehand将辅助功能树序列化连同用户指令一起交给大模型让模型在理解页面结构的基础上规划操作路径。这个设计很聪明。直接喂原始HTML给模型Token消耗巨大不说模型还经常被大量无意义的div、span干扰而辅助功能树天然就是给“外部程序理解界面”用的信息密度高噪音低。实测下来同一个页面用辅助功能树提取Token量可能只有原始HTML的五分之一决策准确率反而更高。2.3 和传统自动化框架的定位差异维度传统框架Playwright/SeleniumStagehand操作方式命令式精确指定每个动作意图式用自然语言描述目标元素定位CSS/XPath/文本匹配大模型根据页面结构自动决策异常处理开发者手工编写等待和判断模型在操作过程中动态调整维护成本页面结构改变需改脚本页面结构调整后可自适应脚本长度长细节全显式短重点在业务意图稳定性依赖页面结构和时序模型能力和页面可访问性需要说明的是Stagehand底层依然依赖Playwright来做浏览器控制它解决的是“决策层”的问题而不是重新发明了浏览器驱动。换句话说传统的定位方式并没有被抛弃而是由模型来生成和执行定位策略。3. 快速上手5分钟跑通第一个自然语言自动化任务3.1 环境准备与依赖安装Stagehand需要Python环境建议直接用虚拟环境隔离避免依赖冲突。安装过程很简单# 创建虚拟环境 python -m venv .venv source .venv/bin/activate # Windows下用 .venv\Scripts\activate # 安装Stagehand pip install stagehand安装完成后需要配置大模型接口。Stagehand默认接入了一套基于对话模型的推理方案需要准备API Key。也可以在初始化时指定自定义模型端点比如接入自己部署的开源模型服务把base_url和api_key替换成自己的配置就行。3.2 第一个Demo让浏览器自己找工作流我习惯用一个简单的“打开网页-搜索-点击进入详情页”流程来验证环境是否正常。import asyncio from stagehand import Stagehand async def main(): stagehand Stagehand( modelyour_model_config, api_keyyour_api_key, headlessFalse # 调试时建议打开浏览器窗口 ) await stagehand.start() await stagehand.page.goto(https://example.com) # 替换成实际测试网址 # 自然语言操作 await stagehand.act(在页面顶部的搜索框输入浏览器自动化) await stagehand.act(点击搜索按钮) await asyncio.sleep(3) # 提取搜索结果标题 results await stagehand.extract(列出页面上前5条搜索结果的标题返回字符串数组) for title in results: print(title) await stagehand.stop() asyncio.run(main())这段代码里page.goto还是传统的Playwright调用但后续操作已经全部换成自然语言。我实际跑下来的体感是页面结构越规范模型的表现越稳如果目标网站结构混乱建议先用observe()看一眼模型对页面的理解再决定下一步指令。3.3 配置参数里容易被忽略的细节初次使用容易忽略几个参数headless生产环境设为True无头模式但调试时一定要设成False否则看不到页面状态出了问题很难定位。timeout模型推理本身有延迟加上页面加载时间默认超时建议调大尤其你是通过慢网络访问目标站点时。model不同模型的工具调用能力差异很大。如果发现act()经常执行到一半就停下先怀疑是不是模型没有准确识别出需要操作的元素。有一个经验对模型来说“点击按钮”是不够的指令。按钮在页面上有多个时它不知道点哪个。把指令写得更具体——“点击页面右侧红色背景的‘提交’按钮”——成功率会高很多。4. 实战案例用Stagehand写一个完整的数据采集流程4.1 一个真实的整理需求之前有个需求从某个行业信息网站上抓取一批企业列表提取公司名称、所在城市、联系方式并翻页抓取前5页数据。用传统方式写光是处理翻页按钮和列表项的动态加载就够写两三百行。用Stagehand整个流程的编排就变得很流畅。这个场景的难点不在“抓数据”而在“页面结构不固定”。那个网站的列表页里企业卡片经常因为广告插入而变化传统选择器很容易失效。而Stagehand的重点放在了“描述这页有哪些企业”上。4.2 完整代码与执行过程拆解import asyncio import json from stagehand import Stagehand async def main(): stagehand Stagehand( modelyour_model_config, api_keyyour_api_key, headlessFalse ) await stagehand.start() await stagehand.page.goto(https://target-site.com/list) # 替换为目标网址 all_companies [] for page_num in range(1, 6): # 提取当前页的数据 page_data await stagehand.extract( 提取当前页面中所有企业卡片的公司名称、所在城市、联系电话 以JSON数组返回每个对象包含name、city、phone三个字段, modejson ) all_companies.extend(page_data) # 翻页操作 if page_num 5: await stagehand.act(f点击下一页按钮翻到第{page_num 1}页) await asyncio.sleep(2) # 等待数据加载 # 保存结果 with open(companies.json, w, encodingutf-8) as f: json.dump(all_companies, f, ensure_asciiFalse, indent2) print(f共抓取 {len(all_companies)} 条数据) await stagehand.stop() asyncio.run(main())执行过程中有几个细节值得注意。extract()模式设为json时模型会尽力按JSON格式输出这样后续处理数据非常方便但前提是指令里要明确字段名和返回结构否则模型自由发挥输出的格式你会很想哭。翻页操作里我没有指定具体的按钮选择器而是说“点击下一页按钮”Stagehand会自己去辅助功能树里找匹配的按钮。这里有一个安全性的考量如果页面上有多个“下一页”模型可能点错。稳妥的办法是指定更明确的文案比如“点击底部翻页区域标有‘下一页’字样的按钮”。4.3 成本与稳定性平衡的几个技巧实测下来Stagehand的Token消耗大头集中在extract()上因为需要把整个辅助功能树送给模型分析。控制成本的思路有几种减少extract()调用频率一页只需要提取一次数据不要反复调用。缩小提取范围如果只需要左侧列表的数据指令里明确写“只提取左侧列表范围内的公司卡片”模型会忽略无关区域Token消耗明显下降。用observe()做预筛选先让模型快速看一眼页面确认是否包含目标数据再决定是否执行extract()。这个做法适合页面经常变动的场景。稳定性方面翻页后一定要加等待时间。模型推理完成到浏览器真正执行动作中间有延迟如果翻页后立即提取数据可能还没渲染出来。我用asyncio.sleep(2)做简单等待实际项目里更建议用显式等待条件比如等某个文本出现后再继续。5. 踩坑实录那些文档里没写的坑与对策5.1 页面时序问题模型看懂了但元素还没加载完Stagehand最常见的问题就是时序。模型已经根据辅助功能树判断出“应该点击某个按钮”但实际点击时按钮还没渲染完毕结果就是操作失败或点到了错误位置。这个问题本质上是模型不具备等待能力它只负责“决策”不负责“保证执行时刻页面就绪”。解决思路有两种一是你在指令中加入等待条件比如act(等待页面上出现加载完成字样然后点击提交按钮)二是在关键操作前用observe()确认页面状态再执行后续动作。5.2 辅助功能树解析失败页面像一堵墙有些网站做了严格的无障碍信息隐藏或者整个页面就是Canvas渲染的辅助功能树几乎提取不到有效信息。这种情况下Stagehand就像盲人摸象模型即使再聪明也无从下手。我遇到过一个纯Canvas的图表页面整个界面在辅助功能树里几乎空白。当时用的是退路方案对这类特殊页面还是回到传统方式写选择器或者用图像识别做补充。Stagehand不是万能药它的发挥空间依赖页面提供可用语义信息这一前提。5.3 模型幻觉导致的误操作乱点一气大模型偶尔会“脑补”不存在的元素。明明页面上没有“登录”按钮模型却可能告诉你已经点击了登录。这个问题在复杂页面上更容易出现尤其是当辅助功能树信息过于庞大模型漏掉了一些关键节点。一个实用的对策在act()之后紧接着做一次验证。我通常会在关键操作后用extract(当前页面上是否出现了XX内容返回布尔值)来确认操作是否真的生效。这样虽然多一次模型调用但能避免后续流程白跑。5.4 Token开销飙升的排查与削减模型调用的Token消耗是个隐形成本。我见过有人跑一个简单的采集流程一次执行烧掉了十万Token原因就是指令写得太模糊模型反复失败重试。排查方法是打开调用日志看每次act()和extract()的输入输出长度。输入过长通常是辅助功能树太大了可以在指令中限定分析范围输出过长则往往是因为模型把无关内容也提取了出来。削减指令中的模糊表述明确“只返回...的数据”能显著降低Token消耗。6. 从Demo到生产适用场景与架构建议6.1 哪些场景适合用Stagehand结合实战经验我认为这几个方向最能发挥AI驱动自动化的优势端到端测试测试用例从固定选择器变成业务语言描述页面改版时测试脚本的维护量大幅下降。数据采集与监测目标页面结构经常调整用自然语言描述“提取什么”而不是“从哪个XPath提取”长期维护成本更低。AI Agent浏览器操作构建能自主浏览网页、检索信息、填写表单的Agent原型Stagehand提供了天然的操作接口。内部工具与自动化流程处理报销系统、OA系统这类老旧但结构稳定的内部网页比传统脚本省事。6.2 不适合的领域趁早绕道大规模高并发采集模型推理延迟和成本都不适合超大并发场景这类需求还是用传统方案更实在。实时性要求极高的自动化模型决策要几百毫秒到几秒不等远慢于直接执行脚本。页面完全不可语义化纯图像渲染或强反自动化保护的站点AI驱动反而被封印。6.3 生产落地的架构建议如果要把Stagehand部署到生产环境我的建议是加一层任务编排。任务队列把每个自动化任务封装成独立任务放入队列顺序执行避免模型请求并发过高导致成本失控。失败重试与降级模型失败不等于任务失败设计好重试策略。连续失败多次时降级到传统方案兜底。结果缓存observe()的输出和extract()的结果可以缓存页面没变化时直接复用能省不少Token。监控模型成本给每个任务记录Token消耗与成功率这样才能知道哪些页面值得用Stagehand、哪些页面不划算。我自己在跑一个定时采集任务时就是把这些任务挂在队列里失败自动重试两次然后每天看一次成功率变化曲线。这种方式的运维成本比传统脚本维护低得多页面改版后经常是不动任何代码模型自己就适应了。7. 写在最后一点心得刚上手Stagehand那会儿我一度觉得这玩意儿太“玄学”——同样的指令有时候一次成功有时候要折腾好几次。后来想明白了它本质上不是“脚本”而是一个“会用浏览器的智能体”你写得越清楚它干得越利落。如果你打算认真用起来我的建议是先别急着替换所有现有脚本。挑一两个页面结构相对稳定的流程跑通之后感受一下维护成本的变化再逐步扩大范围。另外多花点时间打磨你的自然语言指令指令的清晰度和边界描述对结果的影响比模型本身还大。这门技术还在快速迭代但方向已经很明确了浏览器自动化正在从“代码控制”走向“意图驱动”Stagehand只是这条路上走得比较远的一个开源项目而已。
阅读完成 · 觉得有帮助?
咨询建站