Scraping Browser指南网络爬取中的绕过Cloudflare

Scraping Browser 与 Cloudflare

本技术文档旨在说明如何使用 Scrapeless Scraping Browser 和 Scrapeless Web Unlocker 工具来处理 Cloudflare 设置的各种安全挑战。主要功能包括绕过 Cloudflare JS Challenge、Cloudflare Turnstile 以及执行 JavaScript 渲染以访问受 Cloudflare 保护的内容。本文档将提供相关的背景知识、功能介绍、操作步骤和代码示例说明。

理解 Cloudflare 挑战与安全层

Cloudflare 作为一种流行的网络安全和性能服务,其主要职责之一是保护网站免受自动化机器人程序(如爬虫、扫描器)等恶意或非预期流量的干扰。为此,Cloudflare 实施了多种检测和防御机制,包括但不限于:

1.JS Challenge (JavaScript 挑战): 要求访问者的浏览器执行一段特定的 JavaScript 代码,以验证其是否为合法的、具备标准功能的浏览器环境。

2.Turnstile CAPTCHA 替代方案: 一种对用户干扰较小的验证机制,用于区分人类用户和机器人。

3.浏览器指纹识别: 通过收集和分析浏览器及设备的技术特征(如 User-Agent、屏幕分辨率、安装的字体、插件等)来识别和跟踪访问者。

4.速率限制: 监控并限制来自单一来源(如 IP 地址)在特定时间内的请求数量,以防止暴力破解或资源滥用。

这些安全层的存在,使得许多基础的 HTTP 请求库、简单的脚本或配置不当的无头浏览器在尝试访问受 Cloudflare 保护的网站时,会遇到验证失败而被阻止访问。

Cloudflare JS Challenge 与其他挑战的区别

Cloudflare JS Challenge 的独特之处在于其验证方式。它不仅仅是要求用户完成一个简单的交互任务(如识别图像),而是要求客户端环境(浏览器)必须能够成功解析并执行一段由 Cloudflare 动态生成的、通常经过混淆处理的 JavaScript 代码。这段代码会执行环境检测、计算密集型任务或其他逻辑,目的是验证客户端是否具备真实浏览器的复杂行为能力。

成功通过 JS Challenge 的关键在于生成一个有效的 clearance token(通常以 cf_clearance cookie 的形式存在)。这个 token 证明了客户端已通过了 JavaScript 执行能力的验证。相比之下,许多自动化工具缺乏完整的 JavaScript 执行引擎和真实的浏览器环境模拟,因此无法通过此类挑战。

使用 Scrapeless Scraping 浏览器绕过 Cloudflare JS 挑战

Scrapeless Scraping Browser 被设计用来专门应对包括 Cloudflare JS Challenge 在内的复杂网站防护措施。

操作步骤与代码示例

环境设置

创建项目文件夹

为项目创建一个新的文件夹,例如:scrapeless-bypass。

在您的终端中导航到该文件夹:

cd path/to/scrapeless-bypass

初始化 Node.js 项目

运行以下命令以创建 package.json 文件:

npm init -y

安装所需依赖

安装 Puppeteer-core,它允许远程连接到浏览器实例:

npm install puppeteer-core
``` bash
 
如果 Puppeteer 还未安装到您的系统上,请安装完整版本:
 
``` bash
npm install puppeteer puppeteer-core

获取并配置你的 Scrapeless API 密钥。

连接并确保验证码已经成功解决

当我们连接到浏览器访问目标网站时,Scrapeless 会自动检测并解决 CAPTCHA。但是,我们需要确保 CAPTCHA 已成功解决。Scrapeless Scraping Browser 通过一组强大的自定义功能扩展了标准 CDP(Chrome DevTools 协议)。可以通过检查从 CDP API 返回的结果来直接观察 CAPTCHA 求解器的状态:

  • Captcha.detected: CAPTCHA detected Captcha.detected: 检测到 CAPTCHA
  • Captcha.solveFinished: CAPTCHA solved successfully Captcha.solveFinished:CAPTCHA 成功破解
  • Captcha.solveFailed: CAPTCHA solving failed 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 已成功解决。最后,它会捕获页面的屏幕截图以进行验证。

This example defines two main methods:

此示例定义了两个主要方法:

  • addCaptchaListener: for listening to CAPTCHA events within the browser session addCaptchaListener:用于侦听浏览器会话中的 CAPTCHA 事件
  • onCaptchaFinished: for waiting until the CAPTCHA has been solved onCaptchaFinished:等待 CAPTCHA 被解决

上面的示例代码可用于侦听本文讨论的三种常见 CAPTCHA 类型的 CDP 事件:reCAPTCHA v2、Cloudflare Turnstile 和 Cloudflare 5s Challenge

需要注意的是,Cloudflare 5s Challenge有点特别。有时,它不会触发实际的质询,仅依靠 CDP 事件检测来成功可能会导致超时。因此,在挑战后等待页面上出现特定元素是一个更稳定的解决方案。

连接到 Scrapeless Browserless WebSocket

Scrapeless 提供了一个 WebSocket 连接,允许 Puppeteer 直接与无头浏览器交互,从而绕过 Cloudflare 挑战。

完整的 WebSocket 连接地址:

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

代码示例:绕过 Cloudflare Challenge

我们只需要准备以下代码即可连接到 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_clearanceCookie 和 Header

此外,通过 Cloudflare 质询后,您还可以从成功页面检索请求标头和 cf_clearance Cookie。

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

开启请求拦截,捕获请求头,在 cloudflare challenge 后匹配页面请求。

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 Scraping 浏览器绕过 Cloudflare Turnstile

Scrapeless Scraping Browser 同样具备处理 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' });

执行此脚本后,您将能够通过屏幕截图看到解锁效果。

使用 Scrapeless Web Unlocker 进行 JavaScript 渲染

对于那些不仅受 Cloudflare 保护,而且其核心内容依赖于客户端 JavaScript 执行才能完全加载和显示的网站,Scrapeless Web Unlocker 提供了专门的解决方案。

Scrapeless Universal 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 Instructions JavaScript 说明

提供广泛的 JavaScript 指令集,允许您动态地与 Web 页面交互。

这些指令使您能够单击元素、填写表单、提交表单或等待特定元素出现,从而为单击“阅读更多”按钮或提交表单等任务提供灵活性。

{
  "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
      }
    ]
  }
}

Challenge Bypass Example 质询绕过示例

以下示例代码使用 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。