15 KiB
BrowseWeb 詳細ガイド
ヘッドレスブラウザで Web ページを操作するツール。同一ジョブ内ではブラウザコンテキスト(Cookie・ログイン状態)が永続化される。
2 つのモード
1. 基本モード — URL を開いてテキスト取得
BrowseWeb({ url: "https://example.com" })
ローカルで生成した HTML をブラウザで確認したい場合は、workspace ルートからの 相対パス をそのまま渡す(推奨)。
BrowseWeb({ url: "output/viewer.html" })
例:
output/viewer.htmlを開く →BrowseWeb({ url: "output/viewer.html" })input/sample.htmlを開く →BrowseWeb({ url: "input/sample.html" })
内部的には実行中ジョブの workspace 絶対パスと結合され file:// URL に変換される。../ で workspace 外に出るパスは拒否される。file:/// で始まる絶対 URL を直接渡すことも可能だが、workspace 外を指すものは拒否される。
オプション:
waitFor: 待機する CSS セレクタ(省略時は load イベント完了まで待機)extractSelector: 特定要素のテキストだけ抽出する CSS セレクタscreenshot: スクリーンショットを保存するファイル名(例:"page.png"→output/page.png)timeout: タイムアウト(ms、デフォルト 60000)
2. アクションモード — 連続操作
BrowseWeb({
actions: [
{ type: "goto", url: "https://example.com/login" },
{ type: "fill", ref: "e3", value: "user@example.com" },
{ type: "click", ref: "e5" },
{ type: "getText" }
]
})
利用可能な type:
goto—urlで指定したページに遷移click—selectorまたはrefで要素をクリックfill—selectorまたはrefの input/textarea にvalueを入力screenshot—valueで指定したファイル名で保存(省略時screenshot.png)getText— 全ページのスナップショット(ref 注釈付き)またはselector内のテキストを取得wait—msミリ秒待機(最大 30000)dumpHtml—refまたはselector(省略時 body)の outerHTML を取得(脱出口、後述)
長文ページの取得(preview + ファイル保存)
getText (selector 有無問わず) およびスナップショットの戻り値が 5000 文字を超える 場合、フルテキストはワークスペースの logs/browse/{ISO-timestamp}-{hash}.txt に保存され、戻り値は 先頭 5000 文字 + 続きの取得方法案内 になる:
(先頭 5000 文字)
... (truncated; full 38214 chars saved to logs/browse/2026-05-07T09-30-12-a1b2c3d4.txt — Read({file_path:"logs/browse/2026-05-07T09-30-12-a1b2c3d4.txt", offset, limit}) で続きを取得可能)
続きを読みたい場合は Read ツールで offset / limit を指定:
Read({ file_path: "logs/browse/2026-05-07T09-30-12-a1b2c3d4.txt", offset: 200, limit: 200 })
5000 文字以下のページなら従来通り全文が直接返り、ファイルは作成されない。
ref 注釈の仕組み(重要)
BrowseWeb({ url }) や getText の出力には、操作可能な要素が以下のような注釈付きで埋め込まれる:
ようこそ
{e1 link "ホーム" href="/"} {e2 link "製品" href="/products"}
ログインしてください
{e3 textbox name="email" placeholder="メールアドレス"}
{e4 textbox name="password"}
{e5 button "ログイン"}
e1,e2, ... の ID(ref)は出現順に自動採番される- 各 ref は内部的に Playwright で解釈可能なセレクタ(
data-testid/id/[name]/aria-label/ nth-of-type CSS chain の優先順)にマッピングされている - click/fill アクションで
ref: "e5"のように指定するだけで操作できる - CSS セレクタを自分で組み立てる必要がない
検出される要素の範囲
ref が振られるのは以下の要素:
- 標準 HTML タグ:
<a>/<button>/<input>/<select>/<textarea>/<label>/<summary>/<details>/<option> - ARIA role:
button/link/menuitem/menuitemcheckbox/menuitemradio/tab/option/checkbox/radio/switch/combobox/listbox/slider/spinbutton/textbox/searchbox/treeitem [onclick]/[tabindex>=0]/[contenteditable=true]属性- JavaScript で
addEventListener('click'|'mousedown'|'pointerdown', ...)経由で listener が後付けされた要素(jQuery / vanilla JS / Vue / Svelte の compile 後コードで多用される) - open shadow DOM 内部の上記要素
- iframe 内の上記要素(同一オリジン / cross-origin 共に対応。Stripe Elements / OAuth / reCAPTCHA など)
検出されないもの: closed shadow DOM、<canvas> / WebGL の描画内容、React の onClick={...}(ただし React コンポーネントは大抵 <button> か role="button" を使うので別経路で拾える)。
iframe 内の要素
iframe を含むページの getText の出力は、メインフレームのテキストの後ろに フレームごとのセクション が並ぶ形式になる。メインフレーム本文中には iframe の位置に [[IFRAME ...]] プレースホルダーが残るので、フレームの出現順や種別が把握できる:
これは決済画面です
[[IFRAME name=card title=Card details src=https://js.stripe.com/v3/elements]]
[ボタン] {e3 button "支払う"}
--- iframe f1 url="https://js.stripe.com/v3/elements/..." name="card" ---
{f1.e1 textbox "Card number"}
{f1.e2 textbox "MM / YY"}
{f1.e3 textbox "CVC"}
--- end iframe f1 ---
iframe 内の要素を click / fill / dumpHtml したいときは、frame ID prefix 付きの ref を指定するだけ:
BrowseWeb({
actions: [
{ type: "fill", ref: "f1.e1", value: "4242 4242 4242 4242" },
{ type: "fill", ref: "f1.e2", value: "12 / 30" },
{ type: "fill", ref: "f1.e3", value: "123" },
{ type: "click", ref: "e3" } // メインフレームの「支払う」ボタン
]
})
frame ID (f1, f2, …) は getText 取得時の出現順に採番される。同じページに同じ iframe が複数ある場合は src/name で見分けてセクションヘッダーで識別する。
cross-origin iframe (Stripe / OAuth / reCAPTCHA など) でも Playwright が内部で透過的に DOM を取得するので、同じ感覚で操作できる。ただし iframe の中身が完全に読み込まれる前に snapshot を取ると [empty] や [cannot inspect: ...] が出ることがあるので、その場合は wait を挟んで再取得する。
状態属性
ref 注釈の末尾には ARIA 状態が列挙される。エージェントは「いまトグルが開いてるか」「チェック済みか」「無効化されてるか」を判断できる:
{e3 tab "設定" selected}
{e7 button "保存" disabled}
{e2 combobox "国" expanded haspopup}
{e9 checkbox "規約に同意" checked}
{e5 button "メニュー" pressed}
利用される状態: expanded / collapsed / pressed / selected / checked / mixed / disabled / required / haspopup
ref はいつリセットされる?
- ページ遷移(
gotoまたは click でナビゲーションが発生)したとき - 同一ジョブ内でも、ナビゲーション後は getText を呼んで新しいスナップショットを取得する
- 同一ジョブが終わるとブラウザコンテキストごと破棄される
ワークフロー例
例1: ログインしてダッシュボードのデータを取得
// Step 1: ログインページを開いて要素を確認
BrowseWeb({ url: "https://app.example.com/login" })
// → 出力に {e3: input[email]}, {e4: input[password]}, {e5: button "ログイン"} が含まれる
// Step 2: フォーム入力 → 送信 → 遷移後の状態を取得
BrowseWeb({
actions: [
{ type: "fill", ref: "e3", value: "user@example.com" },
{ type: "fill", ref: "e4", value: "p@ssword" },
{ type: "click", ref: "e5" },
{ type: "getText" } // ← ダッシュボードの新 ref を取得
]
})
// Step 3: ダッシュボードでさらにナビゲート(Cookie が維持されているため再ログイン不要)
BrowseWeb({ url: "https://app.example.com/dashboard/orders" })
例2: 複数ページを順に巡回
// 検索結果ページを開く
BrowseWeb({ url: "https://example.com/search?q=foo" })
// → {e1: link "結果1" href="/item/1"}, {e2: link "結果2" href="/item/2"} ...
// 各リンクの href を確認したら、url 直接指定で各ページへ
BrowseWeb({ url: "https://example.com/item/1" })
BrowseWeb({ url: "https://example.com/item/2" })
例3: 動的ページの読み込み待ち
BrowseWeb({
url: "https://app.example.com/spa",
waitFor: ".content-loaded" // この CSS セレクタが現れるまで待つ
})
ユーザーに手動操作を委譲する(noVNC 経由のハンドオフ)
BrowseWeb で詰まったとき、エージェントは InteractiveBrowse を呼んでブラウザの操作権をユーザーに渡せる。
使うべき場面
- ログイン / 2FA / SSO 同意画面 — パスワードや TOTP / プッシュ通知を agent に持たせず、ユーザーに直接入力してもらう
- CAPTCHA / bot 検証 — reCAPTCHA、画像選択、Cloudflare チャレンジ等
- BrowseWeb の click が空振りし続ける —
dumpHtmlでも構造が複雑すぎて selector が組めない、closed shadow DOM、ドラッグ&ドロップが必須等 - canvas / WebGL ベースの UI — 地図ペインや図形エディタなど DOM では addressable でない領域
- 画面状態を目視確認したい — agent が想定通りの画面にいるか不安なとき
フロー
// Step 1: ユーザーに引き継ぐ宣言
InteractiveBrowse({
url: "https://example.com/login",
reason: "ログインが必要です。ID / パスワードを入力して、画面右下の release ボタンを押してください。"
})
// → ジョブが waiting_human に遷移し、UI に noVNC リンクが表示される
// → ユーザーがブラウザ画面で操作 → release を押すとジョブが再開
// → 戻り値に sessionId が含まれる
ジョブ再開後、agent は 同じ sessionId で BrowseWithSession を呼んで続きを引き継ぐ:
// Step 2: ユーザーが完了させた状態 (ログイン済み等) で続行
BrowseWithSession({
sessionId: "abc-123", // InteractiveBrowse の戻り値の sessionId
url: "https://example.com/dashboard",
action: "getText" // または click / fill / screenshot
})
reason の書き方
ユーザーに何をしてほしいかは reason フィールドで明確に伝えること。UI に表示される。良い例:
- 「ログインしてください。完了したら release を押してください」
- 「reCAPTCHA を解いてください。完了したら release を押してください」
- 「カートに入れたい商品を選んでください。完了したら release を押してください」
制約
InteractiveBrowseは ローカルタスク経由のジョブ でのみ使える(taskIdが必要)。Gitea Issue 直接実行や taskId が立たない subtask root では使えない- noVNC が orchestrator にインストール / 設定されていない環境ではエラー(Xvfb / x11vnc / websockify が必要、
config.yamlのbrowser.display_mode: novnc設定。旧captcha_solveは自動移行) - ユーザーが release を押さない限りジョブは進まない。長時間放置すると
browser.auth_timeout(デフォルト 10 分)で timeout
既存の Browser Sessions 機能との違い
| 機能 | 用途 |
|---|---|
| Browser Sessions (Settings UI から保存) | スケジュール実行や定期タスクなど agent しか動いていない時間帯 に、過去にログイン済みの cookie / storageState を再利用 |
| InteractiveBrowse | ジョブ実行中、その場で ユーザーがブラウザを操作してログインや人間判断を行う |
定期タスクで毎回 InteractiveBrowse を呼ぶのは非効率なので、定常運用のサイトは Browser Sessions として登録するのが正解。「初回ログイン or セッション切れ時だけ InteractiveBrowse」のような使い分けが望ましい。
トラブルシューティング
- 「ref "e5" not found in current snapshot」と出る: ページ遷移後で ref がリセットされている。
getTextで新しいスナップショットを取得する - テキストが取れない / 空に近い: ページが SPA で JavaScript で描画されている。
waitForで描画完了を待つ - ボタンを押せない / click しても何も起きない:
- 要素が visible でない可能性。先に getText で本当に存在するか確認
- ref 注釈に
disabledが出ていないか確認 dumpHtml({ ref: "..." })で要素の生 HTML を見て、独自 selector を組む- それでもダメなら
InteractiveBrowseでユーザーに引き継ぐ
<div>に click 反応する独自 UI が ref に出ない: addEventListener フックで多くは検出されるが、React のonClick={...}(root delegation) やel.onclick = fn直接代入は捕捉できない。dumpHtmlで構造を見て selector を直接組むか、InteractiveBrowseで渡す- ログインが維持されない: 別ジョブから呼んでいる可能性。同一ジョブ内なら維持される。定常運用は Browser Sessions に保存する
ファイルダウンロード
リンククリック等でブラウザがファイルダウンロードを開始すると、自動的に workspace の output/ 配下に保存される。戻り値の末尾に以下の形式で通知される:
[download] saved output/report.csv (12345 bytes)
- ファイル名は server-suggested 名から path traversal 対策と禁則文字置換を経て決定される
- 衝突時は
foo-1.csv,foo-2.csv形式で番号付与される - 失敗時は
[download] FAILED <name>: <reason>と出る - ダウンロードされたファイルは続く
Read,ReadPdf,ReadExcel,Bash等の tool で参照できる - 履歴は
logs/downloads.jsonlに追記される (DownloadFile と同じファイル、source: 'BrowseWeb'フィールドで区別)
ダウンロードを認証付きで行いたい場合は、Browser Sessions 機能で対象サイトのログインセッションを保存し、タスクで bind した状態で BrowseWeb を呼ぶこと。
SSRF 保護
ローカル/プライベート IP(127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x, ::1, fc00::/7 等)へのアクセスはデフォルトでブロックされる。社内ホストへアクセスする必要がある場合は、Settings UI の「SSRF Allowed Hosts」に追加する。