ブラウザ自動化|Playwrightとbrowser-use比較
「browser-use」と「Playwright」、ブラウザ自動化のツール選定で迷っている方は多いのではないでしょうか。私自身、AIネイティブを謳う browser-use CLI 2.0 を1ヶ月運用した結果、突然動かなくなり、Playwright Python SDK へ全面的に書き直すという痛い経験をしました。この記事では、その過程で得た「ツールを使い分ける」という結論と、移行で見つかった具体的なノウハウを共有します。
1ヶ月前、なぜ私は browser-use CLI 2.0 を選んだのか
2026年4月の段階で、私は note への記事自動投稿スキルを構築する必要がありました。複数の候補を比較した結果、選んだのは browser-use CLI 2.0。当時、AIネイティブなブラウザ自動化ツールとして高い評価を受けていたものです。
採用理由はシンプルでした。
- 自然言語で「note にログインして、タイトルを入力して、本文を貼り付けて」と指示できる
- サイトの DOM 変化に LLM が追従するため、セレクタの保守が不要
- 未知サイトでも「とりあえずやってみて」が通用する
- 私の判断軸である「複雑さの排除」に合致していた
結果として、1325行の Python スクリプトを書き上げました。ログイン、タイトル入力、本文挿入、サムネイルアップロード、挿絵2枚、CTAバナー3枚、下書き保存まで、フル機能で動かすコードです。本文中には <!-- IMAGE: --> や <!-- CTA: top|middle|bottom --> といったマーカーを埋め込み、画像挿入位置をテキストレベルで指定できる設計にしました。
1ヶ月、数本の記事はちゃんと動きました。問題が起きるまでは。
突然壊れた日の症状 — synthetic event が弾かれる
2026年5月4日、note への記事投稿が突如機能しなくなりました。症状は次の通りです。
- 本文挿入を担う
set_body()関数が3つの戦略すべてで失敗 - 1つ目: 合成 ClipboardEvent を発火 → 失敗
- 2つ目:
document.execCommand('insertHTML')を直接呼ぶ → 失敗 - 3つ目:
innerHTML直接書き換え +inputイベント発火 → 失敗 - 結果として、タイトルとサムネイルだけ入った「本文0文字」の空ドラフトが5件以上量産
- 挿絵もCTAバナーも全滅
この症状にはどこか既視感がありました。記憶を辿ると、過去に Substack のエディタで同じ問題に遭遇していたのです。Substack には「pbcopy + Cmd+V 経由でしか動かない」というメモが残っていました。それと同じ事象が note にも適用されたタイミングだった、というのが結論です。
原因は note のエディタが ProseMirror ベースに移行した(または既存の検証強化が効いた)こと。ProseMirror は現代的なリッチテキストエディタフレームワークで、note・Notion・Substack・Linear・Confluence などで採用されています。このフレームワークは、JavaScript で生成された 合成イベント(synthetic event)を「本物のユーザー操作ではない」と判定して黙殺する仕様を持っているのです。

