【Claude Code】ログイン済みブラウザで雑務を自動化
投稿日: 2026年7月3日
対象読者: Claude Code等のAIエージェントを使っていて、ログインが必要なWeb画面の作業まで任せたい個人開発者
この記事はこんな方向け:
- 記事を公開するたびにSearch Consoleを開いて、URLを貼って、インデックス登録をリクエストして……を手作業で繰り返している方
- Playwright MCPを入れたのに、素のブラウザが立ち上がってGoogleログインからやり直しになった方
- パスワードや2FAコードをAIに渡すのは気持ち悪い、と感じている方
TL;DR
- Playwright MCPが開くのは新規の素のブラウザ。普段のログインセッションは引き継げない
- 解決は、普段のブラウザをデバッグポート付きで起動し、
connectOverCDPでつなぐこと - ログインは人間、操作だけAI。パスワードも2FAもAIには一切渡らない
- Search Consoleのインデックス登録のような「毎回同じ画面仕事」が、指示ひとつで終わるようになる
はじめに
新しい記事を公開したら、Google Search Consoleを開く。検査バーにURLを貼る。「インデックス登録をリクエスト」を押す。1〜2分待つ。次のURLを貼る——。サイトの記事が増えてくると、この繰り返しが地味に開発時間を食っていきます。
「AIエージェントにやらせればいい」と思ってPlaywright MCPを試すと、今度は別の壁が待っています。立ち上がるのはまっさらな別のブラウザで、Googleにはログインしていない。かといってAIにパスワードと2FAコードを渡してログインさせるのは、セキュリティ的にやりたくない。ここで詰まった方は多いはずです。
この記事では、普段使っているログイン済みのブラウザそのものをClaude Codeに操作させる構成を紹介します。筆者はこのサイト(kabe-tech)の運用で、Search Consoleへの登録やAdSense画面の確認をこの方法でAIに任せています。1ヶ月ほど実運用して踏んだハマりどころも含めてまとめます。
Playwright MCPでは「自分のブラウザ」に触れない
まず前提の整理から。Playwright MCPやその類似ツールが操作するのは、ツール自身が起動した独立のブラウザインスタンスです。あなたが普段使っているブラウザのCookieもログインセッションも持っていないので、Search ConsoleやAdSenseのような「ログインの内側」のページを開くと、当然ログイン画面に跳ね返されます。
選択肢は2つしかありません。AIに認証情報を渡してログインさせるか、ログイン済みのブラウザにAIをつなぐか。前者はパスワードがログや会話履歴に残るリスクを抱え込みます。この記事で採るのは後者です。
仕組み:CDPで「今開いているブラウザ」につなぐ
ChromeやBrave等のChromium系ブラウザには、CDP(Chrome DevTools Protocol) という外部から操作を受け付ける口があります。デバッグポートを開けて起動しておけば、Playwrightはブラウザを「起動する」のではなく、走っているブラウザに「接続する」ことができます。両者の違いを図にするとこうです。
接続する側のコードは、Playwrightの connectOverCDP を呼ぶだけ。ログインセッションはブラウザのプロファイルの中にあるので、AIから見える世界は「すでにログインが終わった状態」から始まります。だからパスワードを教える必要がそもそもない——これがこの構成のいちばんの利点です。
セットアップ①:デバッグポート付きでブラウザを起動する
最初のステップは、ブラウザに --remote-debugging-port を付けて起動し直すことです。筆者はBraveを使っていますが、Chrome/Edgeでも実行ファイルのパスが違うだけで同じです。
毎回手で打つのは面倒なので、PowerShellスクリプトにしています。要点だけ抜粋します。
# 既にCDPポートが開いていればそのまま使う(無駄な再起動をしない)
try {
$v = Invoke-WebRequest -Uri "http://127.0.0.1:9222/json/version" -TimeoutSec 2
Write-Output "ALREADY_OPEN"; exit 0
} catch {}
# プロファイルを明示して起動。指定しないとプロファイル選択画面で止まり、
# CDP接続が "Browser context management is not supported" で失敗する
Start-Process brave.exe -ArgumentList @(
"--remote-debugging-port=9222",
"--restore-last-session",
"--profile-directory=`"Profile 3`""
)
2つ、実際に踏んだポイントがあります。
1つ目はポートの再利用。スクリプトの冒頭で /json/version を叩き、すでにポートが生きていれば何もしない。これがないと呼ぶたびにブラウザが再起動し、開いていたタブの作業が中断されます。
2つ目はプロファイルの明示。ブラウザに複数プロファイルがあると、無指定の起動ではプロファイル選択画面で止まることがあります。この状態でCDP接続すると Browser context management is not supported というエラーになり、原因が画面側にあると気づくまで結構悩みました。--profile-directory を必ず付けるのが安全です。
セットアップ②:接続ヘルパーを1枚書いておく
接続側は playwright-core を使います。ブラウザ本体を同梱しない軽量パッケージで、接続するだけなら十分です。筆者が実際に使っているヘルパーがこれです。
// connect.js — ログイン済みブラウザ(CDPポート9222)へのPlaywright接続ヘルパー
const { chromium } = require('playwright-core');
const CDP_URL = 'http://127.0.0.1:9222';
async function withBrowser(fn) {
const browser = await chromium.connectOverCDP(CDP_URL);
const context = browser.contexts()[0]; // 普段のプロファイルのコンテキスト
// URL部分一致で既存タブを再利用。無ければ新規タブ
const getPage = async (urlPart) => {
const existing = urlPart && context.pages().find(p => p.url().includes(urlPart));
const page = existing || await context.newPage();
await page.bringToFront();
return page;
};
try {
return await fn({ browser, context, getPage });
} finally {
await browser.close(); // CDP接続を切るだけ。ブラウザ本体は閉じない
}
}
module.exports = { withBrowser };
地味に重要なのが最後の browser.close() の意味です。CDP接続では、これは接続を切るだけでブラウザ本体を閉じません。自動化が終わったあともブラウザは普段どおり使い続けられます。getPage でタブを再利用しているのも同じ理由で、実行のたびに新規タブが積み上がっていくのを防いでいます。
実戦:Search Consoleのインデックス登録を任せる
ここまで組めば、あとはClaude Codeに「新記事のURLをSearch Consoleに登録して」と頼むだけです。AIが書く操作スクリプトの骨子はこうなります。
const { withBrowser } = require('./connect.js');
withBrowser(async ({ getPage }) => {
const page = await getPage('search-console'); // 開きっぱなしのGSCタブを再利用
await page.goto('https://search.google.com/search-console?resource_id=sc-domain:kabe-tech.com');
// 上部の検査バーにURLを入れてEnter
const bar = page.locator('input[aria-label*="URL を検査"]');
await bar.fill('https://kabe-tech.com/blog/poseMirror/new-article');
await bar.press('Enter');
await page.getByText('インデックス登録をリクエスト').click();
});
シンプルに見えますが、Search Consoleの画面には罠が多く、実際には次の3つを踏みました。同じ構成を組む方は先に知っておいてください。
ボタンは完全一致で押す。 「送信」ボタンを部分一致で探すと、画面の隅にある「フィードバックを送信」に誤爆します。getByRole('button', { name: '送信', exact: true }) のように exact: true を付けるのが確実です。人間なら間違えようのないボタンでAIが誤爆する——部分一致セレクタの典型的な事故でした。
ダイアログがクリックを遮る。 登録リクエスト後に出る確認ダイアログが残っていると、次の操作のクリックが遮られて失敗します。閉じる処理を頑張るより、次のURLに移る前に page.goto() でページごとフレッシュに読み込み直すほうが安定しました。
ディープリンクは信用しない。 URL検査のディープリンク(inspect?resource_id=...&id=...)は404になることがあります。素直に上部の検査バーに入力してEnter、が正解でした。
あとひとつ、仕様として知っておくべきはクォータです。インデックス登録リクエストは1件に1〜2分かかり、1日あたり10件程度で頭打ちになります。AIに任せて効くのは「速くなる」ことではなく、貼って・押して・待つという細切れの拘束時間が自分の予定から消えることのほうです。
CLAUDE.mdとスキルで「毎回説明」をなくす
この構成の仕上げは、手順をAI側に覚えさせることです。毎回「ポート9222で……connectOverCDPで……」と説明していたら本末転倒なので、筆者は起動スクリプトと接続ヘルパーの場所・注意点(前述の誤爆ボタンやダイアログの件)をCLAUDE.mdとスキルファイルに書いておき、どのプロジェクトのセッションからでも「ブラウザでSearch Consoleに新記事を登録して」の一言で通じるようにしています。
ハマりどころをスキルに書き溜めていくと、AIが同じ罠を二度踏まなくなります。自動化スクリプトそのものより、この「教訓の置き場所」のほうが資産価値が高いというのが、1ヶ月運用しての実感です。
まとめ
肝は「AIにログインさせる」のをやめて、「ログイン済みの環境にAIを入れる」に発想を逆転させたことに尽きます。ログインと2FAは人間がブラウザで普段どおり済ませておく。AIに渡すのはCDPポートだけ。これでパスワードを教えるリスクを負わずに、ログインの内側の雑務を任せられるようになります。
個人開発は、コードを書く時間より周辺の雑務——インデックス登録、管理画面の確認、ストアの更新——に時間を溶かしがちです。1回組んでしまえば使い回せる構成なので、Search Console以外にも「ログインが要る定型画面仕事」があれば、そこから試してみてください。
参考資料
- Playwright公式: browserType.connectOverCDP
- ログイン済みの Chrome をそのまま Claude Code から操作する(Zenn)
- Claude Code から Chrome を操作する — CDP × PowerShell(Zenn)
この体制で運用しているサイトの実物が当サイトです。写真からポーズを3D化する Pose Mirror も、公開後のSearch Console登録はぜんぶClaude Codeがやっています。
関連記事:
- 【個人開発】広告収入が運用費を上回るWebアプリの技術選定 — 雑務を減らす前段、運用費を減らす話
- Pose Mirror開発で詰まった5つの問題と解決策 — 開発本体の詰まりどころ集