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 已经开发了一款,现在将其分享给你。祝你爬取愉快!




