🎉全部功能不限时免费!$0元享受无限Profile和团队
免费开始
返回博客
Java
HeadlessChrome:它是什么以及如何检测它?
什么是无头浏览器?无头浏览器可以用来干嘛?如何对无头浏览器进行检测和反检测?所有的这些问题你都将在这篇文章中找到回答。
May 22, 2024

无头浏览器(headless browser)是一种没有图形用户界面(GUI)的浏览器。它可以在后台运行,允许程序员通过命令行接口或脚本来控制和操作浏览器。

现在,是时候开始通过 Nstbrowser 了解检测和反检测无头浏览器爬虫机器人的方法了!

什么是无头Chrome?

无头 Chrome(Headless Chrome)是 Google Chrome 浏览器的一种无头模式。它允许开发者通过命令行或脚本来控制和操作Chrome浏览器,而不需要显示浏览器的用户界面。无头Chrome结合了Chrome浏览器的强大功能和无头模式的高效性,是现代Web开发和测试中不可或缺的工具。

无头浏览器能干嘛?

  1. 高效的自动化测试:无头浏览器能够快速地运行浏览器测试脚本,验证网页的功能、性能和兼容性,而无需加载和渲染用户界面,极大地提高了测试的速度和效率。
  2. 网页抓取:无头浏览器可以用于抓取网页内容,模拟用户操作来访问和提取动态网页中的数据。这对于处理需要登录、加载动态内容或者依赖于JavaScript生成的内容的网页特别有用。
  3. 性能监控:开发人员可以使用无头浏览器来监控和分析网页性能,比如加载时间、资源使用情况等。

抓取网页时经常被封锁?
Nstbrowser 全面解锁网站,避免被检测
Try Free Nstbrowser Now!

如何检测及反检测无头浏览器?

我们已经知道什么是无头浏览器、无头浏览器能干嘛以及它是如何工作的。由于无头浏览器具备很强的自动化特性,无头浏览器也经常被用于反爬虫目的因此检测它的存在变得至关重要.

以下是常见的以Javascript代码为实例的无头浏览器的检测手段及部分反检测方法:

1. 用户代理检测

用户代理是浏览器发送给服务器的标识,通过检查用户代理中是否包含 "Headless" 字样可以初步判断请求是否来自于无头浏览器。这种方法往往并不可靠,因为用户代理可以被伪造或修改。

  • 检测代码
const isHeadlessUserAgent = navigator.userAgent.toLowerCase().includes('headless');
  • 反检测代码
// custom userAgent without 'headless'
Object.defineProperty(navigator, 'userAgent', {
    value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
});

2. JavaScript执行检测

无头浏览器通常不会执行JavaScript或其JavaScript执行能力较弱,因此我们可以通过执行一些简单的JavaScript代码来判断浏览器是否支持JavaScript。这可以通过检查某些JavaScript API 或功能是否可用来实现。

  • 检测代码
const isJavaScriptEnabled = typeof window !== 'undefined';

3. 浏览器特性检测

某些浏览器特性在无头浏览器中可能会被禁用或表现异常,我们可以利用这些特性来进行检测。例如,Canvas API 可以用于检测无头浏览器。

  • 检测代码
const isCanvasSupported = () => {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    return !!context;
}

4. Webdriver检测

通过检测 navigator.webdriver 属性的存在来判断是否是无头浏览器。无头浏览器通常会设置这个属性,而正常的浏览器不会,相关源码:Chromium 源码,可以通过检测这个属性的存在,来判断是否是Chrome headless。

  • 检测代码
const isWebDriverSupported = () => {
    return navigator.webdriver;
}
  • 反检测代码
Object.defineProperty(navigator, 'webdriver', {
    get: () => undefined
});

5. window.chrome检测

检测 window.chrome 是否存在可以帮助判断浏览器是否为无头模式。在无头模式下,这个属性通常是不存在的。

  • 检测代码
const isWindowChromeSupported = () => {
    return window.chrome !== undefined;
}

6. WebRTC检测

WebRTC 是浏览器中用于实时通信的Web标准,详情可以参考Webrtc官网,无头浏览器通常会禁用WebRTC,所以可以通过检测WebRTC的可用性来判断浏览器是否为无头浏览器。

  • 检测代码
const isWebRTCSupported = () => {
    return !!window.RTCPeerConnection;
}

