2017 年,Chrome 59 引入了无头模式,可让您在无人值守的环境中运行浏览器,而没有任何可见的界面。从本质上讲,您可以在不使用 Chrome 的情况下运行 Chrome。
无头模式是通过 Puppeteer 或 ChromeDriver 等项目实现的浏览器自动化的热门选择。下面是一个使用无头模式创建给定网址的 PDF 文件的极简命令行示例:
chrome --headless --print-to-pdf https://developer.chrome.com/
无头设备的运作方式
现在,在我们了解 Headless 的工作原理之前,请务必先了解“旧版”Headless 的工作原理。上述命令行代码段使用 --headless
命令行标志,表明 Headless 只是常规 Chrome 浏览器的一种操作模式。也许令人惊讶,事实并非如此。
事实上,旧版 Headless 是单独的备用浏览器实现方案,正好是作为同一 Chrome 二进制文件的一部分提供。它不会共享 //chrome
中的任何 Chrome 浏览器代码。
实现和维护单独的无头浏览器需要大量的工程开销。此外,由于 Headless 是一个单独的实现,因此它有自己的 bug 和功能,而这些 bug 和功能是 Headful Chrome 所没有的。这会给自动化浏览器测试造成混淆,因为此类测试可能会在头部模式下通过,但在无头模式下会失败,或者相反。
此外,Headless 不包括任何依赖于浏览器扩展程序安装的自动化测试。这同样适用于任何其他浏览器级功能;除非 Headless 有自己的独立实现,否则它不受支持。
Chrome 团队现已统一了无头模式和头部模式。
Chrome 112 现已推出新的无头模式。在此模式下,Chrome 会创建任何平台窗口,但不显示。现有和未来的所有其他函数均不受限制。
使用无头模式
如需使用新的无头模式,请传递 --headless=new
命令行标志:
chrome --headless=new
目前,旧版无头模式仍可通过以下设备使用:
chrome --headless=old
在 Puppeteer 中
如需在 Puppeteer 中选择启用新的无头模式,请执行以下操作:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
headless: 'new',
// `headless: true` (default) enables old Headless;
// `headless: 'new'` enables new Headless;
// `headless: false` enables "headful" mode.
});
const page = await browser.newPage();
await page.goto('https://developer.chrome.com/');
// …
await browser.close();
在 Selenium-WebDriver 中
如需在 Selenium-WebDriver 中使用新的无头模式,请执行以下操作:
const driver = await env
.builder()
.setChromeOptions(options.addArguments('--headless=new'))
.build();
await driver.get('https://developer.chrome.com/');
// …
await driver.quit();
如需了解详情,包括使用其他语言绑定的示例,请参阅 Selenium 团队的博文。
命令行标志
新的无头模式提供以下命令行标志。
--dump-dom
--dump-dom
标志会将目标网页的序列化 DOM 输出到 stdout。例如:
chrome --headless=new --dump-dom https://developer.chrome.com/
这与输出 HTML 源代码不同,您可以通过 curl
执行此操作。为了向您提供 --dump-dom
的输出,Chrome 会先将 HTML 代码解析为 DOM,执行任何可能改变 DOM 的 <script>
,然后将该 DOM 转回到序列化 HTML 字符串。
--screenshot
--screenshot
标志用于截取目标页面的屏幕截图,并将其保存为 screenshot.png
在当前工作目录中。在与 --window-size
标志结合使用时,这尤其有用。
例如:
chrome --headless=new --screenshot --window-size=412,892 https://developer.chrome.com/
--print-to-pdf
--print-to-pdf
标志将目标网页另存为当前工作目录中名为 output.pdf
的 PDF 文件。例如:
chrome --headless=new --print-to-pdf https://developer.chrome.com/
或者,您可以添加 --no-pdf-header-footer
标志以省略打印标题(包含当前日期和时间)和页脚(包含网址和页码)。
chrome --headless=new --print-to-pdf --no-pdf-header-footer https://developer.chrome.com/
不支持:--no-pdf-header-footer
标志后面的功能以前通过 --print-to-pdf-no-header
标志提供。如果使用的是以前的版本,您可能需要回退到旧的标志名称。
--timeout
--timeout
标志定义了最长等待时间(以毫秒为单位),--dump-dom
、--screenshot
和 --print-to-pdf
会在达到该时间后才捕获页面内容,即使页面仍在加载也是如此。
chrome --headless=new --print-to-pdf --timeout=5000 https://developer.chrome.com/
--timeout=5000
标志会告知 Chrome 等待最多 5 秒再打印 PDF。因此,此过程最多需要 5 秒钟即可运行。
--virtual-time-budget
对于任何具有时效性的代码(例如 setTimeout
/setInterval
),--virtual-time-budget
充当“快进”。它会强制浏览器尽快执行网页的任何代码,同时让网页认为时间实际上已经过时。
为了说明其用法,请考虑此演示,该演示使用 setTimeout(fn, 1000)
每秒递增、记录和显示计数器。以下是相关代码:
<output>0</output>
<script>
const element = document.querySelector('output');
let counter = 0;
setInterval(() => {
counter++;
console.log(counter);
element.textContent = counter;
}, 1_000);
</script>
一秒后,网页将显示“1”;两秒后显示“2”,依此类推。 下面展示了如何在 42 秒后捕获页面状态并将其保存为 PDF 文件:
chrome --headless=new --print-to-pdf --virtual-time-budget=42000 https://mathiasbynens.be/demo/time
--allow-chrome-scheme-url
若要访问 chrome://
网址,必须使用 --allow-chrome-scheme-url
标志。Chrome 123 及更高版本提供此标志。示例如下:
chrome --headless=new --print-to-pdf --allow-chrome-scheme-url chrome://gpu
调试
由于 Chrome 在无头模式下实际上处于不可见状态,因此解决问题可能听起来有些困难。调试无头 Chrome 的方式与有头 Chrome 非常相似。
使用 --remote-debugging-port
命令行标志在无头模式下启动 Chrome。
chrome --headless=new --remote-debugging-port=0 https://developer.chrome.com/
这会将唯一的 WebSocket 网址输出到 stdout,例如:
DevTools listening on ws://127.0.0.1:60926/devtools/browser/b4bd6eaa-b7c8-4319-8212-225097472fd9
在 Headless Chrome 实例中,我们可以使用 Chrome 开发者工具远程调试连接到 Headless 目标并对其进行检查。
- 转到
chrome://inspect
,然后点击 Configure...(配置...)按钮。 - 输入 WebSocket 网址中的 IP 地址和端口号。
- 在前面的示例中,我输入了
127.0.0.1:60926
。
- 在前面的示例中,我输入了
- 点击完成。您应该会看到一个 Remote Target 出现,其中列出了其所有标签页和其他目标。
- 点击 Inspect 以访问 Chrome 开发者工具,并检查远程 Headless 目标,包括页面的实时视图。
反馈
我们期待收到您对新的无头模式的反馈。如果您遇到任何问题,请提交 bug。