探索
发现页面上有哪些事情可以做——查找按钮、表单、链接和交互元素。
文档索引
可在此获取完整文档索引:https://docs.stagehand.dev/llms.txt
在进一步浏览前,可使用该文件发现所有可用页面。
在任意网页上发现并规划可执行的操作
observe()?await stagehand.observe("find the login button");observe() 会发现页面上的可操作元素,并返回结构化操作。你可以在真正执行之前先校验这些操作,或者直接执行它们。它适合用于探索页面、规划多步工作流、缓存操作,以及在执行前验证元素。
observe()?探索
发现页面上有哪些事情可以做——查找按钮、表单、链接和交互元素。
规划
预先发现所需的全部操作,从而绘制多步工作流。
缓存
存储已发现的操作,跳过 LLM 调用,加快重复工作流的执行速度。
验证
在执行关键操作之前,先确认元素存在并检查其属性。
observe()使用 observe() 来发现页面上的可操作元素。下面展示了如何查找一个按钮:
const page = stagehand.context.pages()[0];await page.goto("https://example.com");const actions = await stagehand.observe("find the learn more button");| 用例 | 示例指令 |
|---|---|
| 查找按钮 | find the submit button |
| 定位表单 | find all input fields in the form |
| 发现链接 | find navigation links |
| 识别表格 | find the pricing table |
| 映射工作流 | find all checkout steps |
| 验证元素 | find the delete account button |
observe() 的返回值是什么?当你使用 observe() 时,Stagehand 会返回一个 Promise<Action[]>,其结构如下:
[ { description: 'Learn more button', method: 'click', arguments: [], selector: 'xpath=/html[1]/body[1]/shadow-demo[1]//div[1]/button[1]' }]使用具体且描述清晰的指令。
// 清晰且具体await stagehand.observe("find the primary call-to-action button in the hero section");await stagehand.observe("find all input fields in the checkout form");await stagehand.observe("find the delete account button in settings");避免使用模糊查询,或把它当作数据提取工具。
// 过于模糊await stagehand.observe("find buttons");
// 数据提取请改用 extract()await stagehand.observe("what is the page title?");你可以传入额外选项来配置模型、超时时间、选择器范围、需要忽略的页面区域,以及占位变量:
// 自定义模型配置const actions = await stagehand.observe("find navigation links", { model: "openai/gpt-4o", timeout: 30000, selector: "//header" // 聚焦到特定区域});你也可以使用 ignoreSelectors 排除特定节点,以及这些节点的所有后代节点。
const actions = await stagehand.observe("find the main call-to-action buttons", { ignoreSelectors: [ "//aside[contains(@class, 'promo-rail')]", "//div[@id='floating-chat-launcher']", "//section[@aria-label='recommended articles']" ]});对于登录以及其他对安全性敏感的流程,可以先用 observe() 发现候选操作,对其进行验证,然后再通过 act() 执行。传入 variables 后,observe() 会在建议操作的参数中返回 %variableName% 占位符,而不是原始的敏感值。
const actions = await stagehand.observe("find the login form fields", { variables: { username: { value: "user@example.com", description: "The login email" }, password: { value: process.env.USER_PASSWORD, description: "The login password" }, }});
const emailField = actions.find((action) => action.arguments?.includes("%username%"));const passwordField = actions.find((action) => action.arguments?.includes("%password%"));
if (emailField && passwordField) { await stagehand.act(emailField, { variables: { username: "user@example.com" } });
await stagehand.act(passwordField, { variables: { password: process.env.USER_PASSWORD } });}当运行在 Browserbase 上时,Stagehand 会自动在服务端缓存 observe() 的结果。对于输入相同的重复调用,会立即返回,而不会消耗 LLM token。缓存默认开启,可以在构造器上全局控制,也可以在单次调用时覆盖:
// 为整个实例禁用服务端缓存const stagehand = new Stagehand({ env: "BROWSERBASE", serverCache: false,});
// 或者仅对单次调用禁用const actions = await stagehand.observe("find the login button", { serverCache: false });你可以通过传入 page 选项,将 observe() 与来自其他浏览器自动化库(如 Puppeteer、Playwright 或 Patchright)的页面一起使用:
import { Stagehand } from "@browserbasehq/stagehand";import puppeteer from "puppeteer-core";
const stagehand = new Stagehand({ env: "BROWSERBASE",});await stagehand.init();
// 通过 Puppeteer 连接const browser = await puppeteer.connect({ browserWSEndpoint: stagehand.connectURL(), defaultViewport: null,});
const pages = await browser.pages();const customPage = pages[0];
await customPage.goto("https://www.example.com/products");
// 在自定义 Puppeteer 页面上使用 observeconst actions = await stagehand.observe("find all product cards", { page: customPage});这适用于:
stagehand.context.pages() 访问页面(默认)完整 API 参考
查看完整的 observe() 参考文档,了解详细参数说明、返回值以及高级示例。
先一次性发现全部操作,然后再执行,这样就不需要额外的 LLM 调用。与拆分成多个独立 act() 调用相比,这种方式通常快 2–3 倍。
const formFields = await stagehand.observe("find all form input fields");
for (const field of formFields) { await stagehand.act(field); // 无需 LLM 调用}使用 observe() 分析页面
查看如何使用 observe() 规划操作的完整指南。
使用 observe() 缩小提取范围,最多可将 token 使用量降低 10 倍。
const [table] = await stagehand.observe("find the pricing table");
const pricing = await stagehand.extract({ instruction: "extract all pricing tiers", schema: PricingSchema, selector: table.selector});提取结构化数据
了解如何将 observe() 与 extract() 结合使用,以进行精确的数据提取。
在执行关键操作之前,先确认元素存在,并验证其属性。
const [deleteButton] = await stagehand.observe("find the delete account button");
if (deleteButton?.method === "click") { await stagehand.act(deleteButton);} else { throw new Error("Delete button not found");}使用 act() 执行操作
了解如何可靠地执行观察到的操作。
存储并复用已经观察到的操作,以消除冗余的 LLM 调用。下面是一个简单缓存的示例:
const actionCache = new Map<string, Action[]>();
async function cachedObserve(instruction: string) { if (actionCache.has(instruction)) { return actionCache.get(instruction)!; }
const actions = await stagehand.observe(instruction); actionCache.set(instruction, actions); return actions;}完整缓存指南
了解用于优化性能的高级缓存技巧与模式。
问题:observe() 返回空数组。
解决方案:
observe() 之前页面已经完全加载// 在 observe 之前检查页面状态const page = stagehand.context.pages()[0];await page.waitForLoadState('domcontentloaded');
const actions = await stagehand.observe("find the submit button");
if (actions.length === 0) { console.log("No elements found, trying alternative instruction"); const altActions = await stagehand.observe("find the button at the bottom of the form");}问题:描述或选择器与实际元素不匹配。
解决方案:
logInferenceToFile,检查 LLM 的推理过程// 更具体的指令可以提升准确性// 不要这样:await stagehand.observe("find the button");
// 应该加入上下文:await stagehand.observe("find the red 'Delete' button in the user settings panel");问题:method 字段的值不是你预期的内容。
解决方案:
if (action.method === "click") { ... }await stagehand.act({ ...action, method: "click" })const [action] = await stagehand.observe("find the submit button");
// 执行前验证方法const validMethods = ["click", "fill", "type", "press"];if (action && validMethods.includes(action.method || "")) { await stagehand.act(action);} else { console.warn(`Unexpected method: ${action?.method}`);}使用 act() 执行操作
使用 act() 可靠地执行已发现的操作。
提取结构化数据
将 observe() 与 extract() 结合使用,以进行精确的数据提取。
缓存操作
构建操作缓存,消除冗余的 LLM 调用。
完整 API 参考
查看包含详细参数说明的完整 observe() 参考文档。