4時間の試行錯誤と claude-in-chrome MCP での部分成功
仮説検証に4時間以上かけました。順番に潰していった可能性は次のようなものです。
- プロセス競合? → 全プロセスをクリーンアップしても症状変わらず
- note の仕様変更? → 確実にエディタ側の挙動変更があった
- JavaScript injection の根本問題? → これが正解だった
仮説2と3を切り分けるため、寄り道として claude-in-chrome MCP を試しました。これは Anthropic 公式の Chrome 拡張ベースの MCP で、私が普段使っている Chrome をそのまま操作できます。ヘッドレスブラウザではなく、実際のユーザーセッションで動くため、本物の userActivation コンテキストを持っているはずでした。
結果は半分成功、半分失敗でした。
- 本文挿入は成功:
document.execCommand('insertHTML', false, html)が一発で通り、4650文字が入った - file_upload は失敗: Desktop / Downloads / Home の全パスで
-32000 "Not allowed"エラー
原因は claude-in-chrome MCP のサンドボックス層が file_upload を弾いていたことでした。本文とタイトルは入るのに、画像(サムネ・挿絵・CTAバナー)が一切入らない。結局、画像配置だけ手動で行う必要があり、自動化としては未完成のまま停滞しました。
ただ、この4時間は無駄ではありませんでした。「本物のキーイベント・本物の userActivation があれば execCommand は通る」という事実が確認できたからです。これが後の Playwright 移行の判断材料になりました。
抜本調査の結果 — Playwright が推奨される4つの理由
停滞を脱するために、私はいったん手を止めて30分ほど業界調査をしました。「これは私のコードの問題ではなく、ツールの問題かもしれない」と疑い直したのです。結果、いくつかの重要なファクトが見つかりました。
① browser-use 自身が Playwright を捨てて CDP 直叩きに移行している
browser-use の公式ブログ「Closer to the Metal」で、2025年末に Playwright ラッパー層を捨てて Chrome DevTools Protocol(CDP)を直接叩くアーキテクチャに移行したと宣言されています。理由は、Playwright のラッパー層がパフォーマンスと信頼性のボトルネックになっていたから。これはつまり「AIネイティブツールも結局、原始的な CDP に戻っていく」という業界トレンドの表れです。
② ProseMirror 突破の確定解が存在する
「How I Defeated ProseMirror」という海外の検証記事で、document.execCommand('insertText', false, text) だけは beforeinput イベントをネイティブに発火させるため、note・Substack・Notion・Linear・Confluence のすべてで動く確定解だと示されています。ただしこれを userActivation を持った状態で呼ぶ必要があり、合成イベント由来の呼び出しでは弾かれます。
③ Playwright の set_input_files() は CDP 直叩き
Playwright の locator.set_input_files() は、内部で DOM.setFileInputFiles という CDP コマンドを直接発行します。ラッパー層を経由しないため、ファイルアップロードの信頼性が高い。これが claude-in-chrome MCP で失敗していた file_upload の代替になります。
④ Playwright のキーボードイベントはハードウェアレベル相当
page.keyboard.press('Meta+V') は、CDP の Input.dispatchKeyEvent を呼びます。これはブラウザから見て「ハードウェアキーボードからの入力」とほぼ同等に扱われ、userActivation を獲得した状態でクリップボード paste を実行できます。これが ProseMirror の権限ゲートを通過する鍵でした。
調査結果として、推奨ツールの優先順位は以下のように整理されました。
- 第1候補: Playwright Python SDK 直叩き(同じサイトを毎日叩く決定論タスク向け)
- 第2候補: Playwright MCP(Claude Code から保険的に呼ぶ用途、GitHub 32k stars)
- 第3候補: Chrome DevTools MCP(upload_file ツールを持つ代替、GitHub 38.1k stars)
Playwright で書き直した結果と発見した7つのノウハウ
2026年5月5日、note 投稿スクリプトを Playwright Python SDK で書き直しました。結果、コード行数は 1325行 → 1037行(22%削減)。削減率が控えめなのは、各非自明判断の理由をドキュメント文字列で残したからで、実態のロジックは劇的にシンプルになりました。3〜4戦略の fallback チェーンが、単一メソッドに集約されています。
テスト結果は全項目 PASS。ログイン(永続プロファイル)、本文挿入(4544文字)、サムネアップロード(クロップ保存込み)、挿絵2枚、CTAバナー3枚、全リンク検証、すべて動きました。
移行作業の中で見つかった、ドキュメントには載っていない7つのノウハウを共有します。

