OA0 = Omni AI 0
OA0 是一个探索 AI 的论坛
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  functions:引导 Claude 部署无服务器浏览器自动化任务

functions:引导 Claude 部署无服务器浏览器自动化任务

 
  unittest ·  2026-02-16 10:13:06 · 3 次点击  · 0 条评论  

名称: functions
描述: 指导 Claude 使用官方 bb CLI 部署无服务器浏览器自动化


Browserbase Functions 技能

指导 Claude 使用官方 bb CLI 部署无服务器浏览器自动化。

使用场景

在以下情况使用此技能:
- 用户希望部署按计划运行的自动化任务
- 用户需要浏览器自动化的 Webhook 端点
- 用户希望在云端(而非本地)运行自动化
- 用户询问关于 Browserbase Functions

前置条件

1. 获取凭证

从以下地址获取 API 密钥和项目 ID:https://browserbase.com/settings

2. 设置环境变量

直接设置:

export BROWSERBASE_API_KEY="your_api_key"
export BROWSERBASE_PROJECT_ID="your_project_id"

创建函数项目

1. 使用官方 CLI 初始化

pnpm dlx @browserbasehq/sdk-functions init my-function
cd my-function

这将创建:

my-function/
├── package.json
├── index.ts        # 你的函数代码
└── .env            # 在此添加凭证

2. 将凭证添加到 .env

# 从存储的凭证复制
echo "BROWSERBASE_API_KEY=$BROWSERBASE_API_KEY" >> .env
echo "BROWSERBASE_PROJECT_ID=$BROWSERBASE_PROJECT_ID" >> .env

或手动编辑 .env

BROWSERBASE_API_KEY=your_api_key
BROWSERBASE_PROJECT_ID=your_project_id

3. 安装依赖

pnpm install

函数结构

import { defineFn } from "@browserbasehq/sdk-functions";
import { chromium } from "playwright-core";

defineFn("my-function", async (context) => {
  const { session, params } = context;

  // 连接到浏览器
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;

  // 你的自动化逻辑
  await page.goto(params.url || "https://example.com");
  const title = await page.title();

  // 返回可 JSON 序列化的结果
  return { success: true, title };
});

关键对象:
- context.session.connectUrl - 用于连接 Playwright 的 CDP 端点
- context.params - 调用时传入的输入参数

开发工作流

1. 启动开发服务器

pnpm bb dev index.ts

服务器运行在 http://127.0.0.1:14113

2. 本地测试

curl -X POST http://127.0.0.1:14113/v1/functions/my-function/invoke \
  -H "Content-Type: application/json" \
  -d '{"params": {"url": "https://news.ycombinator.com"}}'

3. 迭代开发

开发服务器会在文件更改时自动重载。使用 console.log() 进行调试,输出会显示在终端中。

部署

发布到 Browserbase

pnpm bb publish index.ts

输出:

Function published successfully
Build ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Function ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

保存 Function ID - 调用时需要用到它。

调用已部署的函数

通过 curl

# 开始调用
curl -X POST "https://api.browserbase.com/v1/functions/FUNCTION_ID/invoke" \
  -H "Content-Type: application/json" \
  -H "x-bb-api-key: $BROWSERBASE_API_KEY" \
  -d '{"params": {"url": "https://example.com"}}'

# 响应:{"id": "INVOCATION_ID"}

# 轮询结果
curl "https://api.browserbase.com/v1/functions/invocations/INVOCATION_ID" \
  -H "x-bb-api-key: $BROWSERBASE_API_KEY"

通过代码

async function invokeFunction(functionId: string, params: object) {
  // 开始调用
  const invokeRes = await fetch(
    `https://api.browserbase.com/v1/functions/${functionId}/invoke`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-bb-api-key': process.env.BROWSERBASE_API_KEY!,
      },
      body: JSON.stringify({ params }),
    }
  );
  const { id: invocationId } = await invokeRes.json();

  // 轮询直到完成
  while (true) {
    await new Promise(r => setTimeout(r, 5000));

    const statusRes = await fetch(
      `https://api.browserbase.com/v1/functions/invocations/${invocationId}`,
      { headers: { 'x-bb-api-key': process.env.BROWSERBASE_API_KEY! } }
    );
    const result = await statusRes.json();

    if (result.status === 'COMPLETED') return result.results;
    if (result.status === 'FAILED') throw new Error(result.error);
  }
}

常用模式

参数化数据抓取

defineFn("scrape", async ({ session, params }) => {
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;

  await page.goto(params.url);
  await page.waitForSelector(params.selector);

  const items = await page.$$eval(params.selector, els => 
    els.map(el => el.textContent?.trim())
  );

  return { url: params.url, items };
});

带身份验证的操作

defineFn("authenticated-action", async ({ session, params }) => {
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;

  // 登录
  await page.goto("https://example.com/login");
  await page.fill('[name="email"]', params.email);
  await page.fill('[name="password"]', params.password);
  await page.click('button[type="submit"]');
  await page.waitForURL('**/dashboard');

  // 执行需要身份验证的操作
  const data = await page.textContent('.user-data');
  return { data };
});

错误处理

defineFn("safe-scrape", async ({ session, params }) => {
  const browser = await chromium.connectOverCDP(session.connectUrl);
  const page = browser.contexts()[0]!.pages()[0]!;

  try {
    await page.goto(params.url, { timeout: 30000 });
    await page.waitForSelector(params.selector, { timeout: 10000 });

    const data = await page.textContent(params.selector);
    return { success: true, data };
  } catch (error) {
    return { 
      success: false, 
      error: error instanceof Error ? error.message : '未知错误' 
    };
  }
});

CLI 参考

命令 描述
pnpm dlx @browserbasehq/sdk-functions init <name> 创建新项目
pnpm bb dev <file> 启动本地开发服务器
pnpm bb publish <file> 部署到 Browserbase

故障排除

"缺少 API 密钥"

# 检查 .env 文件是否有凭证
cat .env

# 或为当前 shell 设置
export BROWSERBASE_API_KEY="your_key"
export BROWSERBASE_PROJECT_ID="your_project"

开发服务器无法启动

# 确保 SDK 已安装
pnpm add @browserbasehq/sdk-functions

# 或使用 npx
npx @browserbasehq/sdk-functions dev index.ts

函数超时

  • 最大执行时间为 15 分钟
  • 为页面操作添加特定的超时设置
  • 使用 waitForSelector 而不是 sleep

无法连接到浏览器

  • 检查是否正确使用了 session.connectUrl
  • 确保使用 chromium.connectOverCDP() 而不是 chromium.launch()
3 次点击  ∙  0 人收藏  
登录后收藏  
目前尚无回复
0 条回复
About   ·   Help   ·    
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
Developed with Cursor