0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

"PythonでDataDomeをバイパスする:完全ガイド2026"

0
Last updated at Posted at 2026-03-11

Medium image

PythonでDataDomeをバイパスする

PythonでDataDomeをバイパスする:完全ガイド2026

免責事項:私はBright Dataやこの記事で言及されている他のツールとは関係ありません。すべての意見は、実際の調査に基づく私自身のものです。

TL;DR

  • DataDomeが実際に何であるか、そしてなぜ本当に打破するのが難しいのか
  • DataDomeがスクレイパーに対して使用する5つの検出レイヤー
  • コードファーストの技術:TLSなりすまし、ステルスブラウザ、プロキシローテーション、行動模倣
  • バイパスパイプラインの完全なMermaidアーキテクチャ図
  • 自分のスタックを構築することが意味をなさなくなる時

1. DataDomeに特有の問題

あなたは以前にレート制限をバイパスしたことがあるでしょう。今回は違う感じがします — 実際にそうです。
DataDomeは、ヘッダーを偽装して通過できる単純なファイアウォールではありません。それは、主要な欧州のeコマースプラットフォーム、チケット販売サイト、市場を含む1,200社以上の企業によって使用されているリアルタイムAIスコアリングエンジンです (DataDome.co)。
それは、あなたが人間かどうかを判断するために1日あたり3兆の信号を処理します。
あなたのクリーンなPythonスクレイパーは、最初のリクエストで失敗します。修正を理解する前に、戦いを理解する必要があります。

2. DataDomeが実際にあなたを検出する方法

DataDomeは、バイナリの「ボットかどうか」のスイッチを切り替えるわけではありません。それは、5つの同時検出レイヤーを通じてリアルタイムで信頼スコアを構築します (Scrapfly, 2026)。
1つのレイヤーを見逃すと、スコアが閾値を下回ります。その時に403、スライダーCAPTCHA、または静かな空のHTMLが表示されます。
評価速度の順に5つのレイヤー:

レイヤー チェックされる内容 DataDomeの方法
TLSフィンガープリンティング 暗号スイート、拡張順、JA3ハッシュ JA3/JA4ハンドシェイク時のハッシュ
IPレピュテーション ASNタイプ、悪用履歴、データセンター範囲 リアルタイムIPデータベースルックアップ
HTTP詳細 プロトコルバージョン、ヘッダー順、欠落フィールド HTTP/1.1 vs HTTP/2分析
ブラウザフィンガープリンティング Canvas、WebGL、navigator.webdriver、プラグイン JavaScript実行エンジン
行動分析 マウスカーブ、スクロールリズム、ナビゲーションフロー セッションパターンに対するMLモデル

信頼スコアは静的ではありません。セッション中に継続的に再計算されます。最初の3つのチェックを通過したスクレイパーでも、スクロールの動作がロボットのように見えると、ページ3でブロックされる可能性があります。

3. DataDomeブロックの特定

バイパスを構築する前に、実際にDataDomeに対処していることを確認してください。明らかな兆候は一貫しています:

  • 最初または早いリクエストでのHTTP 403 Forbidden
  • Set-Cookieレスポンスヘッダー内のdatadome
  • レスポンスヘッダー内のx-datadome-cidフィールド
  • サイトコンテンツの代わりにスライダーCAPTCHAページが読み込まれる
  • ブロックされたレスポンスHTML内のスクリプトタグにddという文字列が表示される
curl -I https://www.target-site.com
# Look for: set-cookie: datadome=...
# Or:       x-datadome-cid: ...

確認が取れたら、どのレイヤーと戦っているかがわかります。では、1つずつ戦っていきましょう。

4. レイヤー1 — TLSフィンガープリンティング:目に見えない第一撃

これはDataDomeの最も速く、最も厳しいチェックです。あなたのヘッダーが到着する前に発動します
PythonのrequestsライブラリがHTTPS経由で接続すると、TLSハンドシェイクがJA3ハッシュを露出します — あなたの暗号スイートの順序、拡張リスト、プロトコルバージョンのフィンガープリントです。requests/urllib3のJA3ハッシュはChromeのものとはまったく異なります (DataDome Engineering, 2022)。
DataDomeは既知のボットフィンガープリントのデータベースを維持しています。あなたのリクエストはミリ秒で一致します。
修正方法: curl_cfficurl-impersonateをラップし、Chromeの正確なTLSハンドシェイクを再現するPythonライブラリです。

