🎯 カスタマイズ可能で検出回避型のクラウドブラウザ。自社開発のChromiumを搭載し、ウェブクローラーAIエージェント向けに設計されています。👉今すぐ試す
ブログに戻ります

ゼロからブラウザエージェントループのコンピュータを構築する

Daniel Kim
Daniel Kim

Lead Scraping Automation Engineer

29-Jul-2026

TL;DR:

  • コンピュータ使用エージェントは、有界な知覚-判断-行動ループに縮約できます。 ブラウザは現在のページをキャプチャし、ビジョンモデルが1つのアクションを選択し、Playwrightがそれを実行した後、サイクルは再び始まります。
  • アクションスキーマはモデル出力を実行可能に保ちます。 各判断をclicktypescroll、またはdoneに制限することで、モデルの応答を小さな決定的ディスパッチャーに変えます。
  • 新鮮なスクリーンショットが古い判断を防ぎます。 各モデル呼び出しでは、前のアクション後のページが表示されるため、エージェントはブラウザの現在の状態から推論します。
  • ステップキャップが自律性とコストの両方を制御します。 この例では、最大4回の反復が許可され、2回で終了します:Nextをクリックし、新しい最初の引用を確認した後に停止します。
  • カスタムループは決定ロジックを可視化する必要がある場合に最適です。 ループが頻繁に調整される必要がなくなったときには、1回の抽出のために単一のビジョン呼び出しを使用し、パッケージ化されたエージェントを使います。
  • 開始は無料。 新しいScrapelessアカウントには、無料のスクレイピングブラウザランタイムが含まれています — app.scrapeless.comでサインアップしてください。

はじめに:コンピュータ使用の背後にある小さなループ

コンピュータ使用エージェントは、画面を見て、1つのアクションを決定し、そのアクションを実行するという3つのことを繰り返します。OpenAIのComputer UseツールやGoogleのGeminiコンピュータ使用モードなどの製品は、そのループを単一のAPI呼び出しの背後にまとめています。Skyvernのようなエージェントフレームワークは、それをタスクランナーの背後にパッケージ化します。どちらの下でも、ループ自体は少量のコードです — スクリーンショット、短いアクションリストに制約されたビジョンモデルの呼び出し、およびモデルが選択したことを実行するブラウザコマンドです。

このガイドでは、パッケージ化されたエージェントを介さずにそのループを直接記述します。それは、Chrome DevTools Protocolを介してScrapeless Scraping Browserに接続し、ページのスクリーンショットを取り、4つの選択肢(クリック、タイプ、スクロール、または完了)を持つビジョン可能なモデルに画像を送信し、Playwrightでモデルが返すものを実行してから繰り返します。以下の各ステップは実際のページに対して実行され、モデルの実際の決定がその時点でキャプチャされます。

ループの概要

各反復には真実の1つのソースがあります:最新のスクリーンショットに表示されるページ。

フェーズ 入力 出力 実装
知覚 現在のブラウザページ フルページPNGスクリーンショット page.screenshot(full_page=True)
判断 目標、アクションスキーマ、スクリーンショット 1つのJSON決定 ビジョンモデルリクエスト
行動 検証済みの決定 ブラウザの状態変更 Playwrightのクリック、入力、またはスクロール
停止または繰り返し 新しいブラウザ状態 doneまたは別の反復 max_stepsで制約されたループ

ウォークスルーでは、公共の引用サイトと狭い目標を使用し、最初の引用がアルバート・アインシュタインによって書かれたときのみ最初のページを離れ、別の著者が現れたらすぐに停止します。

ループを自分で構築する理由

ループを直接記述することで、知覚フォーマット、アクション語彙、および停止ルールを制御できます。

構造化されたスナップショットエージェントとパッケージ化されたビジョンフレームワークは、同じ問題をより高いレベルで解決します。最初のものは、WAI-ARIAアクセシビリティツリーから構築された役割、ラベル、および状態のツリーをLLMに渡すことができ、これはクリーンなマークアップのページでより安価で正確です。Scraping Browserで実行されるブラウザ使用はその道を辿ります — 同じCDP接続を介して同じクラウドChromiumを駆動しますが、そのエージェントは抽出されたページテキストに基づいて推論します。

もう1つのショートカットは、パッケージ化されたビジョンフレームワークに全体のループを渡します。これは、スクリーンショットを取り、推論し、行動する点では、このウォークスルーと同じですが、プロンプト、アクションスキーマ、および決定コードは、呼び出しスクリプトではなくライブラリ内にあります。

