コンピュータアクセスシステム

Web自動化エージェント:ClaudeとComputer Useによるブラウザ制御


Web自動化エージェント:ClaudeとComputer Useによるブラウザ制御

あなたの会社は、APIのないサプライヤーポータルからデータを取得する必要があります。それは動的コンテンツ、複数ステップのフォーム、そして数ヶ月ごとに変わるレイアウトを持つWebアプリです。Seleniumスクリプトは、CSSが更新されるたびに壊れます。レガシーコードのようにメンテナンスし続けています — 脆く、コストがかかり、誰も触りたがりません。

ビジョンベースのエージェントはCSSセレクタを気にしません。ページを見て、「検索」ボタンを視覚的に見つけ、クリックし、結果テーブルを読み取り、データを抽出します。レイアウトが変わっても、エージェントは適応します。なぜなら、人間のようにページを読んでいるからです — DOMを解析しているのではありません。

この記事では、Claudeのコンピュータ操作機能を使ってWeb自動化エージェントを構築する方法を解説します。ビジュアル自動化の基本的な仕組み、信頼性の高いナビゲーションパターン、データ抽出テクニック、フォーム入力ワークフロー、エラー回復戦略を学びます。記事を読み終える頃には、シンプルなページ読み取りから複雑なマルチステップワークフローまで、あらゆるWebインターフェースと対話するエージェントを構築するために必要なパターンが身につきます。


ビジュアル自動化 vs. 従来の自動化

ビジョンベースのエージェントを構築する前に、どのような場合に適しているか — そしてどのような場合に適さないかを理解する必要があります。SeleniumやPlaywrightなどの従来の自動化ツールはなくなりません。高速で、決定論的で、よく理解されています。問題は、それぞれのアプローチがどこで優れ、どこで限界を迎えるかです。

従来の自動化(Selenium/Playwright)

従来のブラウザ自動化はDOMとのやり取りで動作します。CSSセレクタやXPath式を使って要素を特定し、プログラム的に操作を実行します:

# 従来のアプローチ — 高速だが脆い
search_input = driver.find_element(By.CSS_SELECTOR, "#search-box-v3 > input.query")
search_input.send_keys("industrial bearings")
driver.find_element(By.CSS_SELECTOR, "button.search-submit-2024").click()

これは高速です。決定論的です。そして、誰かがsearch-box-v3search-box-v4に名前変更したり、フォームのレイアウトを再構成した瞬間に壊れます。サイトの内部構造を反映したセレクタのマッピングを維持することになります — それはあなたがコントロールできない構造です。

従来の自動化は、ビジュアルのみのコンテンツも処理できません。必要なデータが<canvas>要素でレンダリングされていたり、画像に埋め込まれていたり、ブラウザ内でPDFとして表示されていたりする場合、DOMセレクタではアクセスできません。

ビジョンベースの自動化(Computer Use)

ビジョンベースの自動化は、人間と同じように動作します。エージェントはスクリーンショットを受け取り、必要な要素を視覚的に特定し、特定の座標にマウス/キーボードアクションを発行します:

# ビジョンベースのアプローチ — 回復力があるが低速
# エージェントはページを見て、検索ボックスを視覚的に見つけ、入力する
# セレクタ不要 — レイアウトの変更に自動的に適応

トレードオフ:低速で(各アクションに画像付きのAPIコールが必要)、高コストで(スクリーンショットのトークン)、非決定論的です(エージェントは実行ごとにスクリーンショットを異なる解釈をする可能性があります)。しかし、レイアウトの変更に強く、あらゆるビジュアルインターフェースで動作し、ページコンテンツを意味的に理解できます。

ハイブリッドアプローチ