# pip install curl_cffi
from curl_cffi import requests
session = requests.Session(impersonate="chrome")
response = session.get("https://target-site.com")
print(response.status_code)  # Should be 200, not 403
```impersonate="chrome"``` パラメータは、単にヘッダーを偽装するだけではありません。**TLSハンドシェイク全体** — 暗号スイートの順序、拡張値、HTTP/2フレーム設定 — をChrome 131+に正確に一致させるように変更します。

*サポートされているなりすましターゲットには```chrome``````chrome131``````safari``````safari_ios```、および```edge101```が含まれます。このライブラリは、ブラウザが新しいバージョンをリリースする際にこれらのフィンガープリントを更新します。*

この単一の変更で、DataDomeブロックのかなりの部分が解決されます。しかし、これはレイヤー1に過ぎません。

### 5. レイヤー2 — HTTPヘッダー:ボットの最も目立つ兆候

Pythonのデフォルトの```requests``` User-Agentは```python-requests/2.31.0```です。すべてのDataDome保護サイトはこれを即座にブロックします。しかし、User-Agentは主な問題ではありません。DataDomeは**ヘッダーの完全性と順序**をパッケージとしてチェックします。Chromeは、ブラウザ固有の順序で15以上の構造化されたヘッダーを送信します。```Sec-Fetch-Dest```が欠落している、ヘッダーが間違った順序で送信されている、または```Accept-Language```とプロキシのジオロケーションが不一致であると、信頼スコアが下がります。

```python
from curl_cffi import requests

CHROME_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/131.0.0.0 Safari/537.36",
    "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",
    "Accept-Encoding": "gzip, deflate, br, zstd",
    "Sec-CH-UA": '"Not A(Brand";v="8", "Chromium";v="131", "Google Chrome";v="131"',
    "Sec-CH-UA-Mobile": "?0",
    "Sec-CH-UA-Platform": '"Windows"',
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
}

session = requests.Session(impersonate="chrome")
response = session.get("https://target-site.com", headers=CHROME_HEADERS)

重要なジオコヒーレンスルール: プロキシがフランスの場合、Accept-Languagefr-FR,fr;q=0.9でなければなりません。ドイツのIPがen-USの言語ヘッダーとペアになっているのは、DataDomeのモデルがキャッチするための trivial な不一致です。また:ほとんどのスクレイピングライブラリはまだデフォルトでHTTP/1.1を使用しています。DataDomeはこれをフラグします。現代のウェブサイトはHTTP/2またはHTTP/3を実行しています。curl_cffiまたはhttpxを使用してHTTP/2を有効にすると、これが自動的に解決されます。

6. レイヤー3 — IPレピュテーション:信頼スコアの基礎

DataDomeは、接続しているすべてのIPをリアルタイムで複数の脅威インテリジェンスデータベースと照合します。データセンターIPに対する判決は即座に厳しいものです。IPレピュテーションは信頼スコアの約25〜30%を占めます。完璧なヘッダーと完璧なTLSフィンガープリントを持っていても、IPがAWS us-east-1に属しているためにブロックされる可能性があります。

3つのIPティアとその信頼への影響:

Datacenter IPs (AWS, GCP, DigitalOcean)  → Immediate negative score, pre-blocked ranges
Residential IPs (ISP-assigned, real homes) → High trust, harder to abuse at scale
Mobile IPs (carrier-grade NAT)             → Highest trust, shared ranges hard to block

住宅用またはモバイルIPでのプロキシローテーションはDataDomeにとって交渉の余地がありません。以下はクリーンな実装です:

from curl_cffi import requests
import random

RESIDENTIAL_PROXIES = [
    "http://user:pass@residential-proxy-1.example.com:8000",
    "http://user:pass@residential-proxy-2.example.com:8000",
    "http://user:pass@residential-proxy-3.example.com:8000",
]

def get_proxy() -> dict:
    proxy = random.choice(RESIDENTIAL_PROXIES)
    return {"http": proxy, "https": proxy}
```python
session = requests.Session(impersonate="chrome")
response = session.get(
    "https://target-site.com",
    headers=CHROME_HEADERS,
    proxies=get_proxy(),
    timeout=15
)

