返回博客
指南
Mihnea-Octavian ManolacheLast updated on Mar 31, 20262 min read

分步指南:如何绕过 Cloudflare 并提升网页抓取效果

分步指南:如何绕过 Cloudflare 并提升网页抓取效果

如今,网页抓取已成为一项极具挑战性的任务。如果你曾使用无头浏览器构建过网页抓取工具,那么你肯定遇到过一些反机器人系统。而绕过 Cloudflare、Datadome 或任何其他反机器人服务提供商,绝非易事。你必须先制定规避策略,然后在生产环境中实施。即便如此,仍可能存在你从未预料到的场景。

然而,若不至少实现这些规避技术的基本方案,你的爬虫被检测并封禁的概率将极高。正因如此,本文将探讨如何绕过 Cloudflare 的检测。我们将讨论的大部分技术同样适用于其他检测服务商。作为参考,我们将以 Selenium 为例,探讨如何使其隐身运行。在本文中,我将重点讨论以下内容:

  • 机器人检测方法
  • 通用反机器人规避技术
  • 针对 Selenium 的高级规避技巧

Cloudflare 如何检测无头浏览器?

Cloudflare 是一家拥有庞大网络架构的技术公司。其业务涵盖 CDN、DNS 及各类在线安全系统。其 Web 应用防火墙通常旨在防御 DDoS 或跨站脚本攻击。近年来,Cloudflare 及其他业内供应商相继引入了指纹识别系统,能够检测无头浏览器。正如您所料,Selenium 是首批受到这些技术影响的工具之一。 鉴于网络爬虫行业高度依赖这项技术,爬虫工具也受到了直接影响。

在探讨反机器人技术之前,我认为有必要先讨论一下 Cloudflare 是如何检测 Selenium 的。其实,该系统的检测机制相当复杂。例如,浏览器中存在 WebDriver 所不具备的属性。浏览器的 `navigator` 接口甚至有一个名为 `webdriver` 的属性,用于指示浏览器是否受自动化控制。这无疑是一个明显的破绽。如果您想亲自验证一下:

  • 打开浏览器的开发者工具
  • 进入控制台
  • 输入以下命令:`navigator.webdriver`

在您的情况下,它应该返回 `false`。但如果您使用 Puppeteer 或 Selenium 尝试,则会得到 `true`。如果您想知道 Cloudflare 是如何利用这一点来检测机器人的,其实很简单。他们只需在合作伙伴的网站上注入如下脚本即可:

// detection-script.js

const webdriver = navigator.webdriver

// If webdriver returns true, display a reCaptcha

// In this example, I am transferring the user to a Cloudflare challenge page.

// But you get the idea

if ( webdriver ) location.replace('https://cloudflarechallenge.com')

当然,在实际应用中,这些服务商采用了更多层次的检测机制。甚至屏幕尺寸、键盘布局或浏览器使用的插件,都会被用来对浏览器进行精准指纹识别。如果你对无浏览器检测的原理感兴趣,可以看看我开发的简单服务 worker 测试。而这仅仅是针对浏览器的检测方式。 你还可以通过查看请求来源的 IP 地址来检测机器人活动。例如,如果你使用的是数据中心 IP,那么每次请求被封禁的概率都会增加。这就是为什么在构建网络爬虫时,建议使用住宅 IP 或 ISP 代理

如何使用 Selenium 绕过 Cloudflare

幸运的是,网络爬虫社区非常活跃。正因绕过 Cloudflare 及其他反机器人服务商的需求如此迫切,该领域已涌现出开源解决方案。当编程社区通力合作时,定能成就非凡!接下来,我建议我们按照以下步骤进行:

  • 运行一些测试,查看默认的 Selenium 能否绕过 Cloudflare
  • 为脚本添加额外规避措施,使其更具隐蔽性

那么,让我们从第一步开始:

#1:默认 Selenium 能否绕过 Cloudflare?

我向来不轻易妄下结论。尤其因为我们并不确切了解 Cloudflare 系统的运作原理。他们的代码采用了各种混淆手段,使得逆向工程变得更加困难。正因如此,在我多年的开发生涯中,我深知测试是理解系统运作机制的最佳途径。 那么,让我们构建一个基础的爬虫程序,看看它在受 Cloudflare 保护的真实目标上表现如何。