最も実用的な戦略は両方を組み合わせることです:

  • 従来の自動化を使用する — 安定した、構造化されたページで、インターフェースを自分でコントロールしているか、めったに変更されない場合。
  • ビジョンベースの自動化を使用する — 動的なページ、馴染みのないインターフェース、ビジュアルコンテンツ、またはスクリプトをメンテナンスする価値のない一回限りのタスクの場合。
  • ビジョンをフォールバックとして使用する — まずセレクタを試し、失敗した場合に視覚的な識別にフォールバックする。

ビジョンを選ぶべき場合

ビジョンベースの自動化が適切な選択となるのは:

  • APIが利用できない場合で、Webインターフェースが唯一のオプションの場合
  • ページレイアウトが頻繁に変更される場合で、セレクタのメンテナンスコストが高すぎる場合
  • コンテンツがビジュアルの場合 — チャート、画像、canvas要素、埋め込みPDF
  • マルチステップワークフローにコンテキストが必要な場合 — 画面の内容を理解して次のアクションを決定する場合
  • 一回限りの自動化で、メンテナンスされたSeleniumスクリプトのエンジニアリングコストを正当化できない場合
  • 馴染みのないインターフェースで、セレクタをマッピングするよりも自然言語でタスクを記述できる場合

Claude Computer Useの基本

Claudeのコンピュータ操作機能により、モデルは人間と同じ方法でコンピュータ画面と対話できます — スクリーンショットを見て、マウスとキーボードのアクションを発行します。信頼性の高いエージェントを構築する前に、この仕組みを理解することが不可欠です。

動作の仕組み

コンピュータ操作のループはシンプルです:

  1. 現在の画面(またはブラウザウィンドウ)のスクリーンショットをキャプチャする
  2. スクリーンショットをタスクの説明とともにClaudeに送信する
  3. ツールコールを受信する — Claudeが実行すべきアクション(クリック、入力、スクロール)を伝える
  4. ブラウザでアクションを実行する
  5. 新しいスクリーンショットをキャプチャする
  6. タスクが完了するか、エージェントが完了を知らせるまで繰り返す

Claudeはブラウザを直接制御しません。あなたのコードが仲介者として機能し、モデルからの指示を受け取り、実際の環境で実行します。

ツール定義

コンピュータ操作は、利用可能なアクションを記述する特定のツール定義 — computer_20241022 — に依存しています:

computer_tool = {
"type": "computer_20241022",
"name": "computer",
"display_width_px": 1280,
"display_height_px": 800,
"display_number": 1,
}

利用可能なアクションには以下が含まれます:

  • screenshot — 現在の画面状態をキャプチャする
  • mouse_move — カーソルを特定の座標に移動する
  • left_click / right_click / double_click — 現在のカーソル位置でクリックする
  • left_click_drag — クリックしてターゲット位置までドラッグする
  • type — テキスト文字列を入力する
  • key — 特定のキーまたはキーの組み合わせを押す(例:Returnctrl+a
  • scroll — 現在のカーソル位置で上下にスクロールする

アクションループ

以下は、コアとなるコンピュータ操作ループの完全な実装です:

import anthropic
import base64
import subprocess
import time
client = anthropic.Anthropic()
def capture_screenshot() -> str:
"""Capture screen and return base64-encoded PNG."""
# Using scrot for X11; adapt for your environment
subprocess.run(["scrot", "/tmp/screenshot.png"], check=True)
with open("/tmp/screenshot.png", "rb") as f:
return base64.standard_b64encode(f.read()).decode("utf-8")
def execute_action(action: dict):
"""Execute a computer use action using xdotool."""
action_type = action.get("action")
if action_type == "screenshot":
return # Screenshot will be taken in the main loop
elif action_type == "mouse_move":
x, y = action["coordinate"]
subprocess.run(["xdotool", "mousemove", str(x), str(y)])
elif action_type == "left_click":
x, y = action["coordinate"]
subprocess.run(["xdotool", "mousemove", str(x), str(y)])
subprocess.run(["xdotool", "click", "1"])
elif action_type == "type":
text = action["text"]
subprocess.run(["xdotool", "type", "--clearmodifiers", text])
elif action_type == "key":
key = action["key"]
subprocess.run(["xdotool", "key", key])
elif action_type == "scroll":
x, y = action["coordinate"]
direction = action["direction"]
amount = action["amount"]
subprocess.run(["xdotool", "mousemove", str(x), str(y)])
button = "5" if direction == "down" else "4"
for _ in range(amount):
subprocess.run(["xdotool", "click", button])
time.sleep(0.5) # Brief pause after each action
def run_computer_use_agent(task: str, max_steps: int = 50):
"""Run a computer use agent loop."""
messages = [{"role": "user", "content": task}]
for step in range(max_steps):
# Capture current screen state
screenshot_b64 = capture_screenshot()
# Add screenshot to the conversation
if step > 0:
messages.append({
"role": "user",
"content": [{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": screenshot_b64,
},
}],
})
# Call Claude with computer use tool
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
tools=[computer_tool],
messages=messages,
)
# Process response
messages.append({"role": "assistant", "content": response.content})
# Check if the agent is done
if response.stop_reason == "end_turn":
# Extract final text response
for block in response.content:
if hasattr(block, "text"):
return block.text
return "Task completed."
# Execute tool calls
tool_results = []
for block in response.content:
if block.type == "tool_use":
print(f"Step {step}: {block.input.get('action')} "
f"{block.input.get('coordinate', '')}")
execute_action(block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": "Action executed successfully.",
})
messages.append({"role": "user", "content": tool_results})
return "Max steps reached."

