LLM の学習データセット、EC の価格比較、評判のモニタリング、業界別 RAG ナレッジベースには、大量の Web データをリアルタイムで収集する仕組みが欠かせません。しかし現在、価値の高いサイトの 70% 以上が Cloudflare、Akamai、DataDome、Kasada などの企業向け WAF を導入しています。1 台のマシンで固定 IP を利用したり、User-Agent を変更したりするだけでは十分ではなく、クライアントのプロトコルフィンガープリントやリクエストの動作にも配慮が必要です。

1. ボット検知技術の進化

Web スクレイピングとその対策の発展を振り返ると、ボット検知技術は大きく 4 つの段階を経て進化してきました。

  • 第 1 世代(静的な特徴による検出): HTTP ヘッダーの User-Agent、Referer、Host などを確認し、IP ごとにリクエスト頻度を制限します(Rate Limiting)。
  • 第 2 世代(動的な JS チャレンジ): 難読化した JavaScript を実行し、PoW(プルーフ・オブ・ワーク)を計算して、ヘッドレスブラウザーの特徴を検出します(window.navigator.webdriver)。
  • 第 3 世代(ネットワーク層とプロトコルのフィンガープリント): TLS ハンドシェイクの Client Hello に含まれる暗号スイート(JA3/JA4)と、HTTP/2 接続確立時の SETTINGS・WINDOW_UPDATE フレームの特徴を照合します。
  • 第 4 世代(AI による行動分析とマルチモーダル認証): ジャイロセンサーやマウスの軌跡、キー入力間隔のエントロピー、Turnstile 認証、ネットワーク全体の IP 評価に基づく動的なブロックを組み合わせます。

2. TLS フィンガープリント:JA3/JA4 と HTTP/2 フレーム

開発者からは、「Python Requests にプロキシを設定しても、なぜ Cloudflare にすぐブロックされるのか」という疑問がよく寄せられます。その理由は、TLS Client Hello のフィンガープリントにあります。

Python が標準的に使用する urllib3 / OpenSSL は、TLS ハンドシェイク時に暗号スイート、拡張機能、楕円曲線グループの一覧を送信します。これらは実際の Google Chrome が送信するものと大きく異なります。

検出の手がかり:Python Requests の JA3 フィンガープリント

一般的な Python ライブラリの JA3 フィンガープリントは固定的で、ほぼすべての WAF が明確なクローラーの特徴としてブロックリストに登録しています。評価の良好な静的レジデンシャル IP を 10 万個保有していても、HTTP リクエストのデータ送信前に 403 Forbidden が返されたり、5 秒間のチャレンジが始まったりします。

TLS フィンガープリントに対応するため、最新のスクレイピングでは、curl_cffi や tls-client のように TLS Spoofing をサポートするネットワークライブラリを使い、Chrome や Firefox と 100% 同じ特性のハンドシェイクを再現します。

3. Cloudflare の 5 秒チャレンジと Turnstile

Cloudflare Turnstile は、従来の reCAPTCHA に代わって普及しつつあります。クライアント側で複雑な計算を目立たない形で実行し、接続元 IP のレピュテーションを総合的に評価します。

  1. クリーンな IP はスムーズに通過:Turnstile は複数の情報をもとに判定します。住宅 IP だけで認証成功が保証されるわけではないため、接続先でテストし、求められる確認に対応してください。
  2. データセンター IP には追加の認証: 既知のデータセンターの IP 範囲からアクセスすると、ブラウザーのフィンガープリントを再現していても、WAF が対話的なチェックボックスを 1 回以上表示し、自動収集の処理速度を大きく低下させます。

4. 高スループットの混合プロキシプールを設計する

企業が大規模なデータ収集を行う場合、本番環境で成熟した構成は、すべての通信に高価なレジデンシャル IP を使うのではなく、通信の種類に応じて振り分ける 2 層のプロキシゲートウェイを採用します。

┌─ クライアントクラスター (Scrapy / Playwright / Go Colly)
│ └─► 収集リクエストを送信
├─ 第 1 層:スマートルーター (Smart Router)
│ ├─ 対象サイトの保護レベルを確認
│ ├─ 保護レベルの低い静的リソース (CSS, JS, 画像, 文書) ──► IP123 静的データセンタープロキシ(利用可能な帯域幅を確認)
│ └─ 保護レベルの高い主要データ (商品情報, 価格 API, 検索結果) ──► IP123 静的レジデンシャルプロキシ(接続先へのアクセスをテスト)
└─ 動的サーキットブレーカーと自動再試行
429/403 が返った場合は応答内容と再試行の指示を確認してください。同じセッションでは割り当て済みの静的 IP を維持してください。別の IP でもリクエストの受付は保証されません。

5. Python による自動化とセッション維持

以下は接続方法を示すサンプルで、curl_cffi と例示用の接続先を使用しています。実際のプロキシ接続先と対象 URL に置き換えてください。保護されたページへのアクセスを保証するコードではありません。

import time
from curl_cffi import requests

# 配置 IP123 专线代理 IP 网关
PROXY_URL = "http://customer_user:pass_token@gateway.ip123.net:8888"

proxies = {
    "http": PROXY_URL,
    "https": PROXY_URL,
}

def fetch_protected_site(target_url: str):
    # impersonate="chrome120" 将自动模拟 Chrome 的 TLS JA3/JA4 与 HTTP/2 帧特征
    session = requests.Session()
    
    headers = {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
        "Sec-Ch-Ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
        "Sec-Ch-Ua-Mobile": "?0",
        "Sec-Ch-Ua-Platform": '"Windows"',
    }
    
    try:
        response = session.get(
            target_url,
            headers=headers,
            proxies=proxies,
            impersonate="chrome120",
            timeout=15
        )
        print(f"[+] Status: {response.status_code}, Length: {len(response.text)}")
        return response.text
    except Exception as e:
        print(f"[-] Request failed: {e}")
        return None

if __name__ == "__main__":
    url = "https://example-cloudflare-protected-site.com"
    html = fetch_protected_site(url)

最新のデータ収集クラスターには、精度の高い TLS エミュレーションクライアントと、評価の良好なネイティブのレジデンシャルプロキシの組み合わせが必要です。IP123 のノードは、高い同時接続数で短時間接続と持続接続をサポートし、大規模なデータ収集に必要な可用性を提供します。