browser 模板示例

更新时间:
复制 MD 格式

browser 模板提供云原生浏览器运行环境,支持通过标准的 Chrome DevTools Protocol(CDP)over WebSocket 远程控制运行在云端隔离容器中的浏览器实例,原生兼容 Puppeteer、Playwright 等自动化框架。

browser 模板不是开通即用的内置模板,需要先从官方 browser 镜像构建一个带名称的自定义模板,再用该模板创建沙箱。本页只介绍能力、默认配置、构建与最小验证、端点差异;BrowserUse、LangChain 等框架接入的完整教程见使用 Browser Use Sandbox

功能特性

特性说明
浏览器自动化内置 Chromium/Chrome 浏览器,支持完整 Web 标准,原生兼容 Puppeteer、Playwright 等自动化框架
CDP 远程控制通过标准 CDP 协议 over WebSocket 精准操控动态渲染页面(SPA),稳定维持登录态与 Session
VNC 实时可视化内置 VNC 服务,支持通过 noVNC 客户端实时查看浏览器桌面环境,方便调试和监控
安全隔离每个 browser 沙箱实例拥有独立的文件系统和进程空间
传输加密所有数据面端点(CDP 和 VNC)均使用 WSS(WebSocket Secure)协议,全程加密

默认配置

配置项默认值说明
容器镜像fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/browser:v0.0.36预置 browser 镜像
默认端口3000沙箱服务监听端口
CPU4 vCPU最低要求
内存8192 MB最低要求
磁盘大小10240 MB建议 10 GB 以获得充足的临时存储空间

构建与最小验证

browser 模板的用法分为两个阶段:先构建模板(从 browser 镜像固化出一个带名称的模板),再运行模板(创建沙箱、等待健康检查、通过 CDP 打开页面并截图)。

说明

示例中的 E2B_API_KEYE2B_API_URLE2B_DOMAIN 需在运行前通过环境变量(如 .envexport)配置为对应地域的接入地址,SDK 会自动读取,无需在方法调用中显式传入。连接 CDP/VNC 端点时需在请求头携带 X-Access-Token:Python SDK 通过内部属性 sbx._envd_access_token 获取(后续版本可能重命名或移除),JS SDK 通过 sbx.envdAccessToken 获取(TypeScript 中为 protected 修饰,运行时可直接读取)。

准备本地环境

Python

uv venv .venv --python 3.12
source .venv/bin/activate
uv pip install e2b==2.31.0 e2b-code-interpreter==2.8.1 'playwright>=1.49.0'
playwright install chromium

Node.js:使用如下 package.json,然后执行 npm install

{
  "name": "browser-template-demo",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "@e2b/code-interpreter": "^2.6.1",
    "e2b": "^2.31.0",
    "playwright-core": "^1.49.0"
  }
}

构建 browser 模板

从 browser 镜像构建一个带名称的模板,构建时指定 CPU 与内存规格(推荐 4 vCPU / 8192 MB)。

Python

"""browser 模板构建示例。"""

import os

from dotenv import load_dotenv
from e2b import Template, default_build_logger

load_dotenv()

# SDK 自动读取 E2B_API_KEY / E2B_API_URL / E2B_DOMAIN 环境变量。
FROM_IMAGE = "fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/browser:v0.0.36"

build = Template.build(
    Template().from_image(FROM_IMAGE),
    name="my-browser-template",
    cpu_count=4,
    memory_mb=8192,
    on_build_logs=default_build_logger(),
)
print(f"template_id: {build.template_id}")

Node.js

// browser 模板构建示例。
import { Template, defaultBuildLogger } from 'e2b';

// SDK 自动读取 E2B_API_KEY / E2B_API_URL / E2B_DOMAIN 环境变量。
const FROM_IMAGE =
  'fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/browser:v0.0.36';

const build = await Template.build(Template().fromImage(FROM_IMAGE), 'my-browser-template', {
  cpuCount: 4,
  memoryMB: 8192,
  onBuildLogs: defaultBuildLogger(),
});
console.log(`template_id: ${build.templateId}`);

运行模板并验证

创建沙箱后,先轮询 /health 等待 browser 服务就绪,再通过 CDP 端点连接 Playwright 打开目标页并截图。

Python

"""browser 模板运行示例:创建沙箱 -> 等待健康检查 -> CDP 自动化 -> 截图。"""

import time

from e2b_code_interpreter import Sandbox
from playwright.sync_api import sync_playwright

# SDK 自动读取 E2B_API_KEY / E2B_API_URL / E2B_DOMAIN 环境变量。
BROWSER_PORT = 3000


