Scraping BrowserガイドWebスクレイピングでCloudFlareバイパス

スクラピングブラウザとCloudflare

この技術文書では、ScrapelessスクラピングブラウザとScrapeless Web Unlockerツールを使用して、Cloudflareによって設定された様々なセキュリティ上の課題に対処する方法を説明します。主な機能には、Cloudflare JSチャレンジ、Cloudflare Turnstileの回避、およびCloudflareによって保護されたコンテンツにアクセスするためのJavaScriptレンダリングの実行が含まれます。このドキュメントでは、関連する背景知識、機能紹介、操作手順、コード例の説明を提供します。

Cloudflareのチャレンジとセキュリティレイヤーについて

Cloudflareは、人気の高いWebセキュリティとパフォーマンスサービスであり、主にボットやスキャナーなどの悪意のあるトラフィックや予期せぬトラフィックからウェブサイトを保護します。この目的のために、Cloudflareは、以下を含むがこれらに限定されない様々な検出および防御メカニズムを実装しています。

**1. JSチャレンジ(JavaScriptチャレンジ):**訪問者のブラウザが特定のJavaScriptコードを実行して、標準的な機能を備えた正当なブラウザ環境であることを確認する必要があります。

**2. Turnstile CAPTCHA代替:**人間のユーザーとボットを区別するための、侵入性の低い検証メカニズムです。

**3. ブラウザフィンガープリンティング:**ブラウザとデバイスの技術的な特性(例:ユーザーエージェント、画面解像度、インストールされているフォント、プラグイン)を収集および分析して、訪問者を識別および追跡します。

**4. レート制限:**特定の時間内に単一の情報源(例:IPアドレス)からのリクエスト数を監視および制限して、ブルートフォース攻撃やリソースの乱用を防ぎます。

これらのセキュリティレイヤーにより、基本的なHTTPリクエストライブラリ、単純なスクリプト、または正しく構成されていないヘッドレスブラウザは、Cloudflareで保護されたウェブサイトにアクセスできなくなり、検証エラーやアクセス拒否が発生します。

Cloudflare JSチャレンジとその他のチャレンジの違い

Cloudflare JSチャレンジの独自性は、その検証方法にあります。単純なインタラクティブなタスク(例:画像認識)の完了を求めるだけでなく、クライアント環境(ブラウザ)がCloudflareから動的に生成された、多くの場合難読化されたJavaScriptコードを正常に解析して実行することを要求します。このコードは、環境チェック、計算集約的なタスク、またはクライアントの複雑な動作能力を検証するその他のロジックを実行し、実際のブラウザを模倣します。

JSチャレンジに合格するには、有効なクリアランストークン(通常はcf_clearance Cookieの形)を生成する必要があります。このトークンは、クライアントがJavaScript実行能力の検証に合格したことを証明します。多くの自動化ツールには、完全なJavaScript実行エンジンと現実的なブラウザ環境シミュレーションが不足しているため、このようなチャレンジに失敗します。

Scrapelessスクラピングブラウザを使用したCloudflare JSチャレンジの回避

Scrapelessスクラピングブラウザは、Cloudflare JSチャレンジを含む複雑なウェブサイト保護対策に対応するように設計されています。

手順とコード例

環境設定

プロジェクトフォルダの作成

プロジェクト用の新しいフォルダを作成します(例:scrapeless-bypass)。

ターミナルでフォルダに移動します。

cd path/to/scrapeless-bypass

Node.jsプロジェクトの初期化

次のコマンドを実行して、package.jsonファイルを作成します。

npm init -y

必要な依存関係のインストール

ブラウザインスタンスへのリモート接続を可能にするPuppeteer-coreをインストールします。

npm install puppeteer-core

システムにPuppeteerがまだインストールされていない場合は、フルバージョンをインストールします。

npm install puppeteer puppeteer-core

Scrapeless APIキーの取得と設定

接続とCAPTCHAの正常な解決の確認

Scrapelessは、ターゲットウェブサイトにアクセスするためにブラウザに接続するときに、CAPTCHAを自動的に検出して解決します。ただし、CAPTCHAが正常に解決されたことを確認する必要があります。Scrapelessスクラピングブラウザは、標準的なCDP(Chrome DevTools Protocol)を強力なカスタム機能で拡張します。CAPTCHAソルバーのステータスは、CDP APIから返される結果を確認することで直接確認できます。

  • Captcha.detected: CAPTCHAが検出されました
  • Captcha.solveFinished: CAPTCHAが正常に解決されました
  • Captcha.solveFailed: CAPTCHAの解決に失敗しました
import puppeteer from "puppeteer-core";
import EventEmitter from 'events';
const emitter = new EventEmitter()
const scrapelessUrl = 'wss://browser.scrapeless.com/browser?token=your_api_key&session_ttl=180&proxy_country=ANY';
 
