Claude CodeでPlaywrightとBrowser Useを使うブラウザ自動操作ガイド

Claude CodeでPlaywrightとBrowser Useを使うブラウザ自動操作ガイド AI開発

Claude Codeを使った開発の中で、「Webページの情報を自動で取得したい」「ブラウザ操作を自動化して作業を効率化したい」というニーズは日常的に発生します。そのような場面で強力な選択肢となるのが、PlaywrightBrowser Useの2つのツールです。

Playwrightは従来型の確定的なブラウザ自動化ライブラリです。セレクタを明示的に指定してDOMを操作するため、動作が安定しており高速です。一方、Browser UseはLLMを活用したAIエージェント型のブラウザ操作ライブラリで、自然言語でタスクを指示するだけで、AIが自律的にページを解析しながら操作を進めます。

この記事では、PlaywrightとBrowser UseをClaude Codeと連携させる方法を、実際のコード例と合わせて詳しく解説します。それぞれの特性と使い分けを理解することで、ブラウザ自動操作の効率を大幅に高めることができます。

この記事で学べること
・PlaywrightとBrowser Useの根本的な違い
・Claude Codeとの連携方法(MCP・CLI・Skills)
・トークン効率の比較と節約テクニック
・どちらを使うべきかの判断フロー
・両者を組み合わせたハイブリッドアプローチの実装
スポンサーリンク

PlaywrightとBrowser Use:根本的な違い

2つのツールは「ブラウザを操作する」という目的は同じですが、アーキテクチャが根本的に異なります。

項目 Playwright Browser Use
操作モデル 命令型(セレクタ指定) エージェント型(自然言語指示)
DOM知識 開発者が構造を知る必要あり AIがページを解析して判断
UI変更への耐性 セレクタ変更でスクリプト破綻 自動的に適応
実行速度 高速(1〜3秒/ページ) 中速(2〜8秒/ページ)
成功率の目安 既知ページで100% 未知ページで70〜85%程度
LLMトークンコスト なし(AI不使用) タスクに応じて変動
主な用途 テスト自動化・定型処理 探索的作業・変動するUI
使い分けの基本原則
UIが安定していて処理が定型的 → Playwright
UIが変動する・探索的なタスク → Browser Use
両方が必要な複雑な処理 → ハイブリッドアプローチ

Playwrightのセットアップと基本操作

インストール

Terminal
pip install playwright
playwright install          # Chromium / Firefox / WebKit をダウンロード
playwright install chromium # Chromium のみの場合

基本的な同期APIの使い方

Playwrightには同期API(sync_api)と非同期API(async_api)の2種類があります。スクリプトで手軽に使うなら同期APIが便利です。

playwright_basic.py
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()

    # ページに移動
    page.goto("https://example.com")

    # テキスト入力
    page.fill('input[name="q"]', "Python playwright")

    # クリック
    page.click('button[type="submit"]')

    # ページ遷移を待機
    page.wait_for_url("**/search**")

    # テキスト取得(inner_text: 表示されている文字のみ)
    title = page.title()
    print(f"ページタイトル: {title}")

    # スクリーンショット保存
    page.screenshot(path="result.png")

    browser.close()
inner_text() と text_content() の違い
inner_text(): CSSで非表示の要素を除いた、実際に表示されているテキストを取得します。
text_content(): 非表示要素も含めた全テキストを取得します。
スクレイピングでは通常 inner_text() を使うのが自然な結果を得やすいです。

よく使うメソッド一覧

メソッド 用途
goto(url) URLに移動 page.goto("https://example.com")
fill(selector, value) テキスト入力 page.fill("input#email", "test@example.com")
click(selector) 要素をクリック page.click("button[type=submit]")
get_by_role(role) セマンティック選択 page.get_by_role("button", name="送信").click()
wait_for_selector() 要素の出現待機 page.wait_for_selector(".loaded")
query_selector_all() 複数要素取得 page.query_selector_all("li.item")
inner_text() 表示テキスト取得 el.inner_text()
screenshot() スクリーンショット page.screenshot(path="out.png")

非同期APIによる並列処理

複数ページを同時に処理する場合は非同期APIが有効です。処理速度を大幅に向上させることができます。

playwright_async.py
import asyncio
from playwright.async_api import async_playwright

async def scrape_page(browser, url):
    page = await browser.new_page()
    await page.goto(url)
    title = await page.title()
    await page.close()
    return title

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()

        # 3ページを並列処理
        urls = [
            "https://example.com/page1",
            "https://example.com/page2",
            "https://example.com/page3",
        ]
        tasks = [scrape_page(browser, url) for url in urls]
        titles = await asyncio.gather(*tasks)

        for url, title in zip(urls, titles):
            print(f"{url}: {title}")

        await browser.close()