1.1. 搭建环境

使用 Python 时,最好将项目集中在一个目录中。因此,让我们创建一个新文件夹,打开终端窗口并切换到该目录:

# Create a new virtual environment and activate it

~ » python3 -m venv env && source env/bin/activate

# Install dependencies

~ » python3 -m pip install selenium

# Create a new .py file and open the project inside your IDE

~ » touch app.py && code .

1.2. 使用 Selenium 构建一个简单的网页爬虫

既然你已成功搭建好项目环境,现在是时候编写代码了。这里我们不会构建什么复杂的功能,这个脚本仅用于测试目的。如果你想学习高级爬取技术,可以查看这篇关于 Pyppeteer 的教程 [链接](此处应插入文章链接)。

from selenium import webdriver

from selenium.webdriver.chrome.options import Options

# Set Chrome to open in headless mode

options = Options()

options.headless = True

# Create a new Chrome instance and navigate to target

driver = webdriver.Chrome(options=options)

driver.get('https://www.snipesusa.com/')

# Give it some time to load

time.sleep(10)

# Take screenshot of page

driver.get_screenshot_as_file('screenshot.png')

# Close browser

driver.quit()

现在请看截图。这是我得到的结果:

我想我们可以断定测试失败了。目标网站受 Cloudflare 保护,如你所见,我们被拦截了。因此,默认情况下,Selenium 无法绕过 Cloudflare。我不会深入探讨并测试其他机器人检测服务商。如果你想进一步测试,以下是一些目标网站及其服务商:

#2:隐形 Selenium 能否绕过 Cloudflare?

首先,让我澄清一下术语。所谓隐形 Selenium,是指一种能够不被检测并绕过 Cloudflare 的 Selenium 版本。 我并非指代任何具体的隐身技术。您可以通过几种方式在 Selenium 中实现规避技术:既可以使用专门的包来处理,也可以通过 `execute_cdp_cmd` 直接与 Chrome API 交互。后者能提供更多控制权,但需要更多工作量。以下是一个利用该方法修改用户代理值的示例:

driver.execute_cdp_cmd('Emulation.setUserAgentOverride', {

               "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36",

               "platform": "Win32",

               "acceptLanguage":"ro-RO"

       })

但您需要查阅 CDP 文档,找出允许进行所有必要更改的 API。因此,目前我们先使用一些现成的包进行测试。

1.1. 隐形 Selenium

至少有两个包可用于实现 Selenium 的隐身模式。但截至目前,尚无任何包能保证绕过 Cloudflare。因此,我们需要再次进行测试,以验证它们是否有效。 首先,让我们研究 `selenium-stealth`。该包是 `puppeteer-extra-plugin-stealth` 的封装,使得 Python 版的 Selenium 能够使用 Puppeteer 的规避机制。要使用它,首先需要安装。打开终端窗口并输入以下命令:

# Install selenium-stealth

~ » python3 -m pip install selenium-stealth

现在一切就绪。我们可以利用它让之前的爬虫脚本更具隐蔽性:

from selenium import webdriver

from selenium.webdriver.chrome.options import Options

from selenium_stealth import stealth

import time

# Set Chrome to open in headless mode

options = Options()

options.headless = True

# Create a new Chrome instance

driver = webdriver.Chrome(options=options)

# Apply stealth to your webdriver

stealth(driver,

   languages=["en-US", "en"],

   vendor="Google Inc.",

   platform="Win32",

   webgl_vendor="Intel Inc.",

   renderer="Intel Iris OpenGL Engine",

   fix_hairline=True,

)

# Navigate to target

driver.get('https://www.snipesusa.com/')

# Give it some time to load

time.sleep(10)

# Take screenshot of page

driver.get_screenshot_as_file('stealth.png')

# Close browser

driver.quit()

与默认的 Selenium 设置相比,这次运行脚本的结果有所不同:

