使用 Vercel Sandbox 實現瀏覽器自動化
在短暫存在的 Vercel Sandbox 微型虛擬機中執行 agent-browser 與無頭 Chrome。Linux 虛擬機會根據需求啟動、執行瀏覽器命令,然後關閉。此方式適用於任何部署在 Vercel 的框架(Next.js、SvelteKit、Nuxt、Remix、Astro 等)。
相依套件
pnpm add @agent-browser/sandbox @vercel/sandbox
Sandbox 虛擬機需要 Chromium 的系統相依項目以及 agent-browser 本身。@agent-browser/sandbox 輔助工具預設會為全新的沙盒安裝這些相依項目,並使用沙盒快照(如下所述)以達到次秒級啟動。僅在沙盒映像已提供 Chromium 所需函式庫時,才傳入 installSystemDependencies: false。
核心模式
import {
createAgentBrowserSnapshot,
runAgentBrowserCommand,
withAgentBrowserSandbox,
type VercelSandboxSession,
} from "@agent-browser/sandbox/vercel";
async function withBrowser<T>(
fn: (sandbox: VercelSandboxSession) => Promise<T>,
): Promise<T> {
return withAgentBrowserSandbox(fn);
}
螢幕截圖
screenshot --json 命令會將截圖儲存至檔案並回傳路徑。將檔案以 base64 格式讀回:
export async function screenshotUrl(url: string) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const titleResult = await runAgentBrowserCommand<{ data?: { title?: string } }>(sandbox, [
"get", "title",
]);
const title = titleResult.json?.data?.title || url;
const ssResult = await runAgentBrowserCommand<{ data?: { path?: string } }>(sandbox, [
"screenshot",
]);
const ssPath = ssResult.json?.data?.path;
if (!ssPath) throw new Error("螢幕截圖未回傳檔案路徑。");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { title, screenshot };
});
}
無障礙快照
export async function snapshotUrl(url: string) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const titleResult = await runAgentBrowserCommand<{ data?: { title?: string } }>(sandbox, [
"get", "title",
]);
const title = titleResult.json?.data?.title || url;
const snapResult = await runAgentBrowserCommand(sandbox, ["snapshot", "-i", "-c"], {
json: false,
});
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { title, snapshot: snapResult.stdout };
});
}
多步驟工作流程
由於沙盒在命令之間保持持續存在,因此您可以執行完整的自動化序列:
export async function fillAndSubmitForm(
url: string,
data: Record<string, string>,
postSubmitWaitArgs: string[],
) {
return withBrowser(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", url]);
const snapResult = await runAgentBrowserCommand(sandbox, ["snapshot", "-i"], {
json: false,
});
const snapshot = snapResult.stdout;
// 剖析快照以尋找元素參考...
for (const [ref, value] of Object.entries(data)) {
await runAgentBrowserCommand(sandbox, ["fill", ref, value]);
}
await runAgentBrowserCommand(sandbox, ["click", "@e5"]);
// 傳入應用程式特定的等待條件,例如 ["--url", "**/checkout/complete"]、
// ["--text", "Thanks"] 或 ["#confirmation"]。
await runAgentBrowserCommand(sandbox, ["wait", ...postSubmitWaitArgs]);
const ssResult = await runAgentBrowserCommand<{ data?: { path?: string } }>(sandbox, [
"screenshot",
]);
const ssPath = ssResult.json?.data?.path;
if (!ssPath) throw new Error("螢幕截圖未回傳檔案路徑。");
const b64Result = await sandbox.runCommand("base64", ["-w", "0", ssPath]);
const screenshot = (await b64Result.stdout()).trim();
await runAgentBrowserCommand(sandbox, ["close"], { json: false });
return { screenshot };
});
}
沙盒快照(快速啟動)
沙盒快照是一個已儲存的虛擬機映像,其中包含已預先安裝好系統相依項目、agent-browser 與 Chromium 的 Vercel Sandbox。您可以將其視為 Docker 映像:無需每次都從頭開始安裝相依項目,沙盒會從預先建置的映像啟動。
這與 agent-browser 的無障礙快照功能(agent-browser snapshot)無關,後者會傾印頁面的無障礙樹。沙盒快照是 Vercel 基礎架構的概念,用於實現快速虛擬機啟動。
沒有沙盒快照時,每次執行都需要安裝系統相依項目、agent-browser 與 Chromium(約 30 秒)。有了沙盒快照,啟動時間可低於一秒。
建立沙盒快照
快照必須包含系統相依項目(透過 dnf)、agent-browser 與 Chromium:
const snapshotId = await createAgentBrowserSnapshot();
執行此命令一次,然後設定環境變數:
AGENT_BROWSER_SNAPSHOT_ID=snap_xxxxxxxxxxxx
示範應用程式中提供了一個輔助腳本:
npx tsx examples/environments/scripts/create-snapshot.ts
建議任何使用沙盒模式的上線部署都採用此方式。
身分驗證
在 Vercel 部署中,Sandbox SDK 會透過 OIDC 自動進行身分驗證。若在本地開發或需要明確控制,請設定:
VERCEL_TOKEN=<個人存取權杖>
VERCEL_TEAM_ID=<團隊 ID>
VERCEL_PROJECT_ID=<專案 ID>
這些值會被傳入 Sandbox.create() 呼叫中。當這些值不存在時,SDK 會回退使用 VERCEL_OIDC_TOKEN(在 Vercel 上會自動提供)。
排程工作流程(Cron)
結合 Vercel Cron Jobs 以執行重複的瀏覽器任務:
// app/api/cron/route.ts (或您所使用框架中的對應檔案)
export async function GET() {
const result = await withBrowser(async (sandbox) => {
await sandbox.runCommand("agent-browser", ["open", "https://example.com/pricing"]);
const snap = await sandbox.runCommand("agent-browser", ["snapshot", "-i", "-c"]);
await sandbox.runCommand("agent-browser", ["close"]);
return await snap.stdout();
});
// 處理結果、發送警示、儲存資料...
return Response.json({ ok: true, snapshot: result });
}
// vercel.json
{ "crons": [{ "path": "/api/cron", "schedule": "0 9 * * *" }] }
環境變數
| 變數 | 必要 | 說明 |
|---|---|---|
AGENT_BROWSER_SNAPSHOT_ID | 否(但建議使用) | 預先建立的沙盒快照 ID,用於次秒級啟動(參見上述說明) |
VERCEL_TOKEN | 否 | Vercel 個人存取權杖(用於本地開發;在 Vercel 上會自動使用 OIDC) |
VERCEL_TEAM_ID | 否 | Vercel 團隊 ID(用於本地開發) |
VERCEL_PROJECT_ID | 否 | Vercel 專案 ID(用於本地開發) |
框架範例
此模式在所有框架中的運作方式完全相同。唯一的差異在於放置伺服器端程式碼的位置:
| 框架 | 伺服器程式碼位置 |
|---|---|
| Next.js | 伺服器動作、API 路由、路由處理器 |
| SvelteKit | +page.server.ts、+server.ts |
| Nuxt | server/api/、server/routes/ |
| Remix | loader、action 函式 |
| Astro | .astro frontmatter、API 路由 |
範例
請參閱 agent-browser 儲存庫中的 examples/environments/ 目錄,以查看使用 Vercel Sandbox 模式的完整應用程式,其中包含沙盒快照建立腳本、串流進度 UI 以及速率限制。