⚠️ スティッキーセッションが重要です: マルチステップフローのためにセッション中にIPをローテーションしないでください。ログイン → ブラウズ → チェックアウトフローが途中でIPアドレスを変更するのは、DataDomeの行動レイヤーにとって大きな赤信号です。マルチページフローにはスティッキーセッションを使用してください。新しい独立したセッションの開始時にのみローテーションします。

7. レイヤー4 — ブラウザフィンガープリンティング:JavaScriptの尋問

JavaScriptでコンテンツをレンダリングするサイト(DataDome保護サイトはほぼ常にそうです)には、実際のブラウザが必要です。しかし、バニラのPlaywrightやSeleniumはすぐに自分を明らかにします。

Get Data Journal’s stories in your inbox

Remember me for faster sign in
デフォルトのヘッドレスブラウザは、あらゆる場所でボット信号を漏らします (Kameleo, 2025):

  • navigator.webdriver === true — ハードコーディングされた自動化フラグ
  • プラグインが欠落している(Chrome PDF Viewer, Google Docs Offline
  • window.chrome.runtimeオブジェクトが存在しない
  • 実際のGPU出力の代わりにSwiftShaderソフトウェアGPUレンダリング
  • Canvas/WebGLが実際のブラウザとはわずかに異なるピクセル出力を生成する

修正方法:playwright-stealthと手動プロパティパッチの組み合わせ:

# pip install playwright playwright-stealth
import asyncio
from playwright.async_api import async_playwright
from playwright_stealth import stealth_async

async def stealth_scrape(url: str) -> str:
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=True,
            args=["--disable-blink-features=AutomationControlled"]
        )
        context = await browser.new_context(
            viewport={"width": 1920, "height": 1080},
            user_agent=(
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/131.0.0.0 Safari/537.36"
            ),
            locale="en-US",
            timezone_id="America/New_York",
        )
        page = await context.new_page()
        # Apply stealth patches (200+ leak fixes)
        await stealth_async(page)
        # Additional manual patching for DataDome-specific checks
        await page.add_init_script("""
            Object.defineProperty(navigator, 'platform', {
                get: () => 'Win32'
            });
            Object.defineProperty(navigator, 'plugins', {
                get: () => [
                    { name: 'Chrome PDF Plugin' },
                    { name: 'Chrome PDF Viewer' },
                    { name: 'Native Client' }
                ]
            });
        """)
        await page.goto(url, wait_until="networkidle")
        content = await page.content()
        await browser.close()
        return content

html = asyncio.run(stealth_scrape("https://target-site.com"))

Pythonファーストの開発者で、さらに強力な回避を望む場合は、camoufox — カスタムパッチを施したFirefoxビルド — とundetected-chromedriverをSelenium用にツールキットに加える価値があります。

8. レイヤー 5 — 行動分析: 最も難しいレイヤー

前の4つのレイヤーをすべて通過しても、持続的なスクレイピングにはまだ不十分です。DataDomeのMLモデルは、セッション全体にわたる行動の仕方を分析します。
監視されている信号:

  • マウスの動き: 実際のユーザーは自然な加速と揺らぎを伴うベジェ曲線を使用します
  • スクロール動作: 不規則なバーストと間隔があり、線形のピクセル増加ではありません
  • リクエストのタイミング: 人間はアクションの間に2〜15秒かかり、50msではありません
  • ナビゲーションフロー: 実際のユーザーはホームページ → カテゴリ → 商品を訪れ、直接深いリンクのページには行きません
  • セッションのウォームアップ: 商品のURLに直接行くのは疑わしい; 最初にブラウジングするのが自然です
import asyncio
import random

async def human_delay(min_s: float = 1.5, max_s: float = 4.0):
    """Randomized delay with realistic variance - not wild swings."""
    await asyncio.sleep(random.uniform(min_s, max_s))

async def scroll_naturally(page):
    """Scroll in bursts, pause between them, like a real reader."""
    chunks = random.randint(3, 6)
    for _ in range(chunks):
        scroll_px = random.randint(80, 250)
        await page.mouse.wheel(0, scroll_px)
        await asyncio.sleep(random.uniform(0.4, 1.3))