カスタム決定のすべての部分が可視化され、編集可能です:アクション語彙、1つのアクションを要求するプロンプト、ステップキャップ、および決定をPlaywrightの呼び出しに変える行。異なる目標、ターゲット、またはモデルは、フレームワーク全体の構成面ではなく、スクリプトの1つの部分を変更します。

前提条件

Python 3.9以降、playwrightおよびrequestsパッケージ、ブラウザセッション用のScrapeless APIキー、およびビジョン対応モデル用のキーが必要です。無料プランでScrapelessキーを取得できます。以下の例では、モデル呼び出しはOpenRouterを介してルーティングされ、1つのキーと1つのエンドポイントの背後に複数のモデルプロバイダーをフロントします。

プロジェクトのセットアップ

依存関係のインストール

bash Copy
pip install playwright requests

APIキーの構成

bash Copy
export SCRAPELESS_API_KEY="your_scrapeless_api_key"
Copy
export OPENROUTER_API_KEY="モデルのAPIキーを入力"

知覚・決定・行動ループの構築

完全なスクリプトはリモートブラウザに接続し、4つのアクション契約を定義し、モデルが done を返すかステップ制限に達するまで契約を実行します。

リモートブラウザへの接続

スクレイピングブラウザはWebSocket接続を介して1つのCDPエンドポイントを公開します。WebSocketプロトコルChrome DevTools Protocolのトラフィックを双方向で運びます。Playwrightの connect_over_cdp は、デバッグポートを開いたローカルChromiumインスタンスに接続する方法と同じように、そのエンドポイントに接続します。ブラウザ自体はこのスクリプトを実行しているマシンではなく、Scrapelessのクラウドで実行されます。Playwrightプロキシガイドは、同じリモートCDP接続パターンについてより詳細に説明しています。

決定契約の定義

3つの関数がループの3つの部分を担っています:perceive はスクリーンショットを取得し、decide はそれをモデルに送信し、返信を解析し、act はその返信をPlaywrightの呼び出しに変換します。プロンプトはモデルに小さなJSONオブジェクトを固定フィールド順に埋めるように指示します。画像から具体的な事実を1つ挙げてからアクションを選ぶことで、決定が実際にスクリーンショットが示す内容に基づいていることが保たれます。

完全な例を実行する

python Copy
import os
import json
import base64
import requests
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright

GOAL = (
    '目標: 第一の引用カードが「アルバート・アインシュタイン」によって書かれていないページに移動する。 '
    '最初の引用カードの著者名を読む。もしそれが「アルバート・アインシュタイン」であれば、「次へ」という '
    'ページネーションリンクをクリックします。そうでなければ、目標はすでに達成されています。'
)
SCHEMA_PROMPT = (
    GOAL + "\n\nJSONオブジェクトのみで応答し、すべてのフィールドを順に埋めてください:\n"
    '{"first_quote_author": "<最初の引用カードの著者名、画像から読み取ったもの>", '
    '"action": "click" | "type" | "scroll" | "done", '
    '"target": "<クリックまたは入力する要素の可視テキスト、スクロール/完了の場合は省略>", '
    '"value": "<入力するテキスト、アクションが型の場合のみ>", '
    '"reason": "<8単語未満>"}'
)

def browser_url():
    return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
        {"token": os.environ["SCRAPELESS_API_KEY"], "sessionTTL": 180, "proxyCountry": "US"})

def perceive(page):
    return page.screenshot(full_page=True)

def decide(png_bytes):
    img = "data:image/png;base64," + base64.b64encode(png_bytes).decode()
    resp = requests.post(
        "https://openrouter.ai/api/v1/chat/completions",
        headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}", "Content-Type": "application/json"},
        json={"model": "google/gemini-2.5-flash-lite",
              "messages": [{"role": "user", "content": [
                  {"type": "text", "text": SCHEMA_PROMPT},
                  {"type": "image_url", "image_url": {"url": img}}]}],
              "temperature": 0, "max_tokens": 300},
        timeout=120,
    )
    resp.raise_for_status()
    return json.loads(resp.json()["choices"][0]["message"]["content"])

def act(page, decision):
    action = decision["action"]
    if action == "click":
        page.get_by_text(decision["target"], exact=False).first.click(timeout=5000)
        page.wait_for_load_state("networkidle")
    elif action == "type":
        page.get_by_text(decision["target"], exact=False).first.fill(decision["value"], timeout=5000)
    elif action == "scroll":
        page.mouse.wheel(0, 900)
        page.wait_for_timeout(300)
    return action

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(browser_url())
    page = browser.new_page(viewport={"width": 1280, "height": 900})
    page.goto("https://quotes.toscrape.com/", wait_until="networkidle")

    max_steps = 4
    for step in range(1, max_steps + 1):
        decision = decide(perceive(page))
        print(f"ステップ {step}: 著者={decision['first_quote_author']!r} "
              f"アクション={decision['action']} 理由={decision['reason']!r}")
        if decision["action"] == "done":
            break
        act(page, decision)

    print("最終URL:", page.url)
    print("取ったステップ:", step)
    browser.close()

