playwright-bot-bypass について
Playwright Bot Bypass は、許可されたテスト向けのブラウザー自動化スキルです。rebrowser-playwright とヘッドモードの実 Chrome を使い、一部の自動化シグナルを減らします。自社サイトの QA、アクセシビリティテスト、研究向けですが、行動・IP 検知の回避や CAPTCHA 通過を保証しません。
主な機能
- 01rebrowser-playwright の利用
- 02ヘッドモードの実 Chrome で実行
- 03一部の Playwright 痕跡を除去
- 04ブラウザーファクトリーのテンプレート
- 05検知テストスクリプトを提供
活用シーン
- 01自社サイトの自動 QA
- 02ウェブアクセシビリティのテスト
- 03ブラウザー自動化検知の研究
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ greekr4/ playwright-bot-bypass --skill playwright-bot-bypassインストール後、Claude Code で/playwright-bot-bypassを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.gitignorepackage-lock.jsonpackage.jsonexamples/ab-test.mjsstealth-google-search.mjsstealth-twitter-scrape.mjsscripts/bot-detection-test.mjsstealth-template.mjs詳細
Playwright Bot Bypass
rebrowser-playwright と実際のヘッド付き Chrome を使用して、ボット検出を軽減します。フィンガープリントチェッカー(bot.sannysoft.com、areyouheadless)を通過し、Google で CAPTCHA が発生するのを回避します。CDP/ランタイムを認識するエンタープライズ向けボット管理システムを確実に回避できるわけではありません。測定結果については「Detection Coverage」をご覧ください。
許可された用途に限ります。 これは、所有しているサイト、またはテストを許可されているサイトでの QA、アクセシビリティテスト、調査を目的としています。各サイトの利用規約、
robots.txt、適用される法律を遵守してください。ペイウォールの回避、レート制限の悪用、またはサイトが明示した意向に反するスクレイピングには使用しないでください。
検出を回避する方法(およびそのレイヤー)
回避は1つではなく、3つのレイヤーによって実現されます。大部分を担うのは手書きの JS ではなく、実際のブラウザーです。
| 検出ポイント | 標準の Playwright(ヘッドレス) | 回避するもの |
|---|---|---|
CDP/Runtime.enable の漏えい | 存在する(ヘッドレスの兆候) | rebrowser + REBROWSER_PATCHES_RUNTIME_FIX_MODE(自動設定) |
window.__pwInitScripts(isPlaywright) | 存在する | アーティファクトの除去(初期化スクリプトがページ遷移のたびに削除) |
navigator.webdriver | true | rebrowser(false を返します。削除はしていません。undefined 自体が検出の手がかりになります) |
| WebGL レンダラー | SwiftShader(ソフトウェア) | channel:'chrome' + ヘッド付きモード(実際の GPU) |
| ユーザーエージェント | "HeadlessChrome" を含む | channel:'chrome'(実際の Chrome UA)。JS による上書きなし |
| Canvas フィンガープリント | ソフトウェアレンダリングの兆候 | ヘッド付きの実際の Chrome(本物の GPU キャンバス)。JS による細工なし |
navigator.plugins | 空の配列 | ヘッド付きの実際の Chrome(本物の PluginArray)。JS による偽装なし |
navigator.languages | ['en-US'] のみ | locale オプション(ネイティブでワーカーと整合し、JS ゲッターなし) |
なぜ手書きの JS がこれほど少ないのですか? v2.1/v2.2 では、以前の偽 PluginArray、キャンバスノイズ、固定値の
hardwareConcurrency、Permissions の上書き、webdriverの削除、navigator.languagesゲッターをすべて削除しました。どれも検出可能な不整合(独自プロパティによる兆候、ワーカーとの不一致、undefinedの webdriver、Illegal invocationクラッシュ)を生み出していたためです。v2.2 で有効な対策は2つだけです。Playwright の__pwInitScriptsアーティファクトを除去し、rebrowser の Runtime-fix を有効にします。それ以外はすべて、実際のブラウザー本来の一貫した動作です。偽装を減らすほど一貫性が高まり、検出されにくくなります。
前提条件
- Node.js 18 以降(ESM をサポート。
.mjsファイル) - Google Chrome がインストール済みであること(Chromium のみでは不可)
- ヘッド付きモードが必須(
headless: false)。ディスプレイがなければステルス動作はできません
Chrome がインストールされていることを確認します。
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --version
# Linux
google-chrome --version
クイックスタート
1. インストール
npm init -y && npm install rebrowser-playwright
2. stealth-test.mjs を作成
import os from 'node:os';
import path from 'node:path';
// Enable rebrowser's Runtime.enable fix BEFORE importing the library.
process.env.REBROWSER_PATCHES_RUNTIME_FIX_MODE ??= 'addBinding';
const { chromium } = await import('rebrowser-playwright');
const browser = await chromium.launch({
headless: false, // headed = real GPU/canvas
channel: 'chrome', // real Chrome = real UA/WebGL/plugins
args: ['--disable-blink-features=AutomationControlled']
});
// `locale` sets navigator.languages + Accept-Language natively & consistently.
const context = await browser.newContext({ locale: 'ko-KR' });
// The ONLY init script: strip Playwright's main-world signature. Touch NOTHING
// on navigator — the real browser's values are already genuine & consistent.
await context.addInitScript(() => {
for (const k of Object.getOwnPropertyNames(window)) {
if (/^__pw|pwInitScripts|playwright/i.test(k)) {
try { delete window[k]; } catch {}
}
}
if (!window.chrome) window.chrome = {};
});
const page = await context.newPage();
try {
await page.goto('https://bot.sannysoft.com', { waitUntil: 'networkidle' });
const out = path.join(os.tmpdir(), 'stealth-test.png');
await page.screenshot({ path: out });
console.log(`Screenshot saved: ${out}`);
} finally {
await browser.close();
}
3. 実行
node stealth-test.mjs
テンプレートを使用する(推奨)
scripts/stealth-template.mjs は、すべてのパッチがあらかじめ適用された、再利用可能なファクトリーを提供します。
import { createStealthBrowser, humanDelay, humanType, simulateMouseMovement } from './scripts/stealth-template.mjs';
const { browser, page } = await createStealthBrowser();
try {
await page.goto('https://example.com');
// Human-like mouse movement (avoids Cloudflare Turnstile)
await simulateMouseMovement(page);
// Human-like typing instead of instant fill
await humanType(page, 'input[name="q"]', 'search query');
await humanDelay(300, 800);
} finally {
await browser.close();
}
テンプレートのオプション
const { browser, context, page } = await createStealthBrowser({
headless: false, // Required for stealth (default)
viewport: { width: 1280, height: 800 }, // Default
locale: 'ko-KR', // Browser locale (default)
userAgent: null, // Custom UA (optional; default = real Chrome UA)
storageState: './session.json', // Cookie persistence (optional)
proxy: { server: 'http://proxy:8080' }, // Proxy (optional)
noSandbox: false // Opt-in --no-sandbox (Linux root/CI only; it's a bot signal)
});
// Save session for reuse
import { saveSession } from './scripts/stealth-template.mjs';
await saveSession(context, './session.json');
テンプレートが実際に行うこと
テンプレート(v2.2)が対象とするのは、次の2つの対策だけです。
| 対策 | 理由 |
|---|---|
window.__pwInitScripts / __playwright* を削除する(初期化スクリプト、すべてのナビゲーション) | 検出ツールが利用する、確定的な isPlaywright のシグネチャを取り除きます |
REBROWSER_PATCHES_RUNTIME_FIX_MODE=addBinding(インポート前に自動設定) | CDP の Runtime.enable によるヘッドレスの漏えいを隠します |
navigator には何も手を加えません。その他はすべて実際のブラウザー(channel:'chrome' + headed)に任せています。これにより、本物の User-Agent、WebGL/GPU レンダラー、canvas フィンガープリント、PluginArray、一貫性のある権限・ハードウェア値、そして(locale オプションを介した)ネイティブワーカーと一致する navigator.languages + Accept-Language が得られます。
v2.1/v2.2 で削除(実際の環境と値の一貫性がなく、いずれも総合的に悪影響があったため):偽の navigator.plugins、canvas getImageData のノイズ、固定値の hardwareConcurrency/deviceMemory、outerWidth/Height のオフセット、権限の上書き(Illegal invocation でクラッシュ)、navigator.webdriver の削除(undefined になり、かえって手掛かりになる)、navigator.languages ゲッター(独自プロパティとワーカー不一致の手掛かりになる)。
起動引数:--disable-blink-features=AutomationControlled。--no-sandbox はオプトイン({ noSandbox: true })です。セキュリティリスクであると同時に自動化のシグナルでもあるため、デフォルトでは無効です。
負荷の高い SPA(TikTok/IG/FB)では、
addBindingモードで致命的ではない[rebrowser-patches] cannot get world警告が出ることがありますが、ページは引き続き読み込まれます。必要であれば、REBROWSER_PATCHES_RUNTIME_FIX_MODE=alwaysIsolatedに切り替えると警告を抑制できます。
スクリプト
scripts/stealth-template.mjs— 再利用可能なステルスブラウザーファクトリー(すべての例でこれをインポートします)scripts/bot-detection-test.mjs— bot.sannysoft.com で回避を検証します
例
examples/stealth-google-search.mjs— CAPTCHA を回避した Google 検索examples/ab-test.mjs— 検出ありとステルスの並列比較examples/stealth-twitter-scrape.mjs— Twitter/X プロフィールのスクレイピング
注:
ab-test.mjsにはrebrowser-playwrightとplaywrightの両方が必要です。npm install rebrowser-playwright playwright && npx playwright install chromium
すべてのスクリーンショットは OS の一時ディレクトリ(os.tmpdir())に保存されます。macOS/Linux では /tmp、Windows では %TEMP% です。
検出範囲(2026-06-10 測定、macOS の headed Chrome、v2.2)
正直で、実際にテストした結果です。v2.2 のアーティファクト削除と Runtime 修正により、すべてのフィンガープリント/自動化検出が合格になりました。
| 検出ツール | 結果 | 注記 |
|---|---|---|
| bot.sannysoft.com | ✅ すべて緑 | webdriver は false、WebGL/UA/plugins は本物 |
| arh.antoinevastel.com/bots/areyouheadless | ✅ 「not Chrome headless」 | |
| hmaker.github.io/selenium-detector | ✅ 「Passing」 | chromedriver なし |
| bot-detector.rebrowser.net | ✅ 赤 0 件 | __pwInitScripts を削除、Runtime の漏えいなし、webdriver は false |
| deviceandbrowserinfo.com/are_you_a_bot | ✅ 「You are human!」 | isBot:false、isPlaywright:false |
| browserscan.net/bot-detection | ✅ 「Normal」 | CDP テストに合格(Runtime 修正) |
| iphey.com | ✅ 「Trustworthy」 | v2.2 より前は「Unreliable」でした |
| creepjs | ✅ ヘッドレス 0% / ステルス 0% | あいまいな「38% like headless」は検出ではありません |
| nowsecure.nl(Cloudflare Turnstile) | ⚠️ インタラクティブなチャレンジが表示されます | 動作/IP によるゲートであり、フィンガープリントのチェックではありません。自動通過しません |
信頼性:繰り返し実行した 9/9 回で問題なし(__pwInitScripts の削除はすべてのナビゲーションで維持されました)。
v2.2 がこれを実現する仕組み(そして解決できない唯一のこと)
createStealthBrowser() に組み込まれた、2 つの対策があります。
- アーティファクトの除去 — 初期化スクリプトが、ナビゲーションのたびに
window.__pwInitScripts/__playwright*(決定的なisPlaywrightシグネチャ)を削除します。 REBROWSER_PATCHES_RUNTIME_FIX_MODE=addBinding— インポート前に自動設定され、CDP のRuntime.enable漏えいを隠します。
残存する漏えい: window.__playwright_builtins__ は、削除も再定義もできない、別個の構成不可な Playwright グローバルです。現時点では、上記の検出器はいずれもこれを検出条件にしていませんが、将来の検出器が利用する可能性があります。rebrowser のどのバージョンでも(現在お使いのものは最新の 1.52.0 です)これを削除できません — rebrowser-patches#110 で上流に報告されていますが、未解決で修正されていません。
要点: フィンガープリント検出と自動化フレームワーク検出に対しては有効です。ただし、行動・IP ベースのシステム(Cloudflare Turnstile、DataDome、Kasada)やログインウォールを確実に回避できるわけではありません。こうしたケースでは、住宅用 IP と実際の操作を追加するか、エンジンを切り替えてください — patchright(そのまま差し替えて使用可能)または nodriver(CDP/自動化プロトコル全般を構造的に回避します)。
実際のコミュニティサイト(ログアウト状態での単一ロード、住宅用 IP、2026-06-10)
実際のサイトが v2.2 のページ読み込みをボットとしてブロックするかをテストしました(ログイン判定ではありません)。
| サイト | 結果 |
|---|---|
| Reddit、YouTube、Pinterest、Threads、X(直接 URL)、Quora、TikTok | 🟢 コンテンツが完全に読み込まれました — ボット検証も CAPTCHA もありません |
| Instagram、Facebook、LinkedIn | 🟡 標準的なログアウト状態のログインモーダルの背後でコンテンツのシェルが読み込まれました — ボットブロック/チェックポイント/HTTP 999 ではありません |
主な結果: どのサイトからもボット検証やハードブロックは返されませんでした。最も厳しいサイト(IG/FB/LinkedIn)でも、ログアウト状態の通常のユーザー向け表示(表示されたコンテンツの上にログインモーダルが重なる状態)が提供され、ステルス機能が実ユーザーとして認識されたことを示しています。注意点: これは、クリーンな住宅用 IP から各サイトを 1 回ずつ読み込んだ結果です。大量にアクセスすると、IG/FB/LinkedIn では datr Cookie のエイジング、HTTP 999、レート制限が適用されます。これらは IP/アカウントの問題であり、フィンガープリントの問題ではないため、このスキルでは対処できません。TikTok の署名付き API を使う操作(プロフィールの閲覧以外)にも、引き続き十分に利用履歴を積んだセッションが必要です。
制限事項
headless: false(ディスプレイを使うヘッドありモード)が必要です- 実際の Google Chrome のインストールが必要です(
channel: 'chrome') - サイトによっては、行動パターンに基づいて検出される場合があります —
humanDelay、humanType、simulateMouseMovementを使用してください - CAPTCHA を回避するのではなく、CAPTCHA が表示されるのを防ぐだけです
- TLS/JA3 フィンガープリントは
channel: 'chrome'で処理されます(実際の Chrome バイナリを使用します) __pwInitScriptsの漏えい(「検出範囲」を参照)はスキルレベルでは修正できません — rebrowser-playwright 1.52.0 に固有のものです
Python のサポート
undetected-chromedriver(推奨)
pip install undetected-chromedriver
import undetected_chromedriver as uc
# Match your Chrome version: check chrome://version
driver = uc.Chrome() # auto-detects version
driver.get("https://www.google.com")
search_box = driver.find_element("name", "q")
search_box.send_keys("your search query")
search_box.submit()
Python の
playwright-stealthは JavaScript レベルでのみパッチを適用するため、WebGL には引き続き SwiftShader が表示されます。代わりにundetected-chromedriverを使用してください。
代替方法:Python から Node.js を呼び出す
import subprocess
result = subprocess.run(['node', 'stealth-script.mjs', query], capture_output=True)
トラブルシューティング
| 問題 | 修正方法 |
|---|---|
ERR_MODULE_NOT_FOUND | スクリプトと同じディレクトリで npm install rebrowser-playwright を実行してください |
| ブラウザーが開かない | Chrome がインストールされていることを確認してください(前提条件を参照) |
| WebGL に SwiftShader が表示される | 実質的にヘッドレス、または GPU がありません。実際の GPU を搭載したマシンで、channel: 'chrome' を指定してヘッドあり(headless: false)で実行してください。SwiftShader はソフトウェアフォールバックであり、インポートの問題ではありません |
| 引き続き検出される | 操作の間に simulateMouseMovement() と humanDelay() を追加してください |
| プロセスがハングする | browser.close() が finally ブロック内にあることを確認してください |
SyntaxError: await | ファイルの拡張子を .mjs にするか、package.json に "type": "module" を指定してください |