export async function example(url) {
  const browser = await puppeteer.connect({
    browserWSEndpoint: scrapelessUrl,
    defaultViewport: null
  });
  console.log("Verbonden met Scrapeless browser");
  try {
    const page = await browser.newPage();
    // Listen for captcha events
    console.debug("addCaptchaListener: Start listening for captcha events");
    await addCaptchaListener(page);
    console.log("Navigated to URL:", url);
    await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 });
    console.log("onCaptchaFinished: Waiting for captcha solving to finish...");
    await onCaptchaFinished()
    // Screenshot for debugging
    console.debug("Taking screenshot of the final page...");
    await page.screenshot({ path: 'screenshot.png', fullPage: true });
  } catch (error) {
    console.error(error);
  } finally {
    await browser.close();
    console.log("Browser closed");
  }
}
 
async function addCaptchaListener(page) {
  const client = await page.createCDPSession();
  client.on("Captcha.detected", (msg) => {
    console.debug("Captcha.detected: ", msg);
  });
  client.on("Captcha.solveFinished", async (msg) => {
    console.debug("Captcha.solveFinished: ", msg);
    emitter.emit("Captcha.solveFinished", msg);
    client.removeAllListeners()
  });
}
 
async function onCaptchaFinished(timeout = 60_000) {
  return Promise.race([
    new Promise((resolve) => {
      emitter.on("Captcha.solveFinished", (msg) => {
        resolve(msg);
      });
    }),
    new Promise((_, reject) => setTimeout(() => reject('Timeout'), timeout))
  ])
}

この例では、ターゲットウェブサイトにアクセスし、Captcha.solveFinished CDPイベントをリッスンすることで、CAPTCHAが正常に解決されたことを確認します。最後に、ページのスクリーンショットをキャプチャして検証します。

この例では、2つの主要なメソッドを定義しています。

  • addCaptchaListener:ブラウザセッション内でCAPTCHAイベントをリッスンするため
  • onCaptchaFinished:CAPTCHAが解決されるまで待機するため

上記のコード例は、この記事で説明されている3つの一般的なCAPTCHAの種類(reCAPTCHA v2、Cloudflare Turnstile、Cloudflare 5秒チャレンジ)のCDPイベントをリッスンするために使用できます。

Cloudflare 5秒チャレンジはやや特殊です。場合によっては、実際のチャレンジがトリガーされないことがあり、成功のためにCDPイベント検出のみに依存すると、タイムアウトが発生する可能性があります。したがって、チャレンジ後にページに特定の要素が表示されるのを待つ方が、より安定したソリューションとなります。

Scrapeless Browserless WebSocketへの接続

ScrapelessはWebSocket接続を提供しており、Puppeteerがヘッドレスブラウザと直接やり取りして、Cloudflareのチャレンジを回避することを可能にします。

完全なWebSocket接続アドレス:

wss://browser.scrapeless.com/browser?token=APIKey&session_ttl=180&proxy_country=ANY

コード例:Cloudflareチャレンジの回避

Scrapelessのブラウザレスサービスに接続するには、次のコードのみが必要です。

import puppeteer from 'puppeteer-core';
 
const API_KEY = 'your_api_key'
const host = 'wss://browser.scrapeless.com';
const query = new URLSearchParams({
  token: API_KEY,
  session_ttl: '180', // The life cycle of a browser session, in seconds
  proxy_country: 'GB', // Agent country
  proxy_session_id: 'test_session_id', // The proxy session id is used to keep the proxy ip unchanged. The session time is 3 minutes by default, based on the proxy_session_duration setting.
  proxy_session_duration: '5' // Agent session time, unit minutes
}).toString();
 
const connectionURL = `${host}/browser?${query}`;
const browser = await puppeteer.connect({
    browserWSEndpoint: connectionURL,
    defaultViewport: null,
});
console.log('Connected!')

Cloudflareで保護されたウェブサイトへのアクセスとスクリーンショットによる検証

次に、scrapeless browserlessを使用して、cloudflare-challengeテストサイトに直接アクセスし、スクリーンショットを追加して視覚的な検証を行います。スクリーンショットを撮る前に、waitForSelectorを使用してページの要素を待つ必要があることに注意してください。これにより、Cloudflareチャレンジが正常に回避されたことが保証されます。

const page = await browser.newPage();
await page.goto('https://www.scrapingcourse.com/cloudflare-challenge', {waitUntil: 'domcontentloaded'});
// By waiting for elements in the site page, ensuring that the Cloudflare challenge has been successfully bypassed.
await page.waitForSelector('main.page-content .challenge-info', {timeout: 30 * 1000})
await page.screenshot({path: 'challenge-bypass.png'});

この時点で、Scrapeless Browserlessを使用してCloudflareチャレンジを回避しました。

cf_clearance Cookieとヘッダーの取得

Cloudflareチャレンジに合格した後、成功したページからリクエストヘッダーとcf_clearance Cookieを取得できます。

const cookies = await browser.cookies()
const cfClearance = cookies.find(cookie => cookie.name === 'cf_clearance')?.value

リクエストインターセプトを有効にして、リクエストヘッダーをキャプチャし、Cloudflareチャレンジ後のページリクエストを照合します。