① page.expect_file_chooser() が正解
note のファイル input は React popover の中で動的に生成されます。静的な locator.set_input_files ではセレクタが捕捉できません。代わりに、ネイティブのファイル選択ダイアログを横取りする expect_file_chooser を使います。
with page.expect_file_chooser() as fc_info:
page.locator('button:has-text("画像を追加")').click()
file_chooser = fc_info.value
file_chooser.set_files('/path/to/image.png')② クリップボード paste で ProseMirror を突破する
本文挿入は、HTMLをクリップボードに書き込んだ後、Meta+V でペーストするのが確実です。Playwright のキーボードイベントが userActivation を獲得しているため、ProseMirror の権限ゲートを通過します。
context.grant_permissions(
['clipboard-write'],
origin='https://editor.note.com'
)
page.evaluate('''
navigator.clipboard.write([
new ClipboardItem({"text/html": new Blob([html], {type: "text/html"})})
])
''')
page.keyboard.press('Meta+V')③ 物理 mouse.click(x, y) が JS の Range/Selection より確実
ProseMirror の reconciler は、JavaScript で設定した Selection を黙殺する場面があります。要素の bounding-rect を取得して右端を物理クリックし、その後 End キーを押すことで、確実にカーソルを末尾に配置できます。
④ figure id を Set で diff 追跡する
挿入した画像の figure 要素を特定したいとき、locator('figure').last は DOM 順で「最後の figure」を返しますが、後続の挿入で位置が変わると別物を指してしまいます。挿入の前後で Set<figure id> を取得して差分を取れば、新規追加された figure を確実に特定できます。
⑤ 属性セレクタ figure[id="..."] を使う
CSS 形式の figure#fig-abc はハイフンや特殊文字のエスケープ問題が起きます。属性セレクタに切り替えれば、id にどんな文字が入っていても安全に参照できます。
⑥ 検証パスを最後に必ず通す
初回の CTA リンク設定で、リンクが silently fail する場面が時々あります。最終スキャンで figcaption に「¥6,000」のようなキャプション文字列が含まれているかを確認し、欠けていれば再付与する検証パスを入れておくと、自動化の信頼性が一段上がります。
⑦ note のリンクUIは textarea + 適用ボタン
意外な落とし穴ですが、note のリンク挿入UIは <input> ではありません。<textarea placeholder="https://"> に URL を入力し、隣の「適用」ボタンをクリックする構造です。Enter キーでは確定しないので、ボタンクリックを忘れずに。
結論 — ツールを捨てるのではなく、サイト別に使い分ける
ここで重要なのは、browser-use を捨てるべきではないということです。私が下した結論は「ツールを使い分ける」というアーキテクチャ判断でした。