asyncio.run(main())

Browser Useのセットアップと基本操作

Browser UseはPlaywrightをベースに、LLMによる自律的な意思決定を組み合わせたライブラリです。高レベルのタスク(「GitHubでbrowser-useのスター数を調べて」など)を自然言語で指示するだけで、AIがページを解析しながら操作を進めます。

インストール

Python 3.11以上が必要です
Browser UseはPython 3.11+を必須としています。python --version で事前に確認してください。
Terminal
# uvを使う場合(推奨)
uv add browser-use langchain-anthropic   # browser-use + Claude用LangChainアダプタ

# pipを使う場合
pip install browser-use langchain-anthropic
playwright install  # ブラウザのインストール(browser-use内部でPlaywrightを使用)
ANTHROPIC_API_KEYの設定が必要です
Browser UseでClaudeを使うには環境変数 ANTHROPIC_API_KEY を設定してください。
export ANTHROPIC_API_KEY="sk-ant-..."(macOS/Linux)
set ANTHROPIC_API_KEY=sk-ant-...(Windows)

基本的なエージェントの使い方

browser_use_basic.py
import asyncio
from browser_use import Agent
from langchain_anthropic import ChatAnthropic

async def main():
    # langchain_anthropic の ChatAnthropic でClaudeを指定
    llm = ChatAnthropic(model="claude-sonnet-4-6")

    agent = Agent(
        task="GitHubでbrowser-useリポジトリのスター数を調べてください",
        llm=llm,
    )

    # エージェントを実行(自律的にブラウザを操作して結果を返す)
    result = await agent.run()
    print(result.final_result())

asyncio.run(main())

コード内でタスクを自然言語で記述するだけで、エージェントが自律的にブラウザを操作して結果を返します。セレクタやDOM構造の知識は一切不要です。

カスタムアクションの追加

Browser UseのControllerを使うと、独自のアクションをエージェントに追加してドメイン固有の処理を組み込めます。

browser_use_custom_action.py
import asyncio
from browser_use import Agent, Controller
from langchain_anthropic import ChatAnthropic

# カスタムアクションを登録するコントローラー
controller = Controller()

@controller.action("現在のページからすべての価格情報を抽出する")
async def extract_prices(browser) -> list:
    """テーブルの価格データを構造化して返す"""
    page = await browser.get_current_page()
    rows = await page.query_selector_all("table tbody tr")

    prices = []
    for row in rows:
        cells = await row.query_selector_all("td")
        if len(cells) >= 2:
            name  = await cells[0].inner_text()
            price = await cells[1].inner_text()
            prices.append({"プラン": name.strip(), "価格": price.strip()})

    return prices


async def main():
    llm = ChatAnthropic(model="claude-sonnet-4-6")

    agent = Agent(
        task="料金ページを開いて全プランの価格を抽出してください",
        llm=llm,
        controller=controller,   # カスタムアクションを渡す
    )

    result = await agent.run()
    print(result.final_result())

asyncio.run(main())
カスタムアクション実装のポイント
@controller.action("説明") デコレータでエージェントに利用可能なアクションとして登録します
・アクションの説明文はLLMが「いつ呼ぶべきか」を判断する材料になるため、具体的に書きましょう
browser 引数でPlaywrightのページオブジェクトにアクセスできます
・返り値はそのままエージェントの結果として使用されます

Claude Codeとの連携:3つのアプローチ

PlaywrightをClaude Codeで使う方法は主に3つあります。それぞれトークン効率と柔軟性のトレードオフが異なります。Claude Code MCPガイドも参考にしてください。

① MCPサーバー経由(手軽だがトークン消費が多い)

Terminal
# Playwright MCPサーバーをClaude Codeに登録
claude mcp add playwright npx @playwright/mcp@latest

# プロジェクトスコープで登録する場合
claude mcp add playwright npx @playwright/mcp@latest --scope project

MCP経由では、アクセシビリティツリーやスクリーンショットがコンテキストに流れ込みます。手軽に使える反面、複数回操作するとコストが急増するため、試作段階での利用が向いています。

② CLIアプローチ(トークン効率が高い)

Terminal
npm install -g @playwright/cli@latest
playwright install

CLI経由では結果がファイルとして保存され、コンテキストに直接流れません。MCP比でトークン消費を大幅に削減できるため、繰り返し利用する場面に適しています。

③ Pythonスクリプト + Skills(最も効率的)

Pythonスクリプトとして実装し、Claude Code Skillsとして登録するのが最も柔軟で効率的なアプローチです。スクリプトの実行結果はファイル経由で受け取るため、トークン消費を最小化できます。

