OpenClaw 自动化能力实践:用 agent-browser 与 Playwright 搭建可复现的浏览器任务流 1. 从一次“抓不到数据”的崩溃说起浏览器自动化到底难在哪先说个真实场景。我让 OpenClaw 去抓一个用 Vue 写的商品列表页它返回的 HTML 里只有一行div idapp/div数据全在 JavaScript 渲染之后才出现。换成无头浏览器页面是出来了但目标站点识别出 Headless 特征直接弹了个滑块验证。那一刻我才意识到浏览器自动化不是“装个 Playwright 就完事”而是一整套从任务定义、浏览器控制、凭证管理到结果验证的链路工程。OpenClaw 的自动化能力本质上是在解决“让 AI 像人一样操作浏览器”这件事。它把浏览器自动化拆成了几个可组合的层级L0 是纯搜索加抓取不碰浏览器L1 是无头浏览器适合 JS 渲染页面L2 是有头浏览器加 DOM 操作能登录、填表单、点按钮L3 是截图加视觉识别兜底处理图片里的信息。这套分级思路很实用因为日常任务里 80% 的信息获取其实 L0 就够了没必要每次都启动一个完整浏览器。而 agent-browser 是 OpenClaw 在 L2/L3 层的核心组件。它底层基于 CDPChrome DevTools Protocol加 Playwright。Playwright 负责跨浏览器的自动化 APICDP 负责跟 Chrome 实例通信。两者结合之后OpenClaw 可以打开一个独立的 Chromium 实例用独立的 profile 隔离然后通过 DOM 快照理解页面结构再执行点击、输入、滚动这些动作。这篇文章要解决的核心问题是怎么把这条链路搭成可复现的任务流。不是“演示一下能跑”而是你照着配置片段和验证命令在自己的环境里能稳定复现。同时我会说明怎么用统一的 Key/API 通道管理调用凭证避免每个工具各配一套密钥、最后自己都记不清哪个 key 对应哪个服务。适合谁看如果你已经在用 OpenClaw但浏览器任务总是时好时坏或者你正准备把某个重复的网页操作交给 AI却卡在环境配置和验证环节那这篇就是写给你的。我会从任务定义开始一步步走到执行验证中间踩过的坑也会标出来。2. TaoToken 前置统一 Key/API 通道与 agent-browser 的凭证管理在讲具体配置之前得先把凭证这件事理清楚。浏览器自动化任务里OpenClaw 需要调用的外部服务不止一个搜索 API、网页读取 API、大模型推理 API可能还有视觉识别 API。如果每个服务都单独申请 key、单独配置很快就会变成一团乱麻。更麻烦的是当你想换一个模型或者调整调用配额时得翻好几个配置文件。TaoToken 在这里的角色是提供一个统一的 API 通道。你可以把它理解成一个“凭证中转站”OpenClaw 和 agent-browser 只需要认一个 Base URL 和一个 Key背后具体调用哪个模型、哪个搜索服务由通道来路由。这样做的好处很直接——配置集中、切换成本低、排查问题时只需要看一个入口。先明确几个地址后面配置里会反复用到官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endAPI 基础地址https://taotoken.net/api模型对话入口https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewriteCoding Plan 入口https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteClaude Code 接入https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_codeutm_campaignrewrite注意API 地址https://taotoken.net/api后面不加 UTM 参数这是给程序调用的加了反而可能影响请求解析。带 UTM 的那些链接是给人点的用于归因统计。现在说 agent-browser 这边怎么接。OpenClaw 的浏览器控制本身不直接依赖外部 API它用的是本地 CDP 端口。但浏览器任务里经常需要“让模型理解页面快照”或者“让视觉模型识别截图”这些推理请求就要走统一通道。所以配置分两块一块是 OpenClaw 的模型 provider 配置一块是 agent-browser 的浏览器 profile 配置。模型 provider 这块OpenClaw 支持自定义 OpenAI 兼容接口。你需要在配置文件里指定baseURL为https://taotoken.net/apiapiKey填你在控制台生成的 keymodel填你要用的模型 ID。这样 OpenClaw 在需要推理时请求会先到 TaoToken再由它转发到实际模型。好处是你不用在 OpenClaw 里存多个厂商的 key换模型也只改一个model字段。浏览器 profile 这块agent-browser 默认用openclaw这个隔离 profile不会碰你日常用的 Chrome 数据。这个设计很关键因为自动化任务经常要登录各种站点如果跟你自己的浏览器混在一起cookie 和会话会互相污染。独立 profile 意味着 OpenClaw 有自己的一套 cookie 和缓存你手动登录一次之后后续任务可以复用。还有一个容易忽略的点如果你用的是云主机跑 OpenClaw默认没有桌面环境agent-browser 启动有头浏览器时会失败。这时候要么装桌面环境加远程桌面要么改用无头模式。这个后面排障章节会细说。凭证管理上我的建议是所有需要 key 的地方都指向 TaoToken 的同一个 key。包括 OpenClaw 的模型调用、搜索 skill 的 API 调用、视觉识别调用。这样你只需要在一个地方轮换 key不用逐个服务去改。控制台的 API Keys 页面可以生成和管理这些 key接入文档里有各语言的调用示例。3. 可复制配置agent-browser 与 Playwright 的任务流搭建这一章是核心操作部分。我会给出完整的配置片段包括 OpenClaw 的模型 provider 配置、agent-browser 的浏览器 profile 配置、以及一个可复现的浏览器任务定义。你照着改路径和 key 就能跑。先看 OpenClaw 的主配置文件。通常位于~/.openclaw/openclaw.json如果你用的是项目级配置也可能在项目根目录的.openclaw/config.json。下面是一个最小可用的配置片段重点是providers和browser两块{ providers: { default: { type: openai-compatible, baseURL: https://taotoken.net/api, apiKey: sk-your-taotoken-key, model: your-model-id, timeout: 60000 } }, browser: { defaultProfile: openclaw, cdpPort: 18998, headless: false, profiles: { openclaw: { color: #FF4500, isolated: true, userDataDir: ~/.openclaw/browser-profiles/openclaw }, work: { color: #3b82f6, isolated: true, userDataDir: ~/.openclaw/browser-profiles/work } } }, skills: { scrapling-web-scraper: { enabled: true, path: ~/.openclaw/skills/scrapling-skill, config: { stealth_mode: true, solve_cloudflare: true, proxy_rotation: auto } } } }这里有几个参数需要解释。baseURL指向 TaoToken 的 API 地址apiKey换成你在控制台生成的 keymodel填你要用的模型 ID。browser.defaultProfile设为openclaw表示默认用隔离 profile。cdpPort是 CDP 调试端口agent-browser 通过这个端口跟 Chromium 实例通信。headless设为false表示有头模式你能看到浏览器界面方便调试生产环境可以改true。profiles里我配了两个openclaw用于日常自动化任务work用于需要单独登录态的任务。每个 profile 有独立的userDataDircookie 和缓存互不干扰。color是浏览器窗口的标识色多 profile 同时开的时候方便区分。接下来是 agent-browser 的启动和任务定义。OpenClaw 提供了 browser CLI你可以先用命令行验证浏览器能不能正常启动# 查看浏览器状态 openclaw browser status # 启动默认 profile 的浏览器 openclaw browser start # 打开一个页面 openclaw browser open https://example.com # 获取页面快照用于 AI 理解结构 openclaw browser snapshot --format aria # 截图 openclaw browser screenshotsnapshot --format aria这个命令很关键。它返回的是页面的无障碍树结构比原始 HTML 干净得多模型读起来更省 token也更容易定位到可交互元素。agent-browser 在执行点击、输入之前通常会先拿一次快照确认目标元素存在再执行动作。如果你需要控制自己正在用的 Chrome 标签页而不是独立实例可以用userprofile 加 Chrome 扩展的方式。先安装扩展openclaw browser extension install openclaw browser extension path然后打开 Chrome访问chrome://extensions启用开发者模式点“加载已解压的扩展程序”选择上面命令打印的目录。加载后把扩展固定到工具栏。这样 OpenClaw 就能通过扩展中继控制你当前的标签页。不过这种方式适合过渡期使用长期跑自动化任务还是建议用独立 profile避免跟你自己的浏览行为冲突。现在定义一个可复现的浏览器任务。假设我们要抓取一个需要登录才能看到的订单列表页任务分三步打开登录页、填入凭证、跳转到订单页并提取数据。在 OpenClaw 里可以用一个 skill 或者一段任务描述来定义。下面是一个任务定义的 JSON 片段{ task: fetch-order-list, steps: [ { action: browser.open, params: { url: https://example.com/login, profile: openclaw } }, { action: browser.snapshot, params: { format: aria } }, { action: browser.type, params: { selector: input[nameusername], text: ${USERNAME} } }, { action: browser.type, params: { selector: input[namepassword], text: ${PASSWORD} } }, { action: browser.click, params: { selector: button[typesubmit] } }, { action: browser.wait, params: { selector: .order-list, timeout: 15000 } }, { action: browser.extract, params: { selector: .order-item, fields: [orderId, amount, status] } } ] }这个任务流里${USERNAME}和${PASSWORD}是环境变量占位符实际执行时从环境变量注入避免明文写在配置里。browser.wait等待订单列表容器出现超时 15 秒这是处理异步加载的关键步骤。browser.extract按选择器提取字段返回结构化数据。如果你用 Playwright 直接写脚本而不是走 OpenClaw 的 skill 体系也可以。Playwright 的 Python 版本大概是这样from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch( headlessFalse, args[--remote-debugging-port18998] ) context browser.new_context( user_data_dir~/.openclaw/browser-profiles/openclaw ) page context.new_page() page.goto(https://example.com/login) page.fill(input[nameusername], your-username) page.fill(input[namepassword], your-password) page.click(button[typesubmit]) page.wait_for_selector(.order-list, timeout15000) items page.query_selector_all(.order-item) for item in items: print(item.inner_text()) browser.close()注意--remote-debugging-port18998这个参数它让 Playwright 启动的 Chromium 暴露 CDP 端口这样 OpenClaw 的 agent-browser 也能连上同一个实例。user_data_dir指向跟 OpenClaw 配置里一致的 profile 目录保证登录态复用。配置写完之后先别急着跑完整任务。用openclaw browser status确认浏览器状态再用openclaw browser open打开目标页面手动确认页面能正常加载。这一步能排除掉大部分网络和证书问题。4. 验证请求与成功结果从快照到数据落盘配置写完只是第一步真正重要的是验证。浏览器自动化最怕的是“看起来跑了但结果是错的”。所以这一章讲怎么一步步验证每一步都有明确的预期输出。第一步验证模型通道是否通。在 OpenClaw 里发一个最简单的推理请求确认baseURL和apiKey配置正确curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-your-taotoken-key \ -H Content-Type: application/json \ -d { model: your-model-id, messages: [{role: user, content: reply with ok}], max_tokens: 10 }预期返回是一个 JSONchoices[0].message.content里包含ok。如果返回 401说明 key 不对如果返回 404说明model字段填的模型 ID 不存在如果连接超时检查网络能不能访问taotoken.net。这一步过了说明凭证通道没问题。第二步验证浏览器能启动并暴露 CDP 端口。运行openclaw browser start openclaw browser status预期输出里running: truecdpPort: 18998cdpUrl: http://127.0.0.1:18998。如果running: false看日志里有没有 Chromium 启动失败的报错。常见原因是userDataDir路径不存在或者没有写权限手动mkdir -p一下对应目录就行。第三步验证页面快照能拿到。打开一个测试页面拿一次 aria 快照openclaw browser open https://example.com openclaw browser snapshot --format aria预期输出是一段结构化的文本包含页面的标题、链接、按钮等元素。如果输出为空可能是页面还没加载完加一个--wait-until networkidle参数或者先openclaw browser wait --selector body再拿快照。第四步跑一个完整的提取任务验证数据能落盘。用前面定义的fetch-order-list任务执行后检查输出openclaw run fetch-order-list --env USERNAMEyour-user --env PASSWORDyour-pass预期输出是一个 JSON 数组每个元素包含orderId、amount、status三个字段。如果返回空数组先确认.order-item这个选择器在快照里存在如果报超时把browser.wait的timeout调大或者检查登录是否成功——登录失败的话订单页会跳回登录页自然等不到.order-list。第五步验证截图和视觉识别链路。有些信息只在图片里比如验证码或者图表。用截图命令拿到图片再走视觉模型识别openclaw browser screenshot --output /tmp/page.png然后调用视觉模型把图片 base64 编码后发给 TaoToken 的 APIbase64 -w 0 /tmp/page.png /tmp/page.b64 curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-your-taotoken-key \ -H Content-Type: application/json \ -d { model: your-vision-model-id, messages: [{ role: user, content: [ {type: text, text: 描述这张图片里的主要内容}, {type: image_url, image_url: {url: data:image/png;base64,$(cat /tmp/page.b64)}} ] }] }预期返回是对图片内容的文字描述。这一步验证的是 L3 兜底能力速度比 DOM 操作慢但能处理 DOM 拿不到的信息。我实测下来这套验证流程走一遍大概十分钟但能省掉后面几个小时的瞎猜。关键是每一步都有明确的成功标准哪一步挂了就查哪一步不用从头怀疑。还有一个验证技巧把每次任务的快照和提取结果都存一份到本地按时间戳命名。这样当结果不对时可以回看当时的页面结构判断是选择器变了还是页面逻辑变了。OpenClaw 的日志目录通常在~/.openclaw/logs可以配合jq过滤出浏览器相关的条目。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一章列几个真实会遇到的报错以及对应的排查路径。这些报错我在不同环境里都踩过按这个顺序查基本能定位。401 Unauthorized。这个最直接就是 key 不对或者没带上。先确认openclaw.json里的apiKey跟控制台生成的一致注意有没有多余空格。然后确认请求头是Authorization: Bearer sk-xxx格式不是x-api-key或者其他。如果你用的是环境变量注入检查变量名有没有拼错echo $TAOTOKEN_API_KEY看一下值对不对。还有一种情况是 key 被轮换了但配置没更新去控制台的 API Keys 页面确认当前有效的 key。local proxy failed。这个报错通常出现在 agent-browser 启动浏览器的时候提示本地代理连接失败。原因是 OpenClaw 配置里可能残留了代理设置或者系统环境变量里有HTTP_PROXY、HTTPS_PROXY指向了一个不可用的地址。排查方法先env | grep -i proxy看有没有代理变量有的话临时unset掉再启动。然后检查openclaw.json里有没有proxy字段有的话删掉或者改成正确的地址。注意这里说的是本地网络配置问题不是让你去用什么特殊网络工具只是把错误的代理配置清理掉。reading choices 报错。这个通常出现在模型返回格式不符合预期的时候比如choices字段为空或者结构不对。先确认你调的模型 ID 是 chat 类型的不是 embedding 或者别的类型。然后看返回的原始 JSONcurl命令加-v看完整响应。如果返回的是错误信息而不是choices那错误信息里通常有具体原因比如model not found或者insufficient quota。还有一种情况是流式返回没处理完就解析了检查你的客户端有没有正确处理stream: true的响应。OAuth 相关报错。如果你用 Claude Code 或者某些需要 OAuth 授权的工具接入可能会遇到 token 过期或者 scope 不对的问题。Claude Code 接入 TaoToken 的配置方式跟普通 API key 不同需要走https://taotoken.net/claude-code-anthropic这个入口的说明。常见错误是invalid_grant表示授权码已经用过或者过期了重新走一遍授权流程。如果是invalid_scope检查你申请的权限范围跟实际调用的是否匹配。浏览器启动失败但没明显报错。这种情况先看~/.openclaw/logs/browser.log里面通常有 Chromium 的 stderr 输出。常见原因userDataDir被另一个进程占用比如你已经开了一个同 profile 的浏览器杀掉进程或者换个 profile磁盘空间不足Chromium 启动需要写临时文件缺少系统依赖库Linux 上跑ldd检查一下 Chromium 二进制的依赖。快照拿不到元素。页面明明有那个按钮但snapshot里找不到。先确认页面是不是在 iframe 里agent-browser 默认只拿主文档的快照iframe 里的内容需要单独处理。然后确认元素是不是在 shadow DOM 里aria 快照对 shadow DOM 的支持有限可能需要用browser.evaluate执行 JS 直接查询。还有一种情况是元素动态加载快照拿早了加一个wait步骤。提取结果字段缺失。browser.extract返回的对象里某些字段是 null。检查fields数组里的字段名跟页面上的实际属性是否一致大小写敏感。如果页面用的是data-*属性选择器要写成[data-order-id]这种形式。另外如果字段值是异步填充的提取之前先wait一下对应的元素。排查的核心思路是先确认凭证通道401 类再确认浏览器进程proxy/启动类再确认页面状态快照/提取类最后确认模型响应choices/OAuth 类。按这个顺序大部分问题能在几分钟内定位。6. 把任务流固化下来从一次性脚本到可复用能力走到这里你已经有了一个能跑的浏览器任务流。但“能跑”和“可复现”之间还有一段距离。可复现意味着换一台机器、换一个时间点同样的配置和命令能产出同样的结果。要做到这一点需要把几个东西固化下来。第一把配置模板化。openclaw.json里的 key 不要写死用环境变量占位。OpenClaw 支持${VAR}语法启动时从环境注入。这样配置文件可以进版本控制key 留在本地或者密钥管理服务里。TaoToken 的 key 在控制台可以生成多个给不同环境用不同的 key方便审计和轮换。第二把任务定义版本化。前面那个fetch-order-list的 JSON存到项目的tasks/目录下跟代码一起提交。每次修改任务步骤都留 commit 记录出问题可以回滚。任务里的选择器尽量用稳定的属性比如data-testid或者name避免用会变的 class 名。第三把验证步骤自动化。前面手动跑的curl和openclaw browser status可以写成一个verify.sh脚本每次部署后跑一遍。脚本里检查关键返回值不通过就退出非零码接入 CI 流程。这样配置漂移能第一时间发现。第四把日志和快照归档。每次任务执行把 aria 快照、截图、提取结果按任务名/时间戳/的目录结构存下来。数据量不大但排查问题时非常有用。可以写一个清理脚本只保留最近 30 天的记录。第五考虑用 Coding Plan 来管理长期运行的编码和 Agent 任务。如果你的浏览器自动化任务是持续跑的比如每天定时抓取那用 Coding Plan 的额度管理会比按次调用更划算。入口在https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite具体额度规则看页面说明。最后说一个实用技巧给每个浏览器任务加一个“健康检查”步骤。任务开始前先打开一个已知的测试页面拿一次快照确认浏览器和模型通道都正常再执行正式步骤。这样如果环境有问题会在健康检查阶段就失败不会跑到一半才报错浪费时间和配额。这套流程跑顺之后你会发现浏览器自动化的瓶颈往往不在技术本身而在任务定义的清晰度。把“让 AI 去抓一下那个页面”这种模糊指令拆成明确的步骤、选择器、等待条件和预期输出才是可复现的关键。配置和命令只是把这个定义落到实处的工具。