ヘッドレスブラウザ検出: 原因と対処法 (2026)
サイトが「headless browser detected(ヘッドレスブラウザを検出)」と表示したり、自動化されたブラウザに対して静かに別のページを返したりすることがあります。ヘッドレスブラウザはウィンドウを持たずに動作し、通常のデスクトップブラウザとは細かな点で測定可能な違いがあるため、サイトはこれを確認します。このガイドでは、サイトが確認している信号、自分のブラウザが何を露出しているかの調べ方、そして妥当な対処法を説明します。キャプチャのステップとして扱うべき場合や、そこで止めるべき場合についても取り上げます。
サイトがヘッドレスブラウザを確認する理由
自動化フレームワークは本物のブラウザエンジンを動かすため、ページの大部分は同じように動作します。違いが出るのは端の部分です。
- 自動化のフラグ。 自動化ツールで操作されるブラウザは、これまで
navigator.webdriverがtrueに設定されて露出してきました。フレームワークによっては、ページに他の痕跡を残すこともあります。 - 欠けている、または不自然なブラウザ機能。 ヘッドレス版では、プラグインが報告されない、言語一覧が不自然、あるいは実際の画面サイズと合わないウィンドウサイズになることがあります。
- 描画の違い。 Canvas や WebGL の出力は、ヘッドレス環境とヘッドありの環境で異なることがあります。特に GPU のないサーバーでは顕著です。
- タイミング。 自動化されたクリックやページ読み込みは、人間では出せないリズムで行われがちです。
- ネットワークの振る舞い。 リクエストヘッダー、その順序、TLS ハンドシェイクから、ブラウザ以外のクライアントであることが分かることがあります。
サイトはこれらの信号を組み合わせてスコアを付けます。低いスコアは、静かなダウングレード、追加の確認、またはブロックにつながることがあります。
ステップ 1: ブラウザが何を露出しているか確認する
何かを変更する前に、自動化されたブラウザからページが何を読み取れるかを確認します。以下のスクリプトは、自分が管理するページを開き、重要な信号を表示する診断用のものです。自分のテストページでのみ使い、他人のシステムを調べるために使わないでください。
from playwright.sync_api import sync_playwright
CHECK = """() => ({
webdriver: navigator.webdriver,
languages: navigator.languages,
plugins: navigator.plugins.length,
userAgent: navigator.userAgent,
screen: [screen.width, screen.height],
viewport: [window.innerWidth, window.innerHeight],
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
})"""
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example.com") # 自分が所有するページに置き換えてください
print(page.evaluate(CHECK))
browser.close()
同じスクリプトを headless=False で実行し、2つの出力を比較してください。その差分が、サイトが気づきうる点です。
ステップ 2: フラグだけでなく不整合を直す
一つのフラグだけを隠して、他を変えないのは最も多い失敗です。User-Agent は Windows と名乗っているのに、フォント、タイムゾーン、画面サイズが Linux サーバーを示していると、単一のプロパティよりも強い信号になります。内部的に一貫した環境を目指してください。
- できればヘッドありのブラウザを使うか、現在のデスクトップブラウザに合わせたヘッドレスモードを使います。
- ビューポートと言語を互いに一致させます。
- タイムゾーンとロケールは、使用する IP アドレスと整合させます。
- 実行のたびに新規で始めるのではなく、一つの ID には一つのプロファイルとそのクッキーを再利用します。
Playwright では、これらのいくつかを一箇所で設定できます。
context = browser.new_context(
locale="en-US",
timezone_id="America/New_York",
viewport={"width": 1366, "height": 768},
)
page = context.new_page()
ステップ 3: 速度を落とし、訪問者らしく振る舞う
人間が追いつけないほど速い自動化は、すぐに目立ちます。ページ読み込みの間に現実的な待ち時間を入れ、同じ要素を完璧なリズムでクリックするのを避け、一つのアドレスから何百ものページを並列に開かないでください。リクエストを少なく、ゆっくり送ることはサイトへの負荷も減らすので、いずれにせよ正しい行いです。
ステップ 4: 確認がキャプチャかどうかを見分ける
一部の検出フローは、ブロックではなくチャレンジで終わります。キャプチャのウィジェットが表示され、そのステップではソルバーからのトークンが必要になります。Scarnox で現在ライブのキャプチャ種別は PopularCaptcha です。トークンの取得と送信方法は PopularCaptcha の Python ガイド で解説しています。Cloudflare Turnstile など他のウィジェットはロードマップ上にありますが、まだライブではありません。計画を立てる前に キャプチャ種別の解説 を確認してください。
キャプチャのステップが出たからといって、それ以外の構成が正しいとは限りません。設定をどう変えても、そのサイトが毎回ヘッドレスのセッションをブロックするなら、そのサイトの所有者が自動アクセスを望んでいないという明確なサインです。それを尊重してください。
やってはいけないこと
自動化を禁じているサイトから自動化を隠そうとしたり、アクセス制御を回避するために検出回避ツールを使ったりしないでください。それは、このガイドが扱うテストや公開データの収集とは別種のプロジェクトです。必要なアクセス権を得ていない場合は、サイトの所有者に確認するか、公式 API やデータフィードを探してください。
責任を持ったスクレイピング
- 自動化する前に
robots.txtとサイトの利用規約を確認してください。 - リクエスト頻度を低く保ち、取得済みのページはキャッシュしてください。
- ブロックは答えとして受け止め、回避すべきパズルとして扱わないでください。
- 法的根拠なしに個人データを収集しないでください。
次のステップ
自動化が E2E テストのためであれば、アプローチは異なります。自動テストでのキャプチャ を参照してください。Playwright や Puppeteer を使っている場合は、Playwright と Puppeteer でのキャプチャ処理 でトークンの置き場所を解説しています。
まずは無料トライアルクレジットから始めましょう。クレジットカード不要で、アカウントを作成して、自分のページで PopularCaptcha のフローを試せます。現在の料金は料金ページをご覧ください。