browser-automation について
browser-automation は、Chrome DevTools Protocol を使って Chrome を操作するコマンドラインスキルです。ページのキャプチャや抽出、操作ができ、プロファイルにセッション状態を保存できます。
主な機能
- 01ページ全体または要素のキャプチャ
- 02ウェブページから PDF を生成
- 03テキスト、リンク、画像、メタデータの抽出
- 04ページ移動、操作、フォーム入力
- 05Chrome プロファイルによるセッション保持
- 06ブラウザー画面のフレーム録画
活用シーン
- 01ページや要素を画像として保存
- 02記事内容とページ内リンクの抽出
- 03フォーム入力と送信の自動化
- 04ログイン済みサイトでの複数段階の操作
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ the-focus-ai/ chrome-driver --skill browser-automationインストール後、Claude Code で/browser-automationを入力して読み込まれたか確認します。
詳細
Chrome DevTools Protocol によるブラウザー自動化
シンプルなコマンドラインスクリプトを使って、Chrome ブラウザーをプログラムから操作できます。Chrome が起動していない場合、すべてのスクリプトがヘッドレスモードで自動的に起動します。
グローバルオプション(すべてのコマンド)
すべてのコマンドで、セッションの保持と対話型の使用に関する次のオプションを利用できます。
--no-headless- Chrome を表示ウィンドウ付きで実行します(対話型サイトやログインなどで必要です)--user-data=PATH- Cookie、ログイン情報、セッション状態を実行間で保持するために、特定の Chrome プロファイルディレクトリを使用します
例:ログイン済みサイトでセッションを保持する
# First time: login interactively with visible browser
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://instacart.com --no-headless --user-data=~/.chrome-instacart
# After logging in manually, future commands use same profile (cookies preserved)
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://instacart.com/store/market-32 --user-data=~/.chrome-instacart
${CLAUDE_PLUGIN_ROOT}/bin/screenshot https://instacart.com/account --user-data=~/.chrome-instacart /tmp/account.png
利用可能なコマンド
すべてのスクリプトは ${CLAUDE_PLUGIN_ROOT}/bin/ にあります。
screenshot - Web ページを画像としてキャプチャ
${CLAUDE_PLUGIN_ROOT}/bin/screenshot URL [OUTPUT] [OPTIONS]
オプション:
--full-page- スクロール可能なページ全体をキャプチャします--selector=CSS- 特定の要素をキャプチャします--format=png|jpeg|webp- 出力形式(デフォルト:png)--quality=N- JPEG/WebP の品質(0~100)--width=N --height=N- ビューポートのサイズを設定します--max-dimension=N- 出力の最大寸法(デフォルト:8000。大きなページは自動的に縮小されます)
例:
# Basic screenshot
${CLAUDE_PLUGIN_ROOT}/bin/screenshot https://example.com /tmp/page.png
# Full page as JPEG
${CLAUDE_PLUGIN_ROOT}/bin/screenshot https://example.com /tmp/full.jpg --full-page --format=jpeg
# Capture specific element
${CLAUDE_PLUGIN_ROOT}/bin/screenshot https://example.com /tmp/header.png --selector="header"
pdf - Web ページから PDF を生成
${CLAUDE_PLUGIN_ROOT}/bin/pdf URL [OUTPUT] [OPTIONS]
オプション:
--paper=letter|a4|legal|a3|a5|tabloid- 用紙サイズ(デフォルト:letter)--landscape- 横向きにします--margin=INCHES- すべての余白(デフォルト:0.4)--scale=FACTOR- 拡大縮小率(0.1~2.0、デフォルト:1.0)--no-background- 背景色と背景画像を省略します
例:
# Basic PDF
${CLAUDE_PLUGIN_ROOT}/bin/pdf https://example.com /tmp/doc.pdf
# A4 landscape
${CLAUDE_PLUGIN_ROOT}/bin/pdf https://example.com /tmp/report.pdf --paper=a4 --landscape
# Tight margins
${CLAUDE_PLUGIN_ROOT}/bin/pdf https://example.com /tmp/compact.pdf --margin=0.25
extract - Web ページからコンテンツを抽出
${CLAUDE_PLUGIN_ROOT}/bin/extract URL [OPTIONS]
オプション:
--format=markdown|text|html- 出力形式(デフォルト:markdown)--selector=CSS- 特定の要素のみを抽出します--links- すべてのリンクも一覧表示します--images- すべての画像も一覧表示します--metadata- ページのメタデータも表示します
例:
# Get page as markdown
${CLAUDE_PLUGIN_ROOT}/bin/extract https://example.com
# Get plain text from article
${CLAUDE_PLUGIN_ROOT}/bin/extract https://example.com --format=text --selector="article"
# Get all links and metadata
${CLAUDE_PLUGIN_ROOT}/bin/extract https://example.com --links --metadata
navigate - ページに移動して操作
${CLAUDE_PLUGIN_ROOT}/bin/navigate URL [OPTIONS]
オプション:
--wait-for=SELECTOR- 要素が表示されるまで待機します--click=SELECTOR- 要素をクリックします--type=SELECTOR=TEXT- 入力フィールドにテキストを入力します--eval=JAVASCRIPT- JavaScript を実行して結果を出力します--timeout=SECONDS- タイムアウト(デフォルト:30)
例:
# Navigate and wait for content
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://example.com --wait-for="#content"
# Fill form and submit
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://google.com --type="input[name=q]=hello" --click="input[type=submit]"
# Get page title via JavaScript
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://example.com --eval="document.title"
form - Web フォームに入力して送信
${CLAUDE_PLUGIN_ROOT}/bin/form URL [OPTIONS]
オプション:
--fill=SELECTOR=VALUE- 入力フィールドに入力します(繰り返し指定できます)--select=SELECTOR=VALUE- ドロップダウンの選択肢を選びます(繰り返し指定できます)--fill-json='{"sel":"val"}'- JSON から複数のフィールドに入力します--submit=SELECTOR- 入力後に送信ボタンをクリックします--wait-for=SELECTOR- 入力前に要素が表示されるまで待機します--wait-after=SELECTOR- 送信後に要素が表示されるまで待機します--screenshot=PATH- 完了後にスクリーンショットを撮影します
例:
# Login form
${CLAUDE_PLUGIN_ROOT}/bin/form https://example.com/login \
--fill='#username=john' \
--fill='#password=secret' \
--submit='button[type=submit]'
# Form with dropdowns
${CLAUDE_PLUGIN_ROOT}/bin/form https://example.com/register \
--fill='#name=John Doe' \
--fill='#[email protected]' \
--select='#country=US' \
--submit='#register-btn'
# Using JSON
${CLAUDE_PLUGIN_ROOT}/bin/form https://example.com/contact \
--fill-json='{"#name":"John","#email":"[email protected]"}' \
--submit='button.send'
record - スクリーンキャストのフレームを記録
${CLAUDE_PLUGIN_ROOT}/bin/record URL OUTPUT_DIR [OPTIONS]
オプション:
--duration=SECONDS- 記録時間(デフォルト:5)--count=N- キャプチャするフレーム数を指定します--format=jpeg|png- フレーム形式(デフォルト:jpeg)--quality=N- JPEG の品質(0~100、デフォルト:80)--max-width=N- フレームの最大幅--max-height=N- フレームの最大高さ--fps=N- おおよそのフレームレート(デフォルト:10)
例:
# Record 5 seconds
${CLAUDE_PLUGIN_ROOT}/bin/record https://example.com /tmp/frames
# Record 30 PNG frames
${CLAUDE_PLUGIN_ROOT}/bin/record https://example.com /tmp/frames --count=30 --format=png
# Convert to video with ffmpeg
ffmpeg -framerate 10 -i /tmp/frames/frame-%04d.jpg -c:v libx264 output.mp4
interact - 現在のページを操作(ページ遷移なし)
${CLAUDE_PLUGIN_ROOT}/bin/interact [OPTIONS]
複数ステップのワークフローで中心となるコマンドです。 navigate とは異なり、このコマンドはすでに開いているブラウザーのタブに接続し、ページを再読み込みせずに操作を実行します。次のような用途に不可欠です。
- 複数ステップの処理(検索 → 検索結果をクリック → カートに追加)
- シングルページアプリケーション(SPA)
- ページ遷移によって状態がリセットされるサイト
オプション:
--click=SELECTOR- CSS セレクターに一致する要素をクリックします--type=SELECTOR=TEXT- 入力フィールドにテキストを入力します--eval=JAVASCRIPT- JavaScript を実行して結果を出力します--wait-for=SELECTOR- 要素が表示されるまで待機します--select=SELECTOR=VALUE- ドロップダウンの選択肢を選びます--focus=SELECTOR- 要素にフォーカスします--text=SELECTOR- 要素のテキストコンテンツを取得します--timeout=SECONDS- タイムアウト(デフォルト:30)
例:
# Execute JavaScript on current page
${CLAUDE_PLUGIN_ROOT}/bin/interact --eval="document.title" --user-data=~/.chrome-mysite
# Click a button on current page
${CLAUDE_PLUGIN_ROOT}/bin/interact --click="#submit-btn" --user-data=~/.chrome-mysite
# Type into an input without navigating away
${CLAUDE_PLUGIN_ROOT}/bin/interact --type="#search=query" --user-data=~/.chrome-mysite
# Chain actions: focus, type, then click
${CLAUDE_PLUGIN_ROOT}/bin/interact --focus="#search" --type="#search=pork" --click="#search-btn" --user-data=~/.chrome-mysite
# Get text from an element
${CLAUDE_PLUGIN_ROOT}/bin/interact --text="h1.title" --user-data=~/.chrome-mysite
chrome-status - ブラウザーの状態を確認
${CLAUDE_PLUGIN_ROOT}/bin/chrome-status
Chrome が起動しているかどうか、バージョン情報、開いているタブを表示します。
よくあるワークフロー
ページのスクリーンショットを撮る
${CLAUDE_PLUGIN_ROOT}/bin/screenshot https://example.com /tmp/screenshot.png
ページを PDF に変換する
${CLAUDE_PLUGIN_ROOT}/bin/pdf https://example.com /tmp/document.pdf --paper=a4
ページのコンテンツをスクレイピングする
${CLAUDE_PLUGIN_ROOT}/bin/extract https://example.com --format=markdown
フォームに入力して送信する
${CLAUDE_PLUGIN_ROOT}/bin/form https://example.com/login \
--fill='#username=user' \
--fill='#password=pass' \
--submit='button[type=submit]' \
--wait-after='.dashboard'
スクリーンキャストを録画する
${CLAUDE_PLUGIN_ROOT}/bin/record https://example.com /tmp/frames --duration=10
ffmpeg -framerate 10 -i /tmp/frames/frame-%04d.jpg -c:v libx264 video.mp4
注意事項
- 必要に応じて Chrome はヘッドレスモードで自動起動します(ブラウザーを表示するには
--no-headlessを使用します) - コマンド間の処理を高速化するため、Chrome は起動したままになります
- セッション間でログイン状態や Cookie を保持するには
--user-data=PATHを使用します - Chrome を手動で停止するには
pkill -f 'chrome.*--remote-debugging-port'を使用します - デフォルトのポートは 9222 です。変更するには
CHROME_DRIVER_PORTを設定します - すべてのスクリプトで、完全な使用方法を確認するための
--helpが利用できます - 大きなスクリーンショットは、8000px 以内に収まるよう自動的に縮小されます(API の制限)
セッション管理のヒント
ログインが必要なサイト(Instacart、Amazon、銀行など)の場合:
- 永続プロファイルを作成する:
--user-data=~/.chrome-sitenameを継続して使用します - 初回ログイン:ブラウザーを表示して手動でログインするには
--no-headlessを使用します - 以降の自動化:同じ
--user-dataパスを使用すると、セッションが保持されます - 複数のアカウント:アカウントやサイトごとに異なる
--user-dataパスを使用します
複数ステップのワークフローガイド:ショッピングサイト(Instacart、Amazon など)
このセクションでは、ログインと複数の操作が必要なサイトで、複雑な複数ステップのプロセスを自動化する方法を説明します。重要なのは、2 つのコマンドを組み合わせて使うことです。
navigate- URL に移動します(初回の移動に使用)interact- 再読み込みせずに現在のページを操作します(以降のすべての操作に使用)
2 つのコマンドを使うパターンについて
navigate だけでは不十分な理由:
navigateは指定された URL を必ず読み込み/再読み込みしますnavigateの各呼び出しは独立しており、前の状態から「続行」することはありません- 複数ステップのワークフロー(検索 → 選択 → カートに追加)は、各ステップで状態がリセットされるため失敗します
interact が不可欠な理由:
interactは既存のブラウザータブに接続します- 現在表示されているページに対して操作を実行します
interactの呼び出し間でページの状態が保持されます- SPA や複数ステップのプロセスに最適です
完全な例:Instacart のカートに商品を追加する
実際に動作する例を紹介します。
ステップ 1:初期設定 - プロファイルの作成とログイン
初回のみ、ユーザーがログインできるようブラウザーを表示して開きます。
# Open Instacart with visible browser and persistent profile
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://www.instacart.com \
--no-headless \
--user-data=~/.chrome-instacart
# USER ACTION: Log in manually in the browser window
# Your cookies/session will be saved to ~/.chrome-instacart
ステップ 2:店舗に移動する
ログイン後、目的の店舗に移動します。
# First, find the correct store URL by checking the homepage
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://www.instacart.com/store \
--no-headless \
--user-data=~/.chrome-instacart
# Use JavaScript to find links containing your store name
${CLAUDE_PLUGIN_ROOT}/bin/interact \
--eval="Array.from(document.querySelectorAll('a')).filter(a => a.innerText.includes('Market 32')).map(a => a.href).join('\n')" \
--no-headless \
--user-data=~/.chrome-instacart
# Navigate to the store (use the URL found above)
${CLAUDE_PLUGIN_ROOT}/bin/navigate https://www.instacart.com/store/price-chopper-ny/storefront \
--no-headless \
--user-data=~/.chrome-instacart
ステップ 3:商品を検索する(interact を使った複数ステップの操作)
ここからは interact を使って、別のページに移動せずに検索します。
# Click the search input
${CLAUDE_PLUGIN_ROOT}/bin/interact \
--click="#search-bar-input" \
--no-headless \
--user-data=~/.chrome-instacart
# Type the search query
${CLAUDE_PLUGIN_ROOT}/bin/interact \
--type="#search-bar-input=pork shoulder" \
--no-headless \
--user-data=~/.chrome-instacart
# Submit the search using JavaScript (trigger form submit event)
${CLAUDE_PLUGIN_ROOT}/bin/interact \
--eval="var input = document.querySelector('#search-bar-input'); var form = input.closest('form'); form.dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); 'submitted'" \
--no-headless \
--user-data=~/.chrome-instacart
ステップ 4:検索結果を確認する
購入可能な商品を確認します。
# Wait a moment for results to load, then check the page content
sleep 2
${CLAUDE_PLUGIN_ROOT}/bin/interact \
--eval="document.body.innerText.substring(0, 2000)" \
--no-headless \
--user-data=~/.chrome-instacart
ステップ 5:商品をカートに追加する
目的の商品にある追加ボタンをクリックします。
# Find and click the first "Add" button
${CLAUDE_PLUGIN_ROOT}/bin/interact \
--eval="var addBtns = Array.from(document.querySelectorAll('button')).filter(b => b.innerText.trim() === 'Add'); if (addBtns.length > 0) { addBtns[0].click(); 'Added to cart'; } else { 'No Add button found'; }" \
--no-headless \
--user-data=~/.chrome-instacart
ステップ 6:カートが更新されたことを確認する
商品が追加されたことを確認します。
# Check cart count or page state
${CLAUDE_PLUGIN_ROOT}/bin/interact \
--eval="document.body.innerText.includes('2') ? 'Cart has 2 items' : document.body.innerText.substring(0, 500)" \
--no-headless \
--user-data=~/.chrome-instacart
複数ステップの自動化に使う主なテクニック
1. JavaScript で要素を見つける
CSS セレクターが複雑または動的な場合は、--eval を使って要素を見つけます。
# Find all buttons with specific text
--eval="Array.from(document.querySelectorAll('button')).filter(b => b.innerText.includes('Add')).length"
# Find links by text content
--eval="Array.from(document.querySelectorAll('a')).filter(a => a.innerText.includes('Checkout'))[0].href"
# Get input field IDs/names
--eval="JSON.stringify(Array.from(document.querySelectorAll('input')).map(i => ({id: i.id, name: i.name, placeholder: i.placeholder})))"
2. JavaScript 経由で要素をクリックする
--click が機能しない場合(動的な要素、オーバーレイなど):
# Click by finding element with JS
--eval="document.querySelector('.add-to-cart-btn').click(); 'clicked'"
# Click first matching element
--eval="Array.from(document.querySelectorAll('button')).filter(b => b.innerText === 'Add')[0].click(); 'clicked'"
3. フォームを送信する
フォームを送信するためのさまざまな方法:
# Method 1: Dispatch submit event (most reliable for SPAs)
--eval="document.querySelector('form').dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); 'submitted'"
# Method 2: Click submit button
--click="button[type=submit]"
# Method 3: Call submit() directly
--eval="document.querySelector('form').submit(); 'submitted'"
4. 動的コンテンツを待つ
--wait-for または JavaScript によるポーリングを使用します。
# Wait for element to appear
--wait-for=".search-results"
# Or use JavaScript with timeout
--eval="new Promise(r => { let i = setInterval(() => { if (document.querySelector('.results')) { clearInterval(i); r('found'); }}, 100); setTimeout(() => { clearInterval(i); r('timeout'); }, 5000); })"
5. ページの状態を読み取る
情報を抽出して、判断に役立てます。
# Get current URL
--eval="window.location.href"
# Check if logged in
--eval="document.body.innerText.includes('Sign Out') ? 'logged in' : 'not logged in'"
# Get cart count
--eval="document.querySelector('.cart-count')?.innerText || '0'"
# Get product prices
--eval="JSON.stringify(Array.from(document.querySelectorAll('.price')).map(p => p.innerText))"
複数ステップのワークフローに関するトラブルシューティング
問題:コマンド間でページがリセットされる
解決策:初回のページ移動後は、すべてのステップで navigate ではなく interact を使用します。
問題:要素が見つからない
解決策:
--evalを使ってページ構造を調べます--wait-forまたはsleepで動的コンテンツを待ちます- 要素が iframe 内にあるか確認します
問題:クリックが機能しない
解決策:
- JavaScript によるクリックを試します:
--eval="document.querySelector('...').click()" - 先に要素が表示される位置までスクロールします
- 要素を覆うオーバーレイがないか確認します
問題:フォームが送信されない
解決方法:
- フォームの送信イベントを使用します:
form.dispatchEvent(new Event('submit', ...)) - カスタムフォーム処理を行う SPA かどうかを確認します
- 実際の送信ボタンを探してクリックします
問題:ログインセッションが失われる
解決方法:
- 常に同じ
--user-dataパスを使用します - Cookie の有効期限が切れていないか確認します
- サイトによっては、定期的な再ログインが必要です
ベストプラクティス
- ログインが必要なサイトでは、必ず
--user-dataを使用します - 開発中は
--no-headlessを使用して、動作を確認します - 初期ページを読み込むには、
navigateから始めます - そのページでの以降の操作には、
interactを使用します - ページの状態を調べて要素を見つけるには、
--evalを積極的に使用します - サイトの更新に時間がかかる場合は、操作の間に
sleepを追加します - 操作が成功したことを確認するため、各ステップの後に結果を確認します
Instacart 自動化ガイド(テスト済みの実証パターン)
このセクションでは、Instacart での買い物を自動化するための、実地で十分に検証されたパターンを紹介します。これらのパターンは、広範な実環境でのテストを通じて開発されました。
クイックリファレンス:必須コマンド
# Base command pattern (always use these flags)
INTERACT="${CLAUDE_PLUGIN_ROOT}/bin/interact --no-headless --user-data=~/.chrome-instacart"
NAVIGATE="${CLAUDE_PLUGIN_ROOT}/bin/navigate --no-headless --user-data=~/.chrome-instacart"
# Suppress stderr noise
$INTERACT --eval="..." 2>/dev/null
店舗の選択
重要:Instacart の URL を手動で組み立てないでください。 常に UI から移動します:
# Go to homepage first
$NAVIGATE "https://www.instacart.com"
# Find store links on page
$INTERACT --eval="Array.from(document.querySelectorAll('a')).filter(a => a.innerText.includes('Stop & Shop')).map(a => ({text: a.innerText, href: a.href}))"
# Click the store link found above (or navigate to storefront)
$NAVIGATE "https://www.instacart.com/store/stop-shop/storefront"
検索パターン(信頼性の高い 3 ステップの手順)
# Step 1: Clear existing search (IMPORTANT - prevents concatenation)
$INTERACT --eval="var input = document.querySelector('#search-bar-input'); input.select(); document.execCommand('delete'); 'cleared'" 2>/dev/null
# Step 2: Type search term
$INTERACT --type="#search-bar-input=pork shoulder" 2>/dev/null
# Step 3: Submit form (dispatchEvent is most reliable for SPAs)
$INTERACT --eval="document.querySelector('#search-bar-input').closest('form').dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); 'submitted'" 2>/dev/null && sleep 3
効率的な一行コマンド:
$INTERACT --eval="var input = document.querySelector('#search-bar-input'); input.select(); document.execCommand('delete'); 'cleared'" 2>/dev/null && \
$INTERACT --type="#search-bar-input=SEARCH_TERM" 2>/dev/null && \
$INTERACT --eval="document.querySelector('#search-bar-input').closest('form').dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); 'submitted'" 2>/dev/null && sleep 3
商品の検索:在庫のある商品を見つける
利用可能な「Add」ボタンを一覧表示します(商品名を表示):
$INTERACT --eval="JSON.stringify(Array.from(document.querySelectorAll('button[aria-label*=\"Add\"]')).slice(0,8).map(b => b.getAttribute('aria-label')))" 2>/dev/null
ページの内容を取得して、価格とサイズを確認します:
$INTERACT --eval="document.body.innerText.substring(0, 4000)" 2>/dev/null
カートへの商品の追加
Instacart では商品ボタンに aria-label が使用されています。主なパターンは次のとおりです:
| 操作 | Aria-label のパターン |
|---|---|
| 商品を追加 | Add 1 ct [Product Name] または Add 1 lb [Product Name] |
| 数量を増やす | Increment quantity of [Product Name] |
| 数量を減らす | Decrement quantity of [Product Name] |
| 削除 | Remove [Product Name] |
商品を追加する(完全一致):
$INTERACT --eval="var btn = document.querySelector('button[aria-label=\"Add 1 ct Store Brand Baby Spinach\"]'); if(btn) { btn.click(); 'Added'; } else { 'Not found'; }" 2>/dev/null
商品を追加する(部分一致:より柔軟):
$INTERACT --eval="var btn = document.querySelector('button[aria-label*=\"Add\"][aria-label*=\"Spinach\"]'); if(btn) { btn.click(); 'Added'; } else { 'Not found'; }" 2>/dev/null
数量の管理
数量を増やす(同じ商品を追加):
$INTERACT --eval="var btn = document.querySelector('button[aria-label*=\"Increment\"][aria-label*=\"Avocado\"]'); if(btn) { btn.click(); 'Incremented'; } else { 'Not found'; }" 2>/dev/null
複数回、数量を増やす(例:アボカドを 6 個購入):
# Add first one, then increment 5 times
$INTERACT --eval="document.querySelector('button[aria-label*=\"Add\"][aria-label*=\"Avocado\"]').click(); 'Added 1'" 2>/dev/null && sleep 1
for i in 1 2 3 4 5; do
sleep 0.5
$INTERACT --eval="var btn = document.querySelector('button[aria-label*=\"Increment\"][aria-label*=\"Avocado\"]'); if(btn) btn.click(); 'Inc'" 2>/dev/null
done
複数回の数量増加を行う JavaScript ループ(より高速):
$INTERACT --eval="for(let i=0;i<5;i++){var btn=document.querySelector('button[aria-label*=\"Increment\"][aria-label*=\"Lemon\"]');if(btn)btn.click();} 'Incremented to 6'" 2>/dev/null
カートから商品を削除する:
$INTERACT --eval="var btn = document.querySelector('button[aria-label=\"Remove Bertolli Original Extra Virgin Olive Oil\"]'); if(btn) { btn.click(); 'Removed'; } else { 'Not found'; }" 2>/dev/null
カートの管理
カートを表示する(カートのバッジをクリック):
$INTERACT --eval="var badge = Array.from(document.querySelectorAll('*')).find(el => /^\\d+$/.test(el.innerText.trim()) && parseInt(el.innerText) > 10 && el.offsetWidth < 50); if(badge) { var parent = badge.closest('a') || badge.closest('button') || badge.parentElement.parentElement; if(parent) parent.click(); 'clicked cart'; } else { 'cart not found'; }" 2>/dev/null && sleep 2
カートの合計金額を取得する:
$INTERACT --eval="document.body.innerText.match(/\\$\\d{2,3}\\.\\d{2}/) ? document.body.innerText.match(/\\$\\d{2,3}\\.\\d{2}/)[0] : 'no total found'" 2>/dev/null
カートパネルが開いているときに、価格付きでカート内の全商品を一覧表示する:
$INTERACT --eval="document.body.innerText.substring(5500, 12000)" 2>/dev/null
カート内の削除/数量減少ボタンをすべて見つける:
$INTERACT --eval="Array.from(document.querySelectorAll('button')).filter(b => b.getAttribute('aria-label') && (b.getAttribute('aria-label').includes('Remove') || b.getAttribute('aria-label').includes('Decrement'))).slice(0,20).map(b => b.getAttribute('aria-label')).join(' | ')" 2>/dev/null
買い物の一連のワークフロー
複数の商品を追加する効率的なパターン:
# Function to search and add item
add_item() {
local search="$1"
local product="$2"
local qty="${3:-1}"
# Search
$INTERACT --eval="var input = document.querySelector('#search-bar-input'); input.select(); document.execCommand('delete'); 'cleared'" 2>/dev/null
$INTERACT --type="#search-bar-input=$search" 2>/dev/null
$INTERACT --eval="document.querySelector('#search-bar-input').closest('form').dispatchEvent(new Event('submit', {bubbles: true, cancelable: true})); 'submitted'" 2>/dev/null
sleep 3
# Add
$INTERACT --eval="var btn = document.querySelector('button[aria-label*=\"Add\"][aria-label*=\"$product\"]'); if(btn) { btn.click(); 'Added'; } else { 'Not found'; }" 2>/dev/null
sleep 1
# Increment if qty > 1
if [ "$qty" -gt 1 ]; then
for i in $(seq 2 $qty); do
sleep 0.5
$INTERACT --eval="var btn = document.querySelector('button[aria-label*=\"Increment\"][aria-label*=\"$product\"]'); if(btn) btn.click();" 2>/dev/null
done
fi
}
# Usage examples:
add_item "avocados" "Hass Avocado" 6
add_item "baby spinach" "Store Brand Baby Spinach" 2
add_item "bell peppers" "Green Bell Pepper" 2
Instacart 固有の問題のトラブルシューティング
問題:検索語句が連結される(例:「lemonsfresh thyme」)
- 原因:前の検索テキストがクリアされていません
- 解決方法:入力前に、必ず
input.select(); document.execCommand('delete')でクリアします
問題:「Add」ボタンが見つからない
- 原因:aria-label 内の商品名が検索語句と一致していません
- 解決方法:
- 利用可能なボタンを一覧表示します:
JSON.stringify(Array.from(document.querySelectorAll('button[aria-label*="Add"]')).slice(0,8).map(b => b.getAttribute('aria-label'))) - 部分一致を使用します:
aria-label*="Add"][aria-label*="partial name"
- 利用可能なボタンを一覧表示します:
問題:住所に配達可能な店舗がない
- 原因:Instacart では配達先住所に応じて表示される店舗が異なります
- 解決方法:現在の住所で利用可能な店舗を確認するか、住所を変更します
問題:カートの商品数が正しくない
- 原因:重量販売の商品もあります(例:肉は 1 商品と表示されても、重量は 5 ポンドの場合があります)
- 解決方法:これは正常です。実際の数量はカートの詳細で確認します
問題:店舗によって価格が異なる
- 原因:店舗ごとに価格設定が独立しています
- 解決方法:店舗間でカートを比較し、高価な商品を別の商品に置き換えます
商品選びのヒント
- ストアブランドを優先する - 通常は最も安く、検索結果にもストアブランドがよく表示されます
- サイズを確認する - 「16 oz」と「50.7 oz」では、価格に大きな差が生じます
- 大容量パックを選ぶ - 単価を抑えるには、商品名に「Value Pack」とあるものを探します
- 重量販売の商品に注意する - 肉や農産物は重量で販売されます。数量は個数ではなく重量です
- セールを確認する - 検索結果には「With loyalty card」の価格が表示されます
学んだ重要な点
- 最初の
navigateの後は必ずinteractを使う - Instacart は SPA であり、ナビゲーションすると状態がリセットされます - 新しい検索の前に検索入力欄をクリアする - 検索語が連結される不具合を防ぎます
- aria-label セレクターを使う - Instacart のボタンを見つける最も信頼性の高い方法です
2>/dev/nullを追加する - Chrome ドライバーからの不要な stderr 出力を抑制します- 検索送信後に
sleep 3を追加する - 検索結果が読み込まれるまで待機します - aria-label の部分一致(
*=)を使う - 完全一致よりも堅牢です - カートを定期的に確認する - 商品が正しく追加されたことを確認します
- 店舗の配達可能エリアは住所によって異なる - すべての店舗がどこにでも配達できるわけではありません