無料プランでAPIキーを取得する: app.scrapeless.com

実行の確認

ライブページに対して、例は一度ナビゲートされ、次のイテレーションで停止しました:

text Copy
ステップ 1: 著者='アルバート・アインシュタイン' アクション=クリック 理由='初めの引用の著者はアルバート・アインシュタインなので、次をクリックする必要があります。'
ステップ 2: 著者='マリリン・モンロー' アクション=完了 理由='最初の引用はアルバート・アインシュタインによるものではありません。'
最終URL: https://quotes.toscrape.com/page/2/
取られたステップ: 2

2ステップの意思決定を追跡する

トレースは、各アクションの後にループが新しいスクリーンショットを必要とする理由を示しています。

ステップ 1: 最初のカードを読み、次をクリックする

ステップ1はフロントページのスクリーンショットを撮り、モデルは最初の引用カードから「アルバート・アインシュタイン」を読み取ります — 同じ画像を見ている誰でも確認できる事実です — そして {"action": "click", "target": "Next →"} を返します。act 関数はそのターゲットを page.get_by_text("Next →", exact=False) で解決し、DOMに対して直接書かれたスクリプトが使用するのと同じロケーターパターンでクリックします。このクリックにより /page/2/ にナビゲートされます。

ステップ 2: 新しい状態を確認し、停止する

ステップ2は新しいページのスクリーンショットを撮ります。最初の引用カードは今やマリリン・モンローに属しており、モデルはその事実を報告し、返されるアクションは done です。ループは4つの割り当てられたステップのうちの2つが終わると自動的に終了します — キャップに到達する必要はなく、スクロールアクションも必要ませんでした。なぜなら、perceive が一枚の画像にフルページをキャプチャするからであり、表示されているビューポートだけではないからです。ユーザーがスクロールすることでより多くのコンテンツが読み込まれるページ — 無限スクロール、遅延読み込みセクション — では、フルページキャプチャはまだ読み込まれていないコンテンツを見ることができません。これが、scroll がアクションの語彙に残っている理由です。このターゲットがそれをトリガーしないとしてもです。type ブランチも同様に機能し、target に一致する要素を value で満たします;このウォークスルーの目標はフォームフィールドを必要としないため、そのブランチはこの特定の実行を行わずに同一のディスパッチロジックを実行します。

ループを制限し最新の状態に保つ

このようなループがルーズにならないための2つのデザイン選択があります。max_steps の制限により、done を返さないモデルでも自発的に停止します。また、スクリーンショットと単一の意思決定のサイクルにより、ループは古い情報に基づいて行動することはありません — 各決定はその瞬間に存在するページに対して行われ、前回の確認から何が変わったかについての仮定に対してではありません。

正しいブラウザエージェントの形を選択する

適切なアプローチは、タスクが1回の観察を必要とするか、いくつかの観察を必要とするか、また意思決定ロジックの検査が必要かどうかによって異なります。

アプローチ 最適 意思決定に対するコントロール 主なトレードオフ
単一視覚呼び出し 安定したスクリーンショットから値を読み取る 高いが、ブラウザアクションはなし ページ変更後に適応できない
カスタムスクリーンショットループ 複数のステップを通じてブラウザ状態に到達する プロンプト、アクション、および停止条件に対する完全なコントロール 検証とオーケストレーションは自分のもの
パッケージエージェント 多くの目標とページにわたって安定したループを再利用する フレームワーク依存 速い統合、ループに対する可視性が低い

単一視覚呼び出しは1つのスクリーンショットを読み取り、アクションを取らずに構造化データを返します。LLMスクレーパーが何をするかはより広い抽出パターンをカバーしています。その形を使用するのはタスクが単純に値を読み取る場合です。

カスタムループは、目標を満たすために1回以上の確認が必要な場合に使用されます。各スクリーンショットは前のアクションに依存しており、正確な意思決定ロジックは検査および変更可能なコード内に残ります。

パッケージエージェントフレームワークは、同じループ — またはBrowser Useの場合のテキストベースのバリアント — をタスクランナーの背後にラップします。この取引は、ループの形が安定し、主な仕事が多くのページに対して多くの目標を実行することになると有用です。

結論: ループを小さく、観察可能に保つ

