PAYATHON 2026

如何使用 Java Selenium ChromeDriver 通过 Cloudflare bot checking?

排障赵师傅

结论

Java Selenium 没有通用配置能稳定”通过” Cloudflare bot checking。把 Python 示例改写成 Java,或补上 Accept、Accept-Language 等请求头,都解决不了这个问题。

Cloudflare 判断请求时,会综合浏览器端 JavaScript 的执行结果、Cookie、浏览器环境、IP、TLS 特征和其他安全信号。JavaScript 检测通过后,其他规则仍可能拦截请求。Cloudflare 官方文档也说明,JavaScript 检测结果只是机器人判定依据之一。

如果目标网站不属于你,合规的处理方式包括:

  1. 使用没有经过伪装的标准 Chrome。
  2. 不修改浏览器指纹和客户端提示请求头。
  3. 出现交互式验证时,让用户在可见的浏览器中完成。
  4. 由 Selenium 等待验证结束,然后继续操作页面。
  5. 如果验证不断循环,停止自动访问,并联系网站运营方申请授权或放行。

隐藏 WebDriver、伪造指纹、自动点击验证控件或复制 cf_clearance Cookie 都是在规避站点防护,也无法保证长期有效。

为什么添加 Request headers 没有效果

当前代码只修改了 HTTP 请求头,而 Cloudflare Challenge 会在浏览器中运行 JavaScript,并收集客户端信号。请求头只占其中很小一部分。

这段过滤器还可能造成请求信息相互矛盾:

request.headers().add("Platform", "Win64");

Platform 不是 Chromium 使用的标准 Client Hint。Chromium 可能发送 Sec-CH-UA-Platform,但这个字段应由浏览器根据真实环境生成,不适合手动伪造。

如果原请求已经包含同名字段,add() 还会追加一个值。例如,Chromium 已经设置了 Accept-Encoding,代理再次添加后就可能产生重复字段。Connection、Accept-Encoding 和 Client Hint 等请求头应由浏览器管理。

setAcceptInsecureCerts(true) 对 Cloudflare 验证也没有帮助。它只会让 WebDriver 接受无效或不受信任的 TLS 证书。只有代理确实在进行 TLS 中间人解密时,才可能需要这项设置。更合适的做法是安装并信任代理的 CA 证书。

Java 中可以采用的处理方式

移除 BrowserMobProxy 和手工添加的请求头,让 Chrome 使用正常的网络栈。启动可见浏览器后,等待目标页面中稳定的业务元素出现。如果 Cloudflare 要求交互,用户可以直接在浏览器窗口中完成验证。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class Main {

    public static void main(String[] args) {
        ChromeOptions options = new ChromeOptions();
        options.setPageLoadStrategy(PageLoadStrategy.NORMAL);
        options.setPageLoadTimeout(Duration.ofSeconds(60));
        options.setScriptTimeout(Duration.ofSeconds(30));

        WebDriver driver = new ChromeDriver(options);

        try {
            driver.get("https://solscan.io/");

            /*
             * 必须替换为目标业务页面上稳定且唯一的元素。
             * 不要使用 Cloudflare 验证页面中的元素作为成功条件。
             */
            By applicationReady =
                    By.cssSelector("#replace-with-a-stable-selector");

            WebDriverWait wait =
                    new WebDriverWait(driver, Duration.ofMinutes(2));

            wait.until(
                    ExpectedConditions.visibilityOfElementLocated(
                            applicationReady
                    )
            );

            System.out.println("目标页面已经加载,可以继续执行测试。");
        } catch (TimeoutException e) {
            saveScreenshot(driver, "challenge-timeout.png");
            throw new IllegalStateException(
                    "等待目标页面超时。页面可能仍处于 Cloudflare 验证状态。",
                    e
            );
        } finally {
            driver.quit();
        }
    }

    private static void saveScreenshot(WebDriver driver, String fileName) {
        byte[] image = ((TakesScreenshot) driver)
                .getScreenshotAs(OutputType.BYTES);

        try {
            Files.write(Path.of(fileName), image);
        } catch (IOException e) {
            System.err.println("保存截图失败: " + e.getMessage());
        }
    }
}

#replace-with-a-stable-selector 是占位符,需要替换为验证成功后才会出现在业务页面中的元素,比如页面的主搜索框、账户导航栏或应用根节点。

这段代码不会自动操作 Cloudflare 验证控件,只会等待正常浏览器完成验证,并在超时时保存截图。

现有代码还需要注意什么

setPageLoadTimeout() 只控制等待页面加载的时间,不会限制 Cloudflare 脚本的执行时间。

setScriptTimeout() 主要控制 Selenium 执行异步 JavaScript 时的超时,也无法决定 Cloudflare Challenge 能否通过。

Cloudflare 官方列出的验证循环原因包括 JavaScript 被阻止、Cookie 或 DOM Storage 不可用、网络不稳定、User-Agent 在会话中发生变化,以及浏览器表现出明显的自动化信号。更换请求头通常解决不了这些问题,还可能造成新的信息不一致。具体可参考验证循环排查说明。

如果必须使用公司代理,可以继续配置常规的 Selenium Proxy,但建议删除 addRequestFilter() 中改写请求头的代码。代理出口 IP 信誉较差或由多人共享时,也可能频繁触发验证。

如果目标网站由你管理

自动化测试不应针对生产环境中的真实 Challenge 编写”解题”逻辑。可以这样处理:

  • 在测试环境关闭相应的 WAF Challenge,或为受控的 CI 出口设置明确的放行规则。
  • 页面使用 Turnstile 时,改用 Cloudflare 提供的测试 sitekey 和测试 secret key。
  • 分开测试真实安全规则和业务页面的 Selenium 流程。
  • 生产环境继续使用真实验证,避免测试配置进入生产部署。

Cloudflare 明确说明,Selenium 等自动化工具可能被 Turnstile 识别为机器人,因此提供了专用的测试密钥。这些测试密钥只能用于自己控制的环境,生产 secret key 不会接受测试 token。具体可参考Turnstile 自动化测试说明。

Java 仓库和参考资料

SeleniumHQ/selenium 是 Selenium 官方仓库,包含 Java bindings、测试代码和示例。Java bindings 使用说明介绍了依赖配置和基本用法。

Cloudflare 和 Selenium 都没有官方维护的”绕过 Cloudflare” Java 仓库。声称可以稳定绕过检测的第三方项目,通常依赖隐藏自动化特征或伪造浏览器指纹。此类方案容易随着 Cloudflare、Chrome 或 ChromeDriver 更新而失效,也可能违反目标网站的使用规则。

备注:内容仅供参考。