解像度と座標系

Claudeは、ツール定義で指定したスクリーンショットの寸法に基づいて、視覚コンテンツをx,yピクセル座標にマッピングします。いくつかの重要な詳細:

  • ディスプレイの解像度を合わせる — ツール定義のdisplay_width_pxdisplay_height_pxを一致させてください。不一致があると、クリックが間違った場所に着地します。
  • 低解像度の方が良い。 1280×800のスクリーンショットは、テキストを読みUI要素を識別するのに十分な詳細を提供しながら、トークンコストを管理しやすく保ちます。4Kのスクリーンショットは送らないでください。
  • 座標は絶対値 — (0, 0)は画面の左上隅です。

信頼性の高いナビゲーションパターン

実際のWebサイトは煩雑です。ページは非同期にロードされ、ポップアップは予測不能に表示され、動的コンテンツはインタラクション中にレイアウトを変更します。信頼性の高い自動化エージェントには、これらすべてを処理するパターンが必要です。

ロード待機

Web自動化で最もよくあるミス — 従来の自動化でもビジュアル自動化でも — は、ページの準備ができる前にアクションを実行することです。固定のtime.sleep()呼び出しを使わないでください。代わりに、ページの状態を視覚的に確認します:

def wait_for_page_load(
client: anthropic.Anthropic,
expected_content: str,
max_retries: int = 5,
delay: float = 2.0,
) -> bool:
"""Wait for a page to load by checking for expected visual content."""
for attempt in range(max_retries):
screenshot_b64 = capture_screenshot()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=256,
messages=[{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": screenshot_b64,
},
},
{
"type": "text",
"text": (
f"Is this page fully loaded and showing: "
f"'{expected_content}'? "
f"Reply with only 'yes' or 'no'."
),
},
],
}],
)
answer = response.content[0].text.strip().lower()
if "yes" in answer:
return True
print(f"Page not ready (attempt {attempt + 1}/{max_retries}). Waiting...")
time.sleep(delay)
return False

ポップアップ処理

Cookieバナー、通知ダイアログ、チャットウィジェットは、Web自動化の天敵です。ビジョンベースのエージェントはこれらを自然に処理します:

def dismiss_popups(client: anthropic.Anthropic) -> bool:
"""Check for and dismiss any popup overlays."""
screenshot_b64 = capture_screenshot()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=

関連記事