您可以使用的第二个选项是 `undetected_chromedriver`。该组件被描述为“优化的 Selenium chromedriver”。让我们来测试一下:

# Install undetected_chromedriver

~ » python3 -m pip install undetected_chromedriver

代码与我们的默认脚本非常相似。主要区别在于包名。以下是一个使用 `undetected_chromedriver` 的基本爬虫,让我们看看它能否绕过 Cloudflare:

import undetected_chromedriver as uc

import time

# Set Chrome to open in headless mode

options = uc.ChromeOptions()

options.headless = True

# Create a new Chrome instance and maximize the window

driver = uc.Chrome(options=options, executable_path='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome')

driver.maximize_window()

# Navigate to target

driver.get('https://www.snipesusa.com/')

# Give it some time to load

time.sleep(10)

# Take screenshot of page

driver.get_screenshot_as_file('stealth-uc.png')

# Close browser

driver.quit()

再次运行脚本,结果依然顺利。看来至少这两个包能够成功绕过 Cloudflare 的防护。至少在短期内是如此。说实话,如果你大量使用这些脚本,Cloudflare 很可能会追踪到你的 IP 地址并将其封禁。

因此,让我向您介绍第三种方案:Web Scraping API

1.2. Selenium 与 Web Scraping API

Web Scraping API 拥有一个名为“代理模式”的强大功能。您可以在此处了解更多详情。但我想特别指出的是,我们的代理模式可以与 Selenium 成功集成。这样,您就能使用我们已实现的所有规避功能。而且,请相信我们有一支专门的团队在研究定制化的规避技术。 从技术层面讲,我们处理 IP 轮换、使用多种代理、破解验证码,并利用 Chrome API 持续更新指纹。通俗来说,这意味着您无需费心操作,成功率却大幅提升。您将获得目前最隐蔽的 Selenium 版本。具体实现方法如下:

# Install selenium-wire

~ » python3 -m pip install selenium-wire


我们使用 `selenium-wire` 来实现 Selenium 与代理的结合。以下是脚本代码:

from seleniumwire import webdriver

import time

# Method to encode parameters

def get_params(object):

   params = ''

   for key,value in object.items():

       if list(object).index(key) < len(object) - 1:

           params += f"{key}={value}."

       else:

           params += f"{key}={value}"

   return params

# Your WSA API key

API_KEY = '<YOUR_API_KEY>'

# Default proxy mode parameters

PARAMETERS = {

   "proxy_type":"datacenter",

   "device":"desktop",

   "render_js":1

}

# Set Selenium to use a proxy

options = {

   'proxy': {

       "http": f"http://webscrapingapi.{ get_params(PARAMETERS) }:{ API_KEY }@proxy.webscrapingapi.com:80",

   }

}

# Create a new Chrome instance

driver = webdriver.Chrome(seleniumwire_options=options)

# Navigate to target

driver.get('https://www.httpbin.org/get')

# Retrieve the HTML documeent from the page

html = driver.page_source

print(html)

# Close browser

driver.quit()

如果您运行此脚本几次,就会发现 IP 地址每次都在变化。这就是我们的 IP 轮换系统。在后台,它还会自动添加各种规避技术。您甚至无需为此操心。我们会处理 Cloudflare 绕过部分,以便您能更专注于数据解析。

结论

若想构建一个能绕过 Cloudflare 的爬虫,您需要考虑诸多因素。即便由专职团队全天候运作,也无法保证规避措施每次都能奏效。这是因为每次浏览器版本更新,API 都有可能新增功能,而其中某些功能会被用于指纹识别和检测机器人。

我甚至认为,绕过 Cloudflare 及其他服务商的最佳浏览器,就是你自己构建的浏览器。我们在 Web Scraping API 开发了一款这样的浏览器,现在与大家分享。祝您爬取愉快!

关于作者
Mihnea-Octavian Manolache, 全栈开发工程师 @ WebScrapingAPI
Mihnea-Octavian Manolache全栈开发工程师

Mihnea-Octavian Manolache 是 WebScrapingAPI 的全栈及 DevOps 工程师,负责开发产品功能并维护确保平台平稳运行的基础设施。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。