await page.setRequestInterception(true);
page.on('request', request => {
  // Match page requests after cloudflare challenge
  if (request.url().includes('https://www.scrapingcourse.com/cloudflare-challenge') && request.headers()?.['origin']) {
    const accessRequestHeaders = request.headers();
    console.log('[access_request_headers] =>', accessRequestHeaders);
  }
  request.continue();
});

Scrapelessスクラピングブラウザを使用したCloudflare Turnstileの回避

Scrapelessスクラピングブラウザは、Cloudflare Turnstileチャレンジにも対応しています。

同様に、Cloudflare Turnstileに直面した場合でも、ブラウザレススクラピングブラウザは自動的に処理できます。次の例では、cloudflare-turnstileテストサイトにアクセスします。ユーザー名とパスワードを入力した後、waitForFunctionメソッドを使用してwindow.turnstile.getResponse()からのデータが返されるまで待機し、チャレンジが正常に回避されたことを確認します。その後、スクリーンショットを撮り、ログインボタンをクリックして次のページに移動します。

手順とコード例:

const page = await browser.newPage();
await page.goto('https://www.scrapingcourse.com/login/cf-turnstile', { waitUntil: 'domcontentloaded' });
await page.locator('input[type="email"]').fill('admin@example.com')
await page.locator('input[type="password"]').fill('password')
// Wait for turnstile to unlock successfully
await page.waitForFunction(() => {
  return window.turnstile && window.turnstile.getResponse();
});
await page.screenshot({ path: 'challenge-bypass-success.png' });
await page.locator('button[type="submit"]').click()
await page.waitForNavigation()
await page.screenshot({ path: 'next-page.png' });

このスクリプトを実行した後、スクリーンショットでロック解除の効果を確認できます。

JavaScriptレンダリングのためのScrapeless Web Unlockerの使用

コアコンテンツがクライアント側のJavaScript実行に依存して完全に読み込まれ、表示されるCloudflareによって保護されたウェブサイトの場合、Scrapeless Web Unlockerは専用のソリューションを提供します。

ScrapelessユニバーサルAPIはJavaScriptレンダリングと動的なインタラクションを可能にし、Cloudflareを回避するための効果的なツールとなります。

JavaScriptレンダリング

JavaScriptレンダリングは、動的に読み込まれたコンテンツとSPA(シングルページアプリケーション)の処理をサポートします。完全なブラウザ環境をサポートし、より複雑なページのインタラクションとレンダリング要件を処理します。

js_render=trueを使用すると、リクエストにブラウザを使用します。

{
  "actor": "unlocker.webunlocker",
  "input": {
    "url": "https://www.google.com/",
    "js_render": true
  },
  "proxy": {
    "country": "US"
  }
}

JavaScript命令

広範なJavaScript命令を提供し、ウェブページとの動的なインタラクションを可能にします。

これらの命令により、要素のクリック、フォームへの入力、フォームの送信、または特定の要素の出現の待機が可能になり、「詳細を読む」ボタンをクリックしたり、フォームを送信したりするなどのタスクの柔軟性が向上します。

{
  "actor": "unlocker.webunlocker",
  "input": {
    "url": "https://example.com",
    "js_render": true,
    "js_instructions": [
      {
        "wait_for": [
          ".dynamic-content",
          30000
        ]
        // Wait for element
      },
      {
        "click": [
          "#load-more",
          1000
        ]
        // Click element
      },
      {
        "fill": [
          "#search-input",
          "search term"
        ]
        // Fill form
      },
      {
        "keyboard": [
          "press",
          "Enter"
        ]
        // Simulate key press
      },
      {
        "evaluate": "window.scrollTo(0, document.body.scrollHeight)"
        // Execute custom JS
      }
    ]
  }
}

チャレンジ回避の例

次の例では、axiosを使用してScrapelessのWeb Unlockerサービスへのリクエストを送信します。js_renderを有効にし、js_instructionsパラメータのwait_for命令を使用して、Cloudflareチャレンジを回避した後のページ上の要素を待ちます。

import axios from 'axios'
 
async function sendRequest() {
  const host = "api.scrapeless.com";
  const url = `https://${host}/api/v1/unlocker/request`;
  const API_KEY = 'your_api_key'
 
  const payload = {
    actor: "unlocker.webunlocker",
    proxy: {
      country: "US"
    },
    input: {
      url: "https://www.scrapingcourse.com/cloudflare-challenge",
      js_render: true,
      js_instructions: [
        {
          wait_for: [
            "main.page-content .challenge-info",
            30000
          ]
        }
      ]
    },
  }
 
  try {
    const response = await axios.post(url, payload, {
      headers: {
        'Content-Type': 'application/json',
        'x-api-token': API_KEY
      }
    });
    console.log("[page_html_body] =>", response.data);
  } catch (error) {
    console.error('Error:', error);
  }
}
sendRequest();

上記のスクリプトを実行すると、コンソールでCloudflareチャレンジを正常に回避したページのHTMLを確認できます。