ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Web 自动化:用 Playwright 扩展 Skill 感知边界,TaoToken 配置实战

2026/9/29 20:49:14 拓冰建站 浏览量
Web 自动化:用 Playwright 扩展 Skill 感知边界,TaoToken 配置实战 1. 动态页面里 Skill 为什么总“看不见”做 Web 自动化的朋友大概率遇到过这种场景Agent 里挂了一个 Skill让它去某个电商平台抓实时价格或者去政务网站拉一条公示信息。页面在浏览器里肉眼看着好好的Skill 一跑就返回空列表或者只抓到骨架屏的占位文字。问题不在选择器写错而在于 Skill 的感知边界被卡住了。传统做法是 Skill 只解析一次 HTML拿到什么算什么。可现在的页面大量依赖 JavaScript 异步渲染首屏返回的 HTML 里根本没有目标节点数据是后面几秒才塞进 DOM 的。Skill 如果按“请求—解析—返回”的同步思路走感知范围就只覆盖了页面生命周期的前 100 毫秒后面的动态内容全在边界之外。Playwright 的价值就在这里。它驱动的是真实浏览器内核能等网络空闲、能等选择器出现、能执行页面里的 JS相当于把 Skill 的感知窗口从“一帧快照”拉长成“一段可观测的过程”。再配合 TaoToken 提供的统一 Key 与 API 通道把模型调用和浏览器操作串成一条链路Skill 才真正具备在动态页面里“看得见、等得到、抓得准”的能力。这篇就围绕 Playwright 配置、TaoToken 的 settings.json 骨架以及怎么验证感知边界确实被扩展了给一套能直接复制的落地方案。2. TaoToken 前置统一 Key 与 API 通道在把 Playwright 接进 Skill 之前先把模型侧的通道理顺。TaoToken 的作用是给 Agent 提供一个统一的入口模型对话、编码计划、API Key 管理都在同一套体系里省得每个 Skill 各自维护一份凭证。你需要先拿到一个可用的 Key。打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 进入控制台后创建 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite Key 列表页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。创建完复制那串 sk- 开头的字符串后面写进 settings.json。API 的基础地址是 https://taotoken.net/api 注意这个地址不带任何查询参数直接作为 base_url 使用。如果你要确认模型能力或者临时对话测试可以用模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。长期跑编码类或 Agent 类任务建议看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 接入细节在文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。注意Key 只存在本地配置文件或环境变量里不要硬编码进 Skill 源码提交到仓库。生产环境建议用环境变量注入。3. 可复制配置Playwright 与 settings.json 骨架3.1 安装与浏览器二进制先装 Playwright 和 Chromium 内核。命令很直接pip install playwright playwright install chromium如果你用 Node 侧的工具链对应的是npm i -D playwright加npx playwright install chromium。装完确认一下版本避免和 Skill 框架里的 asyncio 事件循环冲突。3.2 settings.json 骨架下面这份骨架把 TaoToken 的 Key、base_url 和 Playwright 的感知参数放在一起。字段名按你实际框架微调结构可以直接抄{ taotoken: { api_key: ${TAOTOKEN_API_KEY}, base_url: https://taotoken.net/api, model: claude-sonnet, timeout: 60 }, playwright: { headless: true, browser: chromium, user_agent: OpenClaw-Agent/1.0, default_timeout: 15000, wait_until: networkidle, viewport: { width: 1440, height: 900 } }, skill: { perception: { wait_selector: .trend-item, max_items: 10, retry: 2, retry_interval_ms: 800 } } }这里几个参数决定了感知边界能扩多宽。wait_until设成networkidle表示等网络请求基本停下来再解析适合数据靠 XHR 拉取的页面。wait_selector是目标节点出现的信号Skill 会一直等到它出现或超时。retry和retry_interval_ms处理偶发的渲染延迟避免一次没等到就放弃。3.3 Skill 核心实现把上面的配置读进来Skill 的主体逻辑如下。关键点是async with保证浏览器进程回收page.wait_for_selector把感知窗口撑到目标节点真正出现import asyncio import json from playwright.async_api import async_playwright from pydantic import BaseModel, Field from typing import List class HotTrendItem(BaseModel): rank: int title: str heat: str class WebSearchOutput(BaseModel): platform: str trends: List[HotTrendItem] async def fetch_hot_trends_skill(platform_url: str, cfg: dict) - WebSearchOutput: pw_cfg cfg[playwright] sk_cfg cfg[skill][perception] async with async_playwright() as p: browser await p.chromium.launch(headlesspw_cfg[headless]) context await browser.new_context( user_agentpw_cfg[user_agent], viewportpw_cfg[viewport], ) page await context.new_page() page.set_default_timeout(pw_cfg[default_timeout]) try: await page.goto(platform_url, wait_untilpw_cfg[wait_until]) await page.wait_for_selector(sk_cfg[wait_selector], timeoutpw_cfg[default_timeout]) items [] elements await page.query_selector_all(sk_cfg[wait_selector]) for i, el in enumerate(elements[: sk_cfg[max_items]]): title await el.query_selector(.title) heat await el.query_selector(.heat-value) items.append(HotTrendItem( ranki 1, titleawait title.inner_text() if title else 未知, heatawait heat.inner_text() if heat else 0, )) return WebSearchOutput(platform示例平台, trendsitems) except Exception as e: print(fWeb 自动化执行失败: {e}) return WebSearchOutput(platformError, trends[]) finally: await browser.close()wait_for_selector这一行是感知边界扩展的核心。没有它query_selector_all可能在节点还没渲染时就执行返回空数组。加上它之后Skill 的“视野”从页面加载完成那一刻延伸到了目标内容真正就位那一刻。4. 验证请求确认感知边界真的扩了配置写完不能只看代码得跑一次确认效果。验证分两步先确认 TaoToken 通道通再确认 Playwright 抓到了动态内容。4.1 验证 TaoToken 通道用 curl 打一次模型接口确认 Key 和 base_url 可用curl -X POST https://taotoken.net/api/v1/messages \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet, max_tokens: 64, messages: [{role: user, content: 回复 ok}] }返回里带content字段且内容正常说明通道没问题。如果返回 401检查 Key 是否复制完整返回 404检查 base_url 有没有多写路径。4.2 验证 Playwright 感知扩展写一个最小脚本对比“不等选择器”和“等选择器”两种情况的抓取结果import asyncio from playwright.async_api import async_playwright async def compare(url: str): async with async_playwright() as p: browser await p.chromium.launch(headlessTrue) page await browser.new_page() await page.goto(url, wait_untildomcontentloaded) # 情况一不等直接抓 early await page.query_selector_all(.trend-item) print(f不等选择器抓到: {len(early)} 条) # 情况二等目标节点出现 await page.wait_for_selector(.trend-item, timeout15000) late await page.query_selector_all(.trend-item) print(f等选择器后抓到: {len(late)} 条) await browser.close() asyncio.run(compare(https://example.com/trends))实测下来动态页面里情况一经常返回 0情况二能稳定拿到目标数量。这个差值就是感知边界被扩展的直接证据。如果两者数量一致说明该页面是服务端渲染Playwright 的等待机制没派上用场但也不影响后续接入。4.3 把结果回传给模型抓到结构化数据后通过 TaoToken 的 API 把结果交给模型做二次处理比如归纳趋势或生成摘要。这一步复用 4.1 的通道把messages里的 content 换成抓取到的 JSON 字符串即可。整条链路跑通Skill 就从“只能看静态 HTML”升级成“能观测动态渲染并回传结构化结果”。5. 本篇常见错排查5.1 选择器等到了但内容为空wait_for_selector只保证节点存在不保证节点里的文字已经填充。如果.trend-item先出现、.title后填充就会抓到空字符串。解决办法是等更具体的选择器比如page.wait_for_selector(.trend-item .title)或者对单个元素用el.wait_for_selector(.title)。5.2 超时时间设太短默认 15 秒对多数页面够用但有些平台首屏要加载大量资源或者有验证码前置流程15 秒不够。可以按页面实际情况调到 30 秒同时把retry打开超时后重试而不是直接失败。注意别把超时设得过大否则 Skill 卡住时排查困难。5.3 浏览器进程泄漏如果 Skill 里用了browser await p.chromium.launch()但没在finally里close()跑几次之后机器上会堆一堆 Chromium 进程内存吃满。务必用async with或者 try-finally 包住。生产环境更稳的做法是引入浏览器池复用 context 而不是每次冷启动。5.4 Key 读取失败settings.json 里写的是${TAOTOKEN_API_KEY}运行时如果环境变量没注入就会拿到字面量字符串请求直接 401。排查时先打印一下读到的 Key 前几位确认是真实值而不是占位符。CI 环境里记得在流水线配置里加这个变量。5.5 被目标站点限流高频抓取同一个页面容易触发限流表现为返回 403 或验证码页。控制抓取频率设置合理的user_agent必要时在 Skill 里加随机间隔。合规方面确认目标站点的 robots.txt 允许抓取别用于非法用途。6. 接入与后续把 Playwright 接进 Skill 之后感知边界从静态 HTML 扩展到了动态渲染的完整生命周期配合 TaoToken 的统一 Key 和 API 通道模型调用和浏览器操作能在同一条链路里完成。如果你在接入过程中遇到 Key 配置或通道报错先去 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 核对凭证再看接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里的参数说明。想先验证模型返回是否符合预期用模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 快速试一次。长期跑编码类或 Agent 类任务Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 的额度模型更适合持续调用。