async def warm_up_session(page, base_url: str):
    """    
    Visit homepage and browse naturally before hitting target.
    DataDome rewards sessions that 'feel' like real shopping journeys.
    """
    await page.goto(base_url, wait_until="domcontentloaded")
    await human_delay(2.0, 4.0)
    await scroll_naturally(page)
    await human_delay(1.5, 3.0)
    # Then navigate to your actual target

⚠️ 落とし穴: あまりにも多くのランダム性も疑わしい。0.01〜30秒の遅延は壊れたボットのように見えます。ページ読み込みには1〜4秒、スクロールチャンクには0.3〜1.5秒の範囲を保ってください。

9. DataDome CAPTCHA: 検出が優雅に失敗する時

5つのレイヤーすべてに対処しても、高トラフィックのターゲットは定期的にあなたに挑戦します。DataDomeのCAPTCHAシステムは主にスライダー挑戦であり、チェックボックスや画像グリッドではありません。スライダーをドラッグする物理的な動作を測定します。
CAPTCHAが表示されたときの選択肢:
オプション A — CAPTCHA解決サービス (例: 2Captcha, CapSolver):

from twocaptcha import TwoCaptcha

solver = TwoCaptcha("YOUR_API_KEY")
result = solver.datadome(
    pageurl="https://target-site.com/blocked-page",
    captcha_url="https://geo.captcha-delivery.com/captcha/..."
)
token = result["code"]
# Inject the token back into the session cookie

オプション B — 予防が治療に勝る: クリーンなIP + 現実的な行動 + 適切なフィンガープリント = 最初からCAPTCHAが少なくなる。ソルバーは1,000 CAPTCHAあたり$1〜3のコストがかかり、それぞれ5〜20秒を追加します。スケールでは、予防の方がはるかに良いROIを持ちます。

10. 完全なアーキテクチャ: マーメイドダイアグラム

以下は、プロダクショングレードのDataDomeバイパスパイプラインで5つのレイヤーがどのように接続されるかです:
Medium image

11. まとめ: 完全なDataDomeバイパスクラス

import asyncio
import random
import time
from curl_cffi import requests as cffi_requests
from playwright.async_api import async_playwright
from playwright_stealth import stealth_async

PROXIES = [
    "http://user:pass@proxy1.example.com:8000",
    "http://user:pass@proxy2.example.com:8000",
]
```python
HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/131.0.0.0 Safari/537.36"
    ),
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
}

class DataDomeBypass:
"""
Layered DataDome bypass combining:
- TLS impersonation (curl_cffi) → Layer 1
- Geo-coherent headers → Layer 2
- Residential proxy rotation → Layer 3
- Stealth browser (Playwright) → Layer 4
- Behavioral warm-up + human delays → Layer 5
"""

    def _get_proxy(self) -> dict:
        p = random.choice(PROXIES)
        return {"http": p, "https": p}

    def fetch_static(self, url: str, retries: int = 3) -> str | None:
        """For non-JS pages: fast, low-resource curl_cffi path."""
        for attempt in range(retries):
            try:
                session = cffi_requests.Session(impersonate="chrome")
                resp = session.get(
                    url,
                    headers=HEADERS,
                    proxies=self._get_proxy(),
                    timeout=15
                )
                if "datadome" in resp.cookies:
                    print(f"[Attempt {attempt+1}] DataDome cookie set - rotating...")
                    time.sleep(random.uniform(5, 10))
                    continue
                if resp.status_code == 200:
                    return resp.text
            except Exception as e:
                print(f"[Static] Error: {e}")
                time.sleep(random.uniform(2, 5))
        return None
```python
async def fetch_dynamic(self, url: str, base_url: str) -> str | None:
    """For JS-rendered pages: stealth Playwright with warm-up."""
    proxy = random.choice(PROXIES)
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=True,
            proxy={"server": proxy},
            args=["--disable-blink-features=AutomationControlled"]
        )
        context = await browser.new_context(
            viewport={"width": 1920, "height": 1080},
            user_agent=HEADERS["User-Agent"],
            locale="en-US",
            timezone_id="America/New_York",
        )
        page = await context.new_page()
        await stealth_async(page)
        # Warm up: homepage first, then target
        await page.goto(base_url, wait_until="domcontentloaded")
        await asyncio.sleep(random.uniform(2.0, 3.5))
        # Natural scroll on homepage
        for _ in range(random.randint(2, 4)):
            await page.mouse.wheel(0, random.randint(100, 300))
            await asyncio.sleep(random.uniform(0.5, 1.2))
        # Now go to the actual target
        await page.goto(url, wait_until="networkidle")
        await asyncio.sleep(random.uniform(1.5, 3.0))
        content = await page.content()
        await browser.close()
        if "datadome" in content.lower() and "captcha" in content.lower():
            print("[Dynamic] CAPTCHA encountered - solver needed.")
            return None
        return content

