返回博客
指南
Mihnea-Octavian Manolache2023年5月2日阅读时间:10分钟

了解如何使用最佳的 Selenium 浏览器绕过 Cloudflare 检测

了解如何使用最佳的 Selenium 浏览器绕过 Cloudflare 检测

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()

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

Bot protection challenge screen on the Snipes site asking the user to press and hold to confirm they are human

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

Table listing websites and the bot protection provider they use, such as Kasada, Akamai, DataDome, and Incapsula

#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 设置相比,这次运行脚本的结果有所不同:

Screenshot of the Snipes retail website featuring a The North Face promotional banner

您可以使用的第二个选项是 `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在无需任何基础设施开销的情况下,以企业级规模提取网络数据。