browser_skill.py(Skillとして登録)
#!/usr/bin/env python3
"""
Claude Code Skill: ブラウザ自動操作
使い方: python browser_skill.py <url> <action>
action: title | screenshot | html
"""
import sys, json, asyncio
from playwright.async_api import async_playwright

async def execute(url: str, action: str) -> dict:
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto(url, wait_until="domcontentloaded")

        result = {}
        if action == "screenshot":
            await page.screenshot(path="/tmp/screenshot.png")
            result = {"file": "/tmp/screenshot.png"}
        elif action == "title":
            result = {"title": await page.title()}
        elif action == "html":
            with open("/tmp/page.html", "w", encoding="utf-8") as f:
                f.write(await page.content())
            result = {"file": "/tmp/page.html"}

        await browser.close()
        return result

if __name__ == "__main__":
    url    = sys.argv[1] if len(sys.argv) > 1 else "https://example.com"
    action = sys.argv[2] if len(sys.argv) > 2 else "title"
    print(json.dumps(asyncio.run(execute(url, action)), ensure_ascii=False))
アプローチ トークン消費目安 柔軟性 セットアップ 推奨場面
MCPサーバー 大(要注意) 1コマンド 手軽に試したいとき
CLI 中(MCPの1/4程度) npm install 定型的な操作
Skills 最小(ファイル読取のみ) 最高 スクリプト作成 本番利用・繰り返し処理

トークン効率の実態と節約テクニック

Claude Codeでブラウザ自動操作を行う際、トークン消費は無視できないコスト要因です。アプローチによって消費量が大きく変わります。Claude Codeのコスト管理についても合わせて確認しておくと良いでしょう。

シナリオ Playwright MCP Playwright CLI Browser Use
1ページ処理 ※ 約114,000トークン 約27,000トークン 約40,000トークン
10ページ連続処理 ※ 約1,140,000トークン 約270,000トークン 約400,000トークン
複雑な探索タスク ※ 約200,000トークン 約45,000トークン 約60,000トークン

※ トークン数はページの複雑さ・使用モデル・ブラウザの描画状況により変動します。上記は標準的なWebページを操作した際の参考値です。

上記の数値はページの複雑さやモデルのバージョンによって変動します。目安として参考にしてください。MCPではアクセシビリティツリーとスクリーンショットがコンテキストに追加されるため、ページが複雑になるほど消費トークン数も増加します。
トークン節約の4つのポイント
① MCPよりCLI/Skillsを使う(大幅削減)
② スクリーンショットは必要な場合のみ有効化
③ 結果はファイル保存してパスだけコンテキストに渡す
④ 複数操作をバッチ化して1リクエストにまとめる

どちらを使うべき?判断フロー

PlaywrightとBrowser Useを使い分けるには、以下の観点で判断します。

チェック項目 Yes → 選択 No → 選択
操作対象のDOMセレクタを把握している Playwright Browser Use
同じ処理を繰り返し実行する Playwright どちらでも
UIが頻繁に変わる Browser Use Playwright
複数サイトをまたぐ比較作業 Browser Use Playwright
処理をテストとして再利用したい Playwright Browser Use
自然言語でタスクを定義したい Browser Use Playwright
迷ったときの指針
「何をクリックすればいいか分かっている」→ Playwright
「ページを見ながら判断が必要」→ Browser Use
「定型80% + 判断20%」→ ハイブリッドアプローチ

ハイブリッドアプローチの実装

実務では「安定している部分はPlaywrightで高速処理し、不確実な部分だけBrowser Useで柔軟に対応する」ハイブリッドアプローチが最も効果的です。

hybrid_scraper.py
import asyncio
from playwright.async_api import async_playwright
from browser_use import Agent
from langchain_anthropic import ChatAnthropic

async def scrape_product_page(url: str) -> dict:
    """
    ハイブリッドアプローチ:
    - Playwright: ナビゲーション・既知の構造を高速処理
    - Browser Use: 未知のレイアウト・複雑な判断が必要な処理
    """
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto(url, wait_until="domcontentloaded")

        # ①まず標準的な構造か確認(Playwrightで高速チェック)
        standard_grid = await page.query_selector(".product-grid")

        if standard_grid:
            # ②標準レイアウトならPlaywrightで確定的に抽出
            items = await page.query_selector_all(".product-item")
            results = []
            for item in items:
                name_el  = await item.query_selector(".product-name")
                price_el = await item.query_selector(".product-price")
                results.append({
                    "name":  await name_el.inner_text()  if name_el  else "",
                    "price": await price_el.inner_text() if price_el else "",
                })
            await browser.close()
            return {"method": "playwright", "data": results}

        # ③非標準レイアウトはBrowser Useにフォールバック
        await browser.close()

    llm = ChatAnthropic(model="claude-sonnet-4-6")
    agent = Agent(
        task=f"{url} の全商品名と価格を抽出してJSON形式で返してください",
        llm=llm,
    )
    result = await agent.run()
    return {"method": "browser_use", "data": result.final_result()}