def wait_until_healthy(sbx: Sandbox, host: str, token: str, timeout: int = 60) -> None:
    """轮询公网网关 /health 端点,直到 browser 服务就绪或超时。"""
    token_header = f"-H 'X-Access-Token: {token}' " if token else ""
    deadline = time.time() + timeout
    while time.time() < deadline:
        result = sbx.commands.run(
            f"curl -sS -o /dev/null -w '%{{http_code}}' -m 4 {token_header}https://{host}/health",
            timeout=10,
        )
        if "".join(result.stdout or []).strip() == "200":
            return
        time.sleep(2)
    raise TimeoutError(f"browser 服务在 {timeout}s 内未就绪")


sbx = None
try:
    sbx = Sandbox.create(template="my-browser-template", timeout=900)
    host = sbx.get_host(BROWSER_PORT)
    token = sbx._envd_access_token  # 公网网关要求 X-Access-Token,否则 403
    headers = {"X-Access-Token": token} if token else {}

    wait_until_healthy(sbx, host, token)

    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(f"wss://{host}/ws/automation", headers=headers)
        context = browser.contexts[0] if browser.contexts else browser.new_context()
        page = context.new_page()
        page.goto("https://example.com", wait_until="domcontentloaded", timeout=30000)
        print(f"page.title() = {page.title()!r}")
        page.screenshot(path="browser-example.png", full_page=True)
        browser.close()
finally:
    if sbx is not None:
        sbx.kill()

Node.js

// browser 模板运行示例:创建沙箱 -> 等待健康检查 -> CDP 自动化 -> 截图。
import { Sandbox } from '@e2b/code-interpreter';
import { chromium } from 'playwright-core';

// SDK 自动读取 E2B_API_KEY / E2B_API_URL / E2B_DOMAIN 环境变量。
const BROWSER_PORT = 3000;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

/** 轮询公网网关 /health 端点,直到 browser 服务就绪或超时。 */
async function waitUntilHealthy(sbx, host, token, timeout = 60) {
  const tokenHeader = token ? `-H 'X-Access-Token: ${token}' ` : '';
  const deadline = Date.now() + timeout * 1000;
  while (Date.now() < deadline) {
    let result;
    try {
      result = await sbx.commands.run(
        `curl -sS -o /dev/null -w '%{http_code}' -m 4 ${tokenHeader}https://${host}/health`,
        { timeoutMs: 10_000 },
      );
    } catch (e) {
      result = e; // 服务未起时 curl 非 0 退出,异常同样携带 stdout
    }
    if ((result.stdout || '').trim() === '200') return;
    await sleep(2000);
  }
  throw new Error(`browser 服务在 ${timeout}s 内未就绪`);
}

let sbx = null;
try {
  sbx = await Sandbox.create('my-browser-template', { timeoutMs: 900_000 });
  const host = sbx.getHost(BROWSER_PORT);
  const token = sbx.envdAccessToken; // 公网网关要求 X-Access-Token,否则 403
  const headers = token ? { 'X-Access-Token': token } : {};

  await waitUntilHealthy(sbx, host, token);

  const browser = await chromium.connectOverCDP(`wss://${host}/ws/automation`, { headers });
  const contexts = browser.contexts();
  const context = contexts.length ? contexts[0] : await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded', timeout: 30_000 });
  console.log(`page.title() = ${JSON.stringify(await page.title())}`);
  await page.screenshot({ path: 'browser-example.png', fullPage: true });
  await browser.close();
} finally {
  if (sbx !== null) await sbx.kill();
}

WebSocket 端点

browser 模板通过 3000 端口暴露以下端点,均需在请求头携带 X-Access-Token 鉴权,<sandbox-host> 通过 SDK 的 sbx.get_host(3000) 获取:

端点路径用途
健康检查https://<sandbox-host>/health判断 browser 服务是否启动完成
CDP 自动化wss://<sandbox-host>/ws/automation浏览器自动化,兼容 Puppeteer 和 Playwright
VNC 实时流wss://<sandbox-host>/ws/livestream实时查看浏览器桌面,可通过 noVNC 客户端查看

在沙箱内部可先探测 CDP WebSocket 握手是否正常,返回 101 Switching Protocols 即说明端点可升级为 WebSocket:

curl -sS -m 4 -i \
  -H 'Connection: Upgrade' -H 'Upgrade: websocket' \
  -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' \
  http://localhost:3000/ws/automation
说明

浏览器 WebSocket API 不支持在握手时设置自定义请求头,因此 noVNC 等纯浏览器客户端无法携带 X-Access-Token,直接连接会返回 403。需使用支持自定义请求头的 WebSocket 客户端(如 wscat、Python websockets)携带 X-Access-Token 完成 RFB 握手。如果只需查看结果,可通过 CDP 连接后调用 page.screenshot() 截图。

使用限制

限制项约束
浏览器支持目前内置 Chromium/Chrome 浏览器

相关文档