7. 音频/视频检测

在无头模式下通常会禁用播放音频或视频,通过尝试播放音频或视频,我们可以检测浏览器是否支持音频或视频播放,从而判断是否为无头浏览器。

  • 检测代码
const isAudioVideoSupported = () => {
    const audio = document.createElement('audio');
    const video = document.createElement('video');
    return !!(audio.canPlayType && video.canPlayType);
}

8. Headless权限检测

目前无头浏览器还无法对浏览器权限进行操作,所以不支持Notification.permission,因为它们不处理用户界面的事件,只进行页面加载和渲染,所以在无头浏览器模式下Notification.permissionnavigator.permissions.query是不一致的。

  • 检测代码
const isHeadlessPermissionMatched = () => {
    return navigator.permissions.query({name: 'notifications'})
        .then(permissionStatus => {
            return Notification.permission === 'denied' && permissionStatus.state === 'prompt';
        })
        .catch(() => {
            return false;
        });
};

navigator.plugins可以查看浏览器中存在的插件列表。浏览器默认情况下会安装一些插件如:Chrome PDF viewer或者Google Native Client等,但是在无头模式下一般不会有任何插件,所以可以通过插件列表是否为空来判断是否是无头浏览器。

  • 检测代码
const pluginInstalled = () => {
    return navigator.plugins.length > 0
}
  • 反检测代码
const originalPlugins = navigator.plugins;
Object.defineProperty(navigator, 'plugins', {
    get: () => originalPlugins
});

10. 语言检测

在Chrome中,可以通过navigator.languagenavigator.languages来获取用户使用的语言,第一个是浏览器UI的语言,第二个是用户偏好语言的列表。在无头模式下,navigator.languages会返回一个空的字符串。

  • 检测代码
const isHeadlessLanguage = () => {
    return !navigator.languages || navigator.languages.length === 0
}
  • 反检测代码
Object.defineProperty(navigator, 'languages', {
    value: ['en-US', 'en']
});

11. 其他常见方法

检测方法:

  • 页面加载速度检测:无头浏览器通常加载页面速度较快,因为它们不需要渲染页面或执行JavaScript。可以通过监测页面加载速度来判断是否可能是无头浏览器。
  • 键盘事件检测: 无头浏览器通常不会触发键盘事件,因为它们通常不需要与用户交互。可以通过监听键盘事件并检查是否触发来判断是否是无头浏览器。
  • 鼠标事件检测:同样地,无头浏览器也不会触发鼠标事件,因为它们通常不需要模拟用户操作。可以通过监听鼠标事件来检测是否是无头浏览器。
  • CSS检测:某些CSS样式在无头浏览器中可能会表现不同,例如某些CSS属性可能不被支持或者渲染效果不同。可以通过加载特定的CSS样式并检查渲染结果来判断是否是无头浏览器。
  • LocalStorage检测:无头浏览器通常不会支持本地存储(LocalStorage),因为它们不需要保持用户会话或状态。可以尝试读取或写入LocalStorage并检查是否成功来判断是否是无头浏览器。

反检测方法

  • 模拟人类行为:无头浏览器通常会以高度自动化的方式执行任务,例如页面加载、表单提交等,这与人类用户的行为模式有所不同。可以通过模拟人类行为,例如添加随机的鼠标移动、键盘输入等,来使检测者认为是真实用户操作而不是无头浏览器。
  • 随机化请求间隔:无头浏览器通常会以非常规律的频率发送请求,可以通过在请求之间添加随机的时间间隔来模拟真实用户的行为,这样可以使检测者难以通过请求频率来判断是否是无头浏览器。
  • 模拟浏览器环境:在无头浏览器中修改一些属性或功能,使其更像真实浏览器。例如,可以修改浏览器窗口大小、显示分辨率、User-Agent 等,以模拟真实浏览器的环境。
  • 嵌入JavaScript交互:无头浏览器通常不会执行大量的JavaScript代码或与页面进行交互。可以通过在页面中嵌入一些需要用户交互的JavaScript代码,并检测其执行结果来判断是否是无头浏览器。
  • 检测特定环境变量:无头浏览器通常会设置一些特定的环境变量或属性,可以通过检测这些环境变量或属性来判断是否是无头浏览器。例如,可以检测环境变量中是否存在特定的标识符,或者检测 JavaScript 中是否存在特定的全局变量。

