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 detectedCaptcha.detected
: 检测到 CAPTCHACaptcha.solveFinished
: CAPTCHA solved successfullyCaptcha.solveFinished
:CAPTCHA 成功破解Captcha.solveFailed
: CAPTCHA solving failedCaptcha.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 sessionaddCaptchaListener
:用于侦听浏览器会话中的 CAPTCHA 事件onCaptchaFinished
: for waiting until the CAPTCHA has been solvedonCaptchaFinished
:等待 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。