首页 > 解决方案 > 无头 Chromium 浏览器始终显示验证码

问题描述

我正在使用带有headless-chromium-php 的google chrome 无头浏览器

导航到某些网站,但它总是被验证码检测到

我尝试使用此插件随机更改用户代理

但没有任何改变

        $UserAgent = \Campo\UserAgent::random([
            'os_type' => 'Windows',
            'device_type' => 'desktop'
        ]);

        $browserFactory = new BrowserFactory('/opt/google/chrome/google-chrome');

        $browser = $browserFactory->createBrowser([
            'sendSyncDefaultTimeout' => 5000,
            'userAgent' => $UserAgent
        ]);
        $page = $browser->createPage();

        $page->navigate($NextURL)->waitForNavigation();

为什么会这样?

标签: phpcentosheadlesschromium-os

解决方案


我强烈建议您阅读以下两篇文章并将所有这些技术应用到您的代码中,以使 Chrome Headless 检测变得更加困难

检测 Chrome 无头,新技术

无法检测和阻止 Chrome Headless

无头浏览器检测器通常使用一系列技术来识别您的浏览器是否被远程控制,例如,一些浏览器环境属性:

用户代理(旧)

它是常用来检测操作系统以及用户浏览器的属性。在具有 Chrome 版本 63 的 Linux 计算机上,它具有以下值:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/63.0.3071.115 Safari/537.36

因此,我们可以检查是否存在 Chrome Headless:

if (/HeadlessChrome/.test(window.navigator.userAgent)) {
    console.log('Chrome headless detected!')
}

网络驱动程序(新)

为了自动化 Chrome 无头,一个新的属性 webdriver 被添加到 navigator 对象(参见 Chromium 代码)。因此,通过测试该属性是否存在,可以检测 Chrome 无头。

if (navigator.webdriver) {
    console.log('Chrome headless detected!')
}

铬(新)

window.chrome是一个似乎为 Chrome 扩展开发者提供功能的对象。虽然它在香草模式下可用,但在无头模式下不可用。

if (!window.chrome) {
    console.log('Chrome headless detected')
}

权限(新)

目前无法在无头模式下处理权限。因此,它会导致 Notification.permission 和 navigator.permissions.query 报告矛盾值的不一致状态。

const permissionStatus = await navigator.permissions.query({ name: 'notifications' })
if (Notification.permission === 'denied' && permissionStatus.state === 'prompt') {
    console.log('This is Chrome headless!')
} else {
    console.log('This is not Chrome headless')
}

插件(旧)

navigator.plugins返回浏览器中存在的插件数组。通常,在 Chrome 上,我们会找到默认插件,例如 Chrome PDF 查看器或 Google Native Client。相反,在无头模式下,返回的数组不包含插件。

if (navigator.plugins.length === 0) {
    console.log('Chrome headless detected!')
}

语言(旧)

在 Chrome 中,有两个 Javascript 属性可以获取用户使用的语言:navigator.language 和 navigator.languages。第一个是浏览器 UI 的语言,而第二个是表示用户首选语言的字符串数组。但是,在无头模式下,navigator.languages 返回一个空字符串。

if (navigator.languages === '') {
    console.log('Chrome headless detected')
}

WebGL

WebGL 是一种在 HTML 画布中执行 3D 渲染的 API。使用此 API,可以查询图形驱动程序的供应商以及图形驱动程序的渲染器。

使用普通的 Chrome 和 Linux,我获得了渲染器和供应商的以下值:“Google SwiftShader”和“Google Inc.”。在无头模式下,我获得了“Mesa OffScreen”,这是用于不使用任何类型的窗口系统进行渲染的技术和“Brian Paul”,这是启动开源 Mesa 图形库的程序。

const canvas = document.createElement('canvas')
const gl = canvas.getContext('webgl')

const debugInfo = gl.getExtension('WEBGL_debug_renderer_info')
const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL)
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)

if (vendor == 'Brian Paul' && renderer == 'Mesa OffScreen') {
    console.log('Chrome headless detected')
}

缺少图片

最后,我们的最后一个发现(似乎也是最可靠的)来自 Chrome 在无法加载图像时使用的图像尺寸。

在 vanilla Chrome 的情况下,图像的宽度和高度取决于浏览器的缩放比例,但不为零。在无头 Chrome 中,图像的宽度和高度均为零。

const img = document.createElement('img')
img.src = "http://iloveponeydotcom32188.jg"
document.body.appendChild(img)
img.onerror = () => {
    if (img.width == 0 && img.height == 0) {
        console.log('Chrome headless detected')
    }
}

推荐阅读