NGパターン: 1スクリプト内で混在
browser-use と Playwright を同じスクリプトで併用すると、セッション管理が複雑化し、デバッグ地獄に陥ります。プロファイルの取り合い・cookie の扱い・並列実行時のロック競合など、解決すべき問題が指数的に増えていきます。
OKパターン: スキル単位でツールを選ぶ
私の現状のスキル構成は次のようになっています。
- note 投稿スキル: Playwright(リッチエディタ + ファイルアップロード)
- Substack 投稿スキル: Playwright(同様の理由、書き直し検討中)
- X 投稿スキル: browser-use(通常フォーム、自然言語指示で十分)
- ココナラ出品管理スキル: browser-use(フォーム + 通常UI)
- 業種特化スクレイピング: browser-use(未知サイトへの AI 判断が強み)
判断軸 — Playwright を選ぶ場面
- React / ProseMirror 系のリッチエディタ操作(note / Substack / Notion / Linear / Confluence / Medium / Ghost など)
- Hidden file input への画像・動画アップロード
- ネイティブキーイベントを要求する操作(クリップボード paste など)
- 同じサイトを毎日叩く決定論タスク(コスト重視)
判断軸 — browser-use 2.0 を選ぶ場面
- 通常フォーム・ボタン操作(user activation のゲートがない)
- データ抽出・スクレイピング(DOM 構造が頻繁に変わる)
- 未知サイトの探索(事前にセレクタを書けない)
- DOM 変化への自己修復が必要
- 自然言語で「○○して××して」と複雑指示を出したい
1ヶ月前の判断は間違っていなかった
browser-use 2.0 自体は依然として優秀なツールです。失敗の本質は「現代的リッチエディタには合成イベントが効かない」というエッジケース知見が抜けていただけ。スキル全体の再構築は不要で、note まわりだけ書き直せば済みました。「全部捨ててやり直し」より「壊れた部分だけ書き直し」のほうが、健全な投資判断だと考えています。
業界全体の構造変化 — AI ネイティブツールの限界と回帰
この経験から、ブラウザ自動化ツール業界の構造変化が見えてきました。
browser-use は元々 Playwright + LLM のラッパーでした。それが2025年末に Playwright を捨てて CDP 直叩きに移行しました。背景には、ラッパー層が信頼性とパフォーマンスの両方でボトルネックになっていたという現実があります。
競合となる Stagehand v3、Skyvern、Computer Use Agent のような AI ネイティブツール群は、未知サイトを横断するタスクには強いものの、同じサイトを反復する用途では「LLM 課金 + 推論遅延」がオーバースペックになります。
一方で Playwright は Microsoft 公式・無料・Apache 2.0 ライセンス。2026年5月時点の業界調査でも信頼性スコア 92% という高水準です。AI ネイティブの「魔法」が剥がれた後、結局 deterministic(決定論的)なツールが残るというのが、この1年で起きていることだと感じています。
Claude Code Skills を活用した自動化全般の設計指針については、こちらの記事で詳しく整理しています。
これから始める人への即実行アドバイス
最後に、ブラウザ自動化を始める方・既に運用している方へ、具体的な行動指針を共有します。
既に browser-use を使っている方へ
- note / Substack / Notion / Linear などのリッチエディタを叩いている箇所を特定する
- その箇所だけ Playwright Python SDK に書き直す
- 他の部分(X、通常フォーム、スクレイピング)は browser-use を継続して問題ない
これから始める方へ
- 同じサイトを反復するタスクなら、Playwright Python SDK を最初から選ぶ
- セットアップは
pip install playwright && playwright install chromiumで完了 - セレクタは
playwright codegen <URL>でブラウザ操作を録画して自動生成できる - ログイン状態の維持は
launch_persistent_contextでプロファイルを永続化する - リッチエディタへの本文挿入は
execCommand insertText経路を最初から組み込む
4つのメタ学習 — ツール選定で繰り返したくない判断ミス
この一連の試行錯誤から得たメタな教訓を、最後に整理しておきます。
① ツール選定は「実装でぶつかってから」変える
1ヶ月前の判断時点で、ProseMirror 系エディタのエッジケースは予測できませんでした。新しいツールには必ず「使ってみないと分からないエッジケース」が存在します。事前の完璧な選定を目指すより、ぶつかってから抜本調査して書き直すほうが、結果的にコストが低いことが多いです。
② AI ネイティブツールにも限界がある
browser-use の自己修復能力は強力です。しかし、user activation を必要とするフレームワーク(React の合成イベント検証、ProseMirror の権限ゲート、Web Authentication API など)には届きません。「LLM が解釈する層」と「ブラウザが実行する層」の間に、原理的な隙間が存在することを覚えておくべきです。
③ 抜本調査は早めに
4時間以上のデバッグ前に、Playwright との比較調査をすべきでした。「これは私のコードの問題ではなく、ツールの問題かもしれない」と疑う判断が、私は遅れました。30分試して動かなかったら、その後の3.5時間は同じ場所で堂々巡りになる可能性が高いです。手を止めて業界調査に振り直す勇気が必要です。
④ AI ネイティブと deterministic を意識的に使い分ける
- 同じサイトを毎日叩く → deterministic(Playwright)
- 未知サイトを探索する → AI ネイティブ(browser-use)
この使い分けを意識的に行うと、トークン課金と信頼性の両方を最適化できます。「全部 AI で」「全部スクリプトで」のどちらかに振り切るのではなく、タスク特性に応じて適材適所で配置するのが、現時点での最適解だと考えています。
まとめ
browser-use CLI 2.0 から Playwright Python SDK への部分的な移行を通じて、私が学んだことは「ツールを捨てるのではなく、サイト別に使い分ける」というアーキテクチャ判断でした。リッチエディタ + ファイルアップロードは Playwright、通常フォーム + スクレイピング + 未知サイトは browser-use、という棲み分けが現時点の最適解です。
1ヶ月前の判断は間違っていませんでした。間違っていたのは「すべてのサイトに同じツールが効く」という前提です。AI ネイティブと deterministic、それぞれの強みが活きる場面を意識的に選ぶことで、自動化スキルの保守コストと信頼性を両立できます。
ブラウザ自動化ツールの選定で迷っている方は、まず「対象サイトのエディタが ProseMirror か」「ファイルアップロードが Hidden input か」を確認するところから始めてみてください。それだけで、最初の選択ミスを大きく減らせるはずです。
「AIで何ができるか分からない」「興味はあるが業務に活かせていない」
── そんな方は、まず1回お話ししてみませんか。
→ AI業務効率化のスポット相談(30分 ¥6,000〜・初回限定)
御社の業務に合わせたClaude Code導入支援
「AIツールを導入したが、現場で使われない」を終わらせる。
業務課題のヒアリングから設計、ハンズオン実践、運用定着まで一貫して支援します。