async def main():
    url = "https://example.com/products"
    result = await scrape_product_page(url)
    print(f"使用ツール: {result['method']}")
    print(f"取得データ: {result['data']}")

asyncio.run(main())

並列処理によるスループット向上

大量のページを処理する場合は、Playwrightの並列処理と組み合わせることでスループットを最大化できます。セマフォで同時実行数を制限することで、サーバーへの負荷を適切にコントロールできます。

parallel_scraper.py
import asyncio, json
from playwright.async_api import async_playwright

async def process_url(semaphore, browser, url):
    """セマフォで同時実行数を制限しながら並列処理"""
    async with semaphore:
        page = await browser.new_page()
        try:
            await page.goto(url, wait_until="domcontentloaded", timeout=15000)
            title = await page.title()
            return {"url": url, "title": title, "status": "ok"}
        except Exception as e:
            return {"url": url, "error": str(e), "status": "error"}
        finally:
            await page.close()

async def batch_scrape(urls: list[str], concurrency: int = 5):
    """最大5並列でURLリストを処理"""
    semaphore = asyncio.Semaphore(concurrency)
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        tasks = [process_url(semaphore, browser, url) for url in urls]
        results = await asyncio.gather(*tasks)
        await browser.close()
    return results

# 使い方
urls = [f"https://example.com/page{i}" for i in range(20)]
results = asyncio.run(batch_scrape(urls, concurrency=5))

success = [r for r in results if r["status"] == "ok"]
print(f"処理完了: {len(success)}/{len(results)}件成功")

よくある質問

QPlaywrightとPuppeteerはどちらが良いですか?

AClaude Codeでの利用であればPlaywrightを推奨します。Playwrightは公式MCPサーバーが提供されており、Claude Codeとの連携がシームレスです。またChromium・Firefox・WebKitの3ブラウザに対応し、非同期APIの設計も洗練されています。Puppeteerは主にChromium専用で、Playwright登場以降は後継として位置づけられています。

QBrowser UseはGPT-4oとClaude、どちらが良いですか?

ABrowser UseのドキュメントではGPT-4oとClaude Sonnetが最も信頼性が高いとされています。Claude Codeユーザーであれば、既にAPIキーを持っていることが多いためClaudeを選ぶのが自然です。モデル名は claude-sonnet-4-6 のように langchain_anthropic.ChatAnthropic に渡します。

Qheadlessモードとheadedモード、どちらを使うべきですか?

A開発・デバッグ時は headless=False でブラウザ画面を表示しながら動作確認するのが効率的です。本番運用や自動化スクリプトでは headless=True(デフォルト)にしてサーバーリソースを節約してください。

QBrowser Useでエージェントが正しく動作しない場合の対処法は?

Aまずタスクの指示文を具体的にする(URLやボタン名を明記する)と成功率が上がります。それでも解決しない場合、max_steps パラメータを増やすことで複雑なタスクも完了できるようになります。また save_conversation_path パラメータでエージェントの行動ログを保存すると、どのステップで詰まっているか確認できます。

QClaude Codeのコンテキストウィンドウが溢れてしまいます。どうすればいいですか?

AMCP経由の利用ではスクリーンショットや完全なアクセシビリティツリーがコンテキストに蓄積されます。CLIやSkillsアプローチに切り替えて結果をファイル経由で渡すことで、大幅にトークン消費を削減できます。Claude Codeのコスト管理ガイドも参考にしてください。

まとめ

PlaywrightとBrowser Useは、それぞれ異なる強みを持つブラウザ自動化ツールです。

Playwright Browser Use
強み 高速・確実・低コスト 柔軟・適応的・自然言語対応
弱み UIが変わると壊れる 速度・成功率・トークンコスト
Claude Code連携 MCP / CLI / Skills Pythonライブラリとして直接統合

実務ではどちらか一方に絞るのではなく、安定した処理はPlaywright、変動・探索的な処理はBrowser Useと使い分けるハイブリッドアプローチが最も効果的です。また、トークン効率の観点からもMCPよりCLI・Skillsを優先することで、コストを大幅に削減できます。

Claude Codeの他の機能との組み合わせについては、Claude CodeガイドClaude Agent SDKガイドも参考にしてみてください。