dev-browser について
dev-browserは、小さなスクリプトで段階的に操作し、実行間でページ状態を保持するブラウザー自動化スキルです。独立したChromiumまたはユーザーのChromeセッションに接続でき、Playwrightによる操作とアクセシビリティスナップショットを備えています。
主な機能
- 01スクリプト実行間でページ状態を保持
- 02独立ChromiumまたはChrome拡張モード
- 03Playwrightによるページ操作
- 04ARIAスナップショットと参照で要素を特定
- 05スクリーンショットとページ状態の確認
活用シーン
- 01複数のスクリプトでタスクを段階的に自動化
- 02既存ブラウザーのログイン済みサイトを操作
- 03未知のページ構成を調べて要素を選択
- 04ネットワークリクエストの再生による大規模データ収集
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ code-yeongyu/ oh-my-openagent --skill dev-browserインストール後、Claude Code で/dev-browserを入力して読み込まれたか確認します。
詳細
Dev Browser スキル
スクリプトの実行をまたいでページの状態を維持するブラウザー自動化です。タスクを段階的に進めるため、小さくて目的を絞ったスクリプトを作成します。ワークフローの一部で動作を確認でき、繰り返し作業が発生する場合は、1回の実行でまとめて処理するスクリプトを作成できます。
アプローチの選択
- ローカル/ソースを利用できるサイト:まずソースコードを読み、セレクターを直接指定します
- ページレイアウトが不明な場合:
getAISnapshot()で要素を見つけ、selectSnapshotRef()で操作します - 視覚的なフィードバック:スクリーンショットを撮影して、ユーザーに見えている画面を確認します
セットアップ
インストール:Windows のサポートを含む詳しいセットアップ手順については、references/installation.md を参照してください。
利用できるモードは 2 つです。どちらを使用するか不明な場合は、ユーザーに確認してください。
スタンドアロンモード(デフォルト)
新しい Chromium ブラウザーを起動して、新規の自動化セッションを開始します。
./skills/dev-browser/server.sh &
ユーザーからリクエストがあった場合は、--headless フラグを追加してください。スクリプトを実行する前に、Ready メッセージが表示されるまで待ってください。
拡張機能モード
ユーザーが現在使用している Chrome ブラウザーに接続します。次の場合に使用してください。
- ユーザーがすでにサイトにログインしていて、ローカル開発環境ではない認証済みの環境で操作を行いたい場合。
- ユーザーから拡張機能を使うよう依頼された場合
重要:基本的なフローは同じです。ユーザーのブラウザー内に名前付きページを作成します。
リレーサーバーを起動します:
cd skills/dev-browser && npm i && npm run start-extension &
コンソールに Waiting for extension to connect... が表示された後、Extension connected が表示されるまで待ってください。これにより、クライアントが接続され、ブラウザーを操作できる状態になったことがわかります。
ワークフロー:
- スクリプトでは、通常モードと同じように
client.page("name")を呼び出し、新しいページを作成するか、既存のページに接続します。 - 自動化はユーザーの実際のブラウザーセッションで実行されます
拡張機能がまだ接続されていない場合は、起動して有効化するようユーザーに伝えてください。ダウンロードリンク:https://github.com/SawyerHood/dev-browser/releases
スクリプトの作成
すべてのスクリプトは
skills/dev-browser/ディレクトリから実行してください。@/インポートエイリアスでは、このディレクトリの設定が必要です。
ヒアドキュメントを使って、スクリプトをインラインで実行します。
cd skills/dev-browser && npx tsx <<'EOF'
import { connect, waitForPageLoad } from "@/client.js";
const client = await connect();
// Create page with custom viewport size (optional)
const page = await client.page("example", { viewport: { width: 1920, height: 1080 } });
await page.goto("https://example.com");
await waitForPageLoad(page);
console.log({ title: await page.title(), url: page.url() });
await client.disconnect();
EOF
スクリプトの再利用が必要な場合、複雑な場合、またはユーザーから明示的に依頼された場合に限り、tmp/ ファイルに書き込みます。
主な原則
- 小さなスクリプト:各スクリプトでは 1 つのことだけを行います(移動、クリック、入力、確認)
- 状態を評価する:次の手順を判断できるよう、最後に状態をログに出力するか返します
- わかりやすいページ名:「main」ではなく、「checkout」や「login」を使います
- 切断して終了する:
await client.disconnect()を実行します。ページはサーバー上に保持されます - evaluate ではプレーンな JavaScript を使う:
page.evaluate()はブラウザー内で実行されるため、TypeScript 構文は使えません
ワークフローのループ
複雑なタスクでは、次のパターンに従ってください。
- スクリプトを作成する:1 つの操作を実行します
- 実行する:実行結果を確認します
- 評価する:うまくいきましたか?現在の状態はどうなっていますか?
- 判断する:タスクは完了しましたか?それとも次のスクリプトが必要ですか?
- タスクが完了するまで繰り返します
ブラウザーコンテキストでは TypeScript を使用しないでください
page.evaluate() に渡したコードはブラウザー内で実行されます。ブラウザーは TypeScript を理解できません。
// ✅ Correct: plain JavaScript
const text = await page.evaluate(() => {
return document.body.innerText;
});
// ❌ Wrong: TypeScript syntax will fail at runtime
const text = await page.evaluate(() => {
const el: HTMLElement = document.body; // Type annotation breaks in browser!
return el.innerText;
});
データのスクレイピング
大規模なデータセットをスクレイピングする場合は、DOM をスクロールするのではなく、ネットワークリクエストを傍受して再実行してください。リクエストのキャプチャ、スキーマの検出、ページ分割された API の再実行を含む詳しいガイドについては、references/scraping.md を参照してください。
クライアント API
const client = await connect();
// Get or create named page (viewport only applies to new pages)
const page = await client.page("name");
const pageWithSize = await client.page("name", { viewport: { width: 1920, height: 1080 } });
const pages = await client.list(); // List all page names
await client.close("name"); // Close a page
await client.disconnect(); // Disconnect (pages persist)
// ARIA Snapshot methods
const snapshot = await client.getAISnapshot("name"); // Get accessibility tree
const element = await client.selectSnapshotRef("name", "e5"); // Get element by ref
page オブジェクトは、標準の Playwright Page です。
待機
import { waitForPageLoad } from "@/client.js";
await waitForPageLoad(page); // After navigation
await page.waitForSelector(".results"); // For specific elements
await page.waitForURL("**/success"); // For specific URL
ページの状態を確認する
スクリーンショット
await page.screenshot({ path: "tmp/screenshot.png" });
await page.screenshot({ path: "tmp/full.png", fullPage: true });
ARIA スナップショット(要素の検出)
getAISnapshot() を使用してページ上の要素を検出します。YAML 形式のアクセシビリティツリーが返されます。
- banner:
- link "Hacker News" [ref=e1]
- navigation:
- link "new" [ref=e2]
- main:
- list:
- listitem:
- link "Article Title" [ref=e8]
- link "328 comments" [ref=e9]
- contentinfo:
- textbox [ref=e10]
- /placeholder: "Search"
参照情報の見方:
[ref=eN]- 操作対象となる要素の参照(表示され、クリック可能な要素のみ)[checked]、[disabled]、[expanded]- 要素の状態[level=N]- 見出しレベル/url:、/placeholder:- 要素のプロパティ
参照を使った操作:
const snapshot = await client.getAISnapshot("hackernews");
console.log(snapshot); // Find the ref you need
const element = await client.selectSnapshotRef("hackernews", "e2");
await element.click();
エラーからの復旧
失敗後もページの状態は保持されます。次のようにデバッグしてください。
cd skills/dev-browser && npx tsx <<'EOF'
import { connect } from "@/client.js";
const client = await connect();
const page = await client.page("hackernews");
await page.screenshot({ path: "tmp/debug.png" });
console.log({
url: page.url(),
title: await page.title(),
bodyText: await page.textContent("body").then((t) => t?.slice(0, 200)),
});
await client.disconnect();
EOF