12. 誰も言及しないメンテナンスの問題

すべてのDataDomeバイパスチュートリアルが便利にスキップすること: これは定期的に壊れます

DataDomeは検出モデルを継続的に更新しています。先週の火曜日に機能していたフィンガープリントが、次の月曜日にはブロックを引き起こす可能性があります。

`playwright-stealth`

ライブラリはオープンソースのコミュニティプロジェクトであり、DataDomeの週次リリースを追跡するエンジニアチームは存在しません。

`undetected-chromedriver`

も同様です。

本番環境でのDataDomeバイパススタックの維持には、(Scrapfly, 2026)以下が必要です:

  • Chrome/Firefoxのメジャーリリースごとにフィンガープリントの変更を監視する
  • フラグが付けられたプロキシIPを継続的に交換する
  • DataDomeのMLモデルが改善されるにつれて行動パターンを更新する
  • ライブラリの更新後にパイプライン全体の回帰テストを行う

小規模または一回限りのスクレイピングであれば、これは管理可能です。しかし、大規模な本番パイプラインでは、このメンテナンスコストがすぐに積み重なります。

13. 車輪の再発明をやめるべき時

ある時点で、ビルド対購入の計算が逆転します。チームがデータから価値を引き出すよりも回避ロジックの維持に多くの時間を費やしている場合、何かが間違っています。

Bright DataのWeb Unlockerのようなツールは、TLSの偽装、住宅プロキシのローテーション、ブラウザフィンガープリンティング、行動シミュレーション、CAPTCHA解決という5つの検出レイヤーを単一のAPIコールで処理します — それを維持する必要はありません。彼らのScraping Browserは、DataDomeのチェックをそのまま通過するPlaywright互換のCDPエンドポイントを公開しています。

(完全な開示:私はBright Dataとは提携していません。私は、モバイルAPIパスを含むDataDome特有のエンドポイントを実際に処理する数少ないツールの1つとして、研究コミュニティで一貫して見られるのを見てきました。)

スイッチを引き起こす計算:

  • あなたは1日あたり数千のリクエストでDataDome保護サイトにアクセスしている
  • あなたのターゲットは警告なしにアンチボットベンダーをローテーションしている
  • あなたのチームの時間はプロキシ/ソルバーAPIのコストよりも価値がある
  • 下流データパイプラインに99%+の成功率が必要

管理されたインフラは逃げ道ではありません。DIYメンテナンスコストがサブスクリプションコストを超えるときは、適切なツールです。

14. 法的および倫理的考慮事項

上記のいずれかをライブターゲットに対して展開する前に、このチェックリストを確認してください:
Check robots.txt — これは多くの法域での倫理的シグナルおよび法的リファレンスです (hiQ Labs v. LinkedIn, 9th Circuit 2022)
Review Terms of Service — DataDome保護サイトにはしばしば明示的なノースクレイピング条項があります
Avoid personal data — GDPRおよびCCPAはEU/CA居住者の情報に適用されます
Rate-limit responsibly — サーバーを過剰に叩くことは、米国でCFAA違反を構成する可能性があります
Prefer official APIs — より速く、より安定しており、法的に明確です

研究、価格監視、競争情報のために公開されているデータをスクレイピングすることは、認証の壁を回避したり、プライベートユーザーデータを収集したりしない限り、一般的に米国およびEUでは合法と見なされます。疑問がある場合は、デジタル権利法に詳しい弁護士に相談してください — この分野は進化し続けています。

Summary: The DataDome Bypass Checklist

Medium image
最終チェックリスト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?