【Claude Code】ログイン済みブラウザで雑務を自動化

投稿日: 2026年7月3日(2026年10月5日更新)
対象読者: Claude Code等のAIエージェントを使っていて、ログインが必要なWeb画面の作業まで任せたい個人開発者

この記事はこんな方向け:

  • 記事を公開するたびにSearch Consoleを開いて、URLを貼って、インデックス登録をリクエストして……を手作業で繰り返している方
  • Playwright MCPを入れたのに、素のブラウザが立ち上がってGoogleログインからやり直しになった方
  • パスワードや2FAコードをAIに渡すのは気持ち悪い、と感じている方

この記事でできるようになること

Playwright MCP が開くのは、新しく起動した素のブラウザなので、普段のログインは引き継げません。普段のブラウザをデバッグポート付きで起動し、connectOverCDP でつなげば、ログインは人間が済ませ、操作だけを AI に任せられます。パスワードも2段階認証のコードも、AI には渡りません。

はじめに

新しい記事を公開したら、Google Search Consoleを開く。検査バーにURLを貼る。「インデックス登録をリクエスト」を押す。1〜2分待つ。次のURLを貼る……。サイトの記事が増えてくると、この繰り返しが地味に開発時間を食っていきます。

「AIエージェントにやらせればいい」と思ってPlaywright MCPを試すと、今度は別の壁が待っています。立ち上がるのはまっさらな別のブラウザで、Google にはログインしていない。かといってAIにパスワードと2FAコードを渡してログインさせるのは、セキュリティ的にやりたくない。ここで詰まった方は多いはずです。

この記事では、普段使っているログイン済みのブラウザそのものを Claude Code に操作させる構成を紹介します。筆者はこのサイト(kabe-tech)の運用で、Search Console への登録や AdSense の画面の確認をこの方法で AI に任せています。運用しながら踏んだ罠も含めてまとめます。

Playwright MCPでは「自分のブラウザ」に触れない

まず前提の整理から。Playwright MCP やその類似ツールが操作するのは、ツール自身が起動した独立のブラウザです。普段使っているブラウザのCookieもログインセッションも持っていないので、Search ConsoleやAdSenseのような「ログインの内側」のページを開くと、当然ログイン画面に跳ね返されます。

選択肢は2つしかありません。AIに認証情報を渡してログインさせるか、ログイン済みのブラウザにAIをつなぐか。前者はパスワードがログや会話履歴に残るリスクを抱え込みます。この記事で採るのは後者です。

仕組み:CDPで「今開いているブラウザ」につなぐ

Chrome や Brave などの Chromium 系ブラウザには、CDP(Chrome DevTools Protocol)という、外部から操作を受け付ける口があります。デバッグポートを開けて起動しておけば、Playwrightはブラウザを「起動する」のではなく、走っているブラウザに「接続」できます。両者の違いを図にするとこうです。

Playwright MCPは新規のまっさらなブラウザを起動するためログインなしで2FAからやり直しになる。connectOverCDPなら普段のブラウザにポート9222で接続し、ログイン済みセッションと開いているタブをそのまま使える。パスワードはAIに渡らない

接続する側のコードは、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タブを再利用
  // kabe-tech.com は URL プレフィックス型のプロパティ。sc-domain: で指定するとアクセス権が無いと言われる
  await page.goto('https://search.google.com/search-console?resource_id=https%3A%2F%2Fkabe-tech.com%2F');

  // 上部の検査バーに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 の画面には罠が多く、実際に次の4つを踏みました。

1つ目は、ボタンを完全一致で押すことです。「送信」ボタンを部分一致で探すと、画面の隅にある「フィードバックを送信」に誤爆します。getByRole('button', { name: '送信', exact: true }) のように exact: true を付けるのが確実です。

2つ目は、ダイアログがクリックを遮ることです。登録をリクエストしたあとの確認ダイアログが残っていると、次のクリックが失敗します。閉じる処理を書くより、次の URL に移る前に page.goto() でページごと読み込み直すほうが安定しました。

3つ目は、ディープリンクを信用しないことです。URL 検査のディープリンク(inspect?resource_id=...&id=...)は 404 になりました。上部の検査バーに入力して Enter を押すのが確実です。

4つ目は、固まったタブが1つあるだけで、接続そのものがタイムアウトすることです。connectOverCDP は、つないだ瞬間に開いているすべてのタブへ接続しにいきます。描画が固まったタブが1つでもあると、その応答を待ち続けて失敗します。19タブのうち1つが固まっていただけで、操作が9回続けて全部失敗したこともありました。固まったタブを探して閉じると、すぐにつながりました。

仕様として知っておくべきなのは上限です。インデックス登録のリクエストは1件に1〜2分かかり、1日あたり10件ほどで上限に達します。AI に任せて変わるのは、速さよりも、貼って押して待つという細切れの時間が自分の予定から消えることです。

CLAUDE.mdとスキルで「毎回説明」をなくす

仕上げに、手順を AI 側に覚えさせます。毎回「ポート9222で、connectOverCDP で」と説明するのは手間です。そこで筆者は、起動スクリプトと接続ヘルパーの場所、踏んだ罠を、CLAUDE.md とスキルのファイルに書いています。どのプロジェクトのセッションからでも、「ブラウザで Search Console に新記事を登録して」の一言で通じます。

踏んだ罠をスキルに書き足していくと、AI が同じ罠を踏む回数が減りました。自動化のスクリプトそのものより、この教訓の置き場所のほうが役に立っている、というのが筆者の実感です。

まとめ

AI にログインさせる代わりに、ログイン済みの環境に AI をつなぐ。この構成の考え方はそれだけです。ログインと2段階認証は人間がブラウザで普段どおり済ませ、AI に渡すのは CDP のポートだけにします。パスワードを教えずに、ログインの内側の雑務を任せられます。

個人開発は、コードを書く時間より周辺の雑務(インデックス登録、管理画面の確認、ストアの更新)に時間を溶かしがちです。1回組んでしまえば使い回せる構成なので、Search Console以外にも「ログインが要る定型画面仕事」があれば、そこから試してみてください。

参考資料


この体制で運用しているのが当サイトです。写真からポーズを3D化する PoseMirror のページも、公開したあとの Search Console への登録は Claude Code に任せています。

自動化の傍らで作っているのが、このアプリです。

Claude Codeと二人三脚で開発している3Dデッサン人形ツールです。

▶ 同じ個人開発で作った3Dデッサン人形サイトを見る

関連記事:

← Kabe-Tech トップへ