需要注意的是,因为无头浏览器可以模拟几乎所有正常浏览器的行为,会利用各种反检测手段来使得无头浏览器看起来更像真实用户的行为,从而提高反爬虫的难度,所以无论用什么方法来反检测无头浏览器都不是绝对可靠的,至少到目前为止是如此。

利用指纹浏览器反无头浏览器检测

我们也可以利用指纹浏览器来绕过无头浏览器检测,我们以 Nstbrowser 指纹浏览器为例。Nstbrowser的 API 解决方案是目前避免机器人检测的最佳选择之一,您可以免费获取 API 密钥。

为什么使用 Nstbrowser 进行检测?

  • Nstbrowser是完全免费使用的
  • Nstbrowserless 与流行的Puppeteer和Playwright兼容,提供更全面的技术支持
  • 它支持通过API以无头模式启动浏览器

接下来,通过Nstbrowser指纹浏览器和我本地 GoogleChrome 浏览器,分别访问 CreepJSAreyouheadless 无头浏览器检测站点来对比无头浏览器检测效果。

我们将使用 Puppeteer 调用API的方式来启动无头指纹浏览器,具体会用到 LaunchExistBrowser 接口,当然你也可以根据文档选择自己需要的其他的API。

开始之前你需要:

  • Step 1. 提前下载和安装 Nstbrowser
  • Step 2. 生成 API Key
  • Step 3. 创建一个 Profile 并手动下载 内核,你也可以在客户端点击启动你的Profile然后会触发自动下载内核

一切准备就绪之后就可以编码了。下面代码展示了启动无头模式浏览器并访问无头浏览器检测站点并截图:

import puppeteer from 'puppeteer-core';

// wiat for millseconds
function sleep(millseconds) {
  return new Promise(resolve => setTimeout(resolve, millseconds));
}

// visit headless detection site and take screenshots 
async function execPuppeteer(browserWSEndpoint) {
  try {
    const browser = await puppeteer.connect({
      browserWSEndpoint: browserWSEndpoint,
      defaultViewport: null,
    });

    const page = await browser.newPage();
    // detect headless on creepjs site
    await page.goto('https://abrahamjuliot.github.io/creepjs');
    await sleep(5 * 1000);
    await page.screenshot({ fullPage: true, path: 'detect_headless_creepjs.png' });

    // detect headless on areyouheadless site
    await page.goto('https://arh.antoinevastel.com/bots/areyouheadless');
    await sleep(2 * 1000);
    await page.screenshot({ path: 'detect_headless_areyouheadless.png' });

    await page.close();
    await browser.disconnect();
  } catch (err) {
    console.error(err);
  }
}

// LaunchExistBrowser: Connect to or start an existing browser
// You need to create the corresponding profile in advance
// Support custom config
async function launchAndConnectToBrowser(profileId) {
  const host = 'localhost:8848';
  const apiKey = 'you api key;
  const config = {
    headless: true, // support: true, 'new'
    autoClose: true,
  };
  const query = new URLSearchParams({
    'x-api-key': apiKey, // required
    config: encodeURIComponent(JSON.stringify((config))),
  });
  const browserWSEndpoint = `ws://${host}/devtool/launch/${profileId}?${query.toString()}`;
  console.log('browserWSEndpoint: ', browserWSEndpoint);
  await execPuppeteer(browserWSEndpoint);
}

launchAndConnectToBrowser('your profile id').then();

运行结果:

CreepJS测试结果

CreepJS测试结果

Areyouheadless测试结果

Areyouheadless测试结果

通过运行结果截图对比我本地 Google Chrome 的检测结果发现这两个站点的无头检测均未识别到我们使用的是无头浏览器,这也是我们想要的效果。

总结

通过本文的探讨和示例代码,希望能为开发者提供有效的参考和指导,提升网站的安全性和数据保护能力。
无头浏览器的检测和反检测是一个不断演进的技术对抗过程。可以借助有效的反检测工具应对被检测和被封锁的风险,Nstbrowser 可以帮助你保证绝对的隐蔽性,并且使用先进的技术解锁网络封锁。

此外,开发者需要持续关注最新的技术动态,更新检测策略,以应对新的挑战。无论用什么方法来反检测无头浏览器,都需要不断优化和改进,以确保其有效性和可靠性。