「コンピュータ使用」エージェントのメカニズムは、スクリーンショット、短いアクションリストに制約されたビジョンモデル呼び出し、および結果を実行するブラウザコマンドです。このサイクルは、モデルが目標を達成したと報告するまで、またはステップキャップに達するまで繰り返されます。

上記の実行では、アルバート・アインシュタインによって前面に立たされたページから、マリリン・モンローによって前面に立たされたページに移動するのに2回のターンがかかりました。モデルの決定は各ステップで可視であり、実行されたPlaywrightコールは通常のアプリケーションコードとして残り続けました。

ランタイムが提供するものをスクレイピングブラウザ製品ページで読み込み、ステップ数とモデルコストを価格ページで比較検討してから、このようなループを数目標以上にスケーリングすることを検討してください。


ブラウザエージェントループを構築する準備はできましたか?

私たちのコミュニティに参加して、無料プランを請求し、ブラウザエージェントを構築している他の開発者と情報を交換しましょう:Discord · Telegram

app.scrapeless.com に登録して、無料のスクレイピングブラウザランタイムを入手し、制約されたループを公開ページと検証可能な目標に適応させましょう。


よくある質問

Q: コンピュータ使用スタイルのブラウザエージェントループとは何ですか?

コンピュータ使用スタイルのブラウザエージェントループは、目標が達成されるまで繰り返される3つのステップのサイクルです:ページをスクリーンショットで認識し、そのスクリーンショットを視覚的モデルに送信し、一つのアクションを決定し、その決定を実際のブラウザコマンドで実行します。OpenAIのコンピュータ使用ツールとGoogleのGeminiコンピュータ使用モードは、同じサイクルをホストされたAPIの背後にパッケージ化しています。

Q: これがSkyvernやBrowser Useを同じブラウザで実行することと何が違うのですか?

これらのフレームワークは内部で同じ種類のループを実行しますが、プロンプト、アクションスキーマ、および決定コードはライブラリ内に存在します。このウォークスルーでは、これらの3つの要素を直接記述し、決定の各部分がフレームワークの構成表面ではなく、呼び出しスクリプト内で可視化および編集可能です。

Q: これは単一のスクリーンショットからJSON抽出呼び出しとどう違うのですか?

単一の視覚呼び出しは1つの画像を読み取り、データを返しますが、アクションは実行されずループもありません。このウォークスルーは、モデルが目標が達成されたと報告するまで、認識、決定、実行を繰り返し、各ステップのスクリーンショットは前のステップのアクションの結果を反映します。

Q: なぜモデルの応答を自由形式の指示ではなく、固定のアクションスキーマに制限するのですか?

小さく固定された語彙(クリック、入力、スクロール、完了)は、モデルの応答を呼び出しコードが決定論的に処理できるものに変換します。制約のない応答は、安全にブラウザを操作する前に独自の解析および解釈レイヤーを必要とします。

Q: ループがアクションを選択する前に、モデルに具体的な事実を示させる理由は何ですか?

モデルに画像からチェック可能な詳細を述べるよう求めることで(この例では最初のカードの著者)、アクションが実際にスクリーンショットに表示されているものに基づいています。目標が達成されたかどうかをオープンに推論させるフィールドは、目の前の画像からそれてしまう可能性が高くなります。

Q: なぜ可視部分だけでなく、フルページのスクリーンショットを取るのですか?

そうすることで、モデルは長いリストの下部にあるページネーションリンクなど、折り返しの下にある要素を最初に専用のスクロールステップなしで見ることができます。ユーザーがスクロールするとのみ追加コンテンツが読み込まれるページ(無限スクロールや遅延読み込みセクション)は、フルページのキャプチャが不足するケースであり、スクロールアクションがループ内での位置を得る理由です。

Q: なぜステップ数を制限するのですか?

max_stepsは、単一の目標が実行できる認識-決定-実行サイクルの数を制限しますので、決してdoneを返さないモデルでも無限に動作するのではなく、停止します。各ステップは1つのスクリーンショットと1つのモデル呼び出しであり、したがって制限は実行のコストも制約します。

Q: この例ではどの視覚モデルを使用しており、別のモデルに置き換えることはできますか?

この例は、OpenRouterを介してgoogle/gemini-2.5-flash-liteにルーティングされます。同じチャット補完の形で到達可能な視覚モデルのいずれかが、modelフィールドを変更することで置き換えることができます。

Q: このようなループを実際のサイトに向けるのは安全ですか?

はい、ターゲットが公開されていて、ステップ数が制限されており、目標がログイン、支払い、プライベートデータを除外する場合は安全です。上記の例は、スクレイピングの練習用に構築された公開の引用サイトに対して2つの制約付きステップを実行します。

Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。

最も人気のある記事

カタログ