Chrome 59附带了无头Chrome。这是在无头环境中运行Chrome浏览器的一种方式。本质上,没有Chrome即可运行Chrome!它将Chromium和Blink渲染引擎提供的所有现代Web平台功能引入命令行。
为什么这样有用?
无头浏览器是自动化测试和不需要可见UI外壳的服务器环境的绝佳工具。例如,您可能想对真实的网页运行一些测试,为其创建PDF,或者仅检查浏览器如何呈现URL。
启动无头(CLI)
无头模式入门的最简单方法是从命令行打开Chrome二进制文件。如果您已安装Chrome 59+,请使用以下--headless
标志启动Chrome :
0 1 2 3 4 5 |
chrome \ --headless \ # Runs Chrome in headless mode. --disable-gpu \ # Temporarily needed if running on Windows. --remote-debugging-port=9222 \ https://www.chromestatus.com # URL to open. Defaults to about:blank. |
chrome
应该指向您安装的Chrome。确切位置因平台而异。由于使用的是Mac,因此我为已安装的每个版本的Chrome创建了方便的别名。
如果您使用的是Chrome稳定版,但无法获得Beta版,建议您使用chrome-canary
:
0 1 2 3 |
alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome" alias chrome-canary="/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary" alias chromium="/Applications/Chromium.app/Contents/MacOS/Chromium" |
在此处下载Chrome Canary 。
命令行功能
在某些情况下,您可能不需要以编程方式编写Headless Chrome脚本。有一些有用的命令行标志 可以执行常见任务。
打印DOM
该--dump-dom
标志打印document.body.innerHTML
到标准输出:
0 1 |
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/ |
创建PDF
该--print-to-pdf
标志创建页面的PDF:
0 1 |
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/ |
截屏
要捕获页面的屏幕截图,请使用--screenshot
标志:
0 1 2 3 4 5 6 7 |
chrome --headless --disable-gpu --screenshot https://www.chromestatus.com/ # Size of a standard letterhead. chrome --headless --disable-gpu --screenshot --window-size=1280,1696 https://www.chromestatus.com/ # Nexus 5x chrome --headless --disable-gpu --screenshot --window-size=412,732 https://www.chromestatus.com/ |
运行--screenshot
将screenshot.png
在当前工作目录中生成一个名为的文件。如果您要查找整页的屏幕截图,则可能会涉及更多内容。David Schnurr撰写了一篇很棒的博客文章,内容涵盖了您。检出 使用无头Chrome作为自动截图工具 。
REPL模式(读评估打印循环)
该--repl
标志以无头模式运行,您可以在浏览器中直接从命令行评估JS表达式:
0 1 2 3 4 5 6 |
$ chrome --headless --disable-gpu --repl --crash-dumps-dir=./tmp https://www.chromestatus.com/ [0608/112805.245285:INFO:headless_shell.cc(278)] Type a Javascript expression to evaluate or "quit" to exit. >>> location.href {"result":{"type":"string","value":"https://www.chromestatus.com/features"}} >>> quit $ |
在没有浏览器用户界面的情况下调试Chrome?
当您使用运行Chrome时--remote-debugging-port=9222
,它将启动启用了DevTools协议的实例。该协议用于与Chrome通信并驱动无头浏览器实例。这也是Sublime,VS Code和Node等工具用于远程调试应用程序的工具。#协同作用
由于您没有浏览器用户界面来查看该页面,因此请http://localhost:9222
在另一个浏览器中导航至,以检查一切是否正常。您将看到可检查页面的列表,您可以在其中单击并查看Headless呈现的内容:
在这里,您可以像往常一样使用熟悉的DevTools功能来检查,调试和调整页面。如果您以编程方式使用Headless,则此页面还是一个功能强大的调试工具,可用于查看通过导线传输的所有原始DevTools协议命令,并与浏览器进行通信。
以编程方式使用(节点)
木偶戏
Puppeteer是Chrome小组开发的Node库。它提供了高级API来控制无头(或完整)Chrome。它与其他自动测试库(如Phantom和NightmareJS)相似,但仅适用于最新版本的Chrome。
除其他外,Puppeteer可用于轻松获取屏幕截图,创建PDF,浏览页面以及获取有关这些页面的信息。如果您想快速自动化浏览器测试,则建议使用该库。它隐藏了DevTools协议的复杂性,并处理了诸如启动Chrome的调试实例之类的多余任务。
安装它:
0 1 |
npm i --save puppeteer |
示例-打印用户代理
0 1 2 3 4 5 6 7 |
const puppeteer = require('puppeteer'); (async() => { const browser = await puppeteer.launch(); console.log(await browser.version()); await browser.close(); })(); |
示例-截取页面截图
0 1 2 3 4 5 6 7 8 9 10 |
const puppeteer = require('puppeteer'); (async() => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://www.chromestatus.com', {waitUntil: 'networkidle2'}); await page.pdf({path: 'page.pdf', format: 'A4'}); await browser.close(); })(); |
查看Puppeteer的文档 以了解有关完整API的更多信息。
CRI库
chrome-remote-interface 是比Puppeteer的API更底层的库。如果您想靠近金属并直接使用DevTools协议,则建议使用它。
启动Chrome
chrome-remote-interface不会为您启动Chrome,因此您必须自己照顾一下。
在CLI部分,我们使用 手动启动了Chrome--headless --remote-debugging-port=9222
。但是,要完全自动化测试,您可能需要从应用程序中生成Chrome 。
一种方法是使用child_process
:
0 1 2 3 4 5 6 7 8 9 10 11 |
const execFile = require('child_process').execFile; function launchHeadlessChrome(url, callback) { // Assuming MacOSx. const CHROME = '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'; execFile(CHROME, ['--headless', '--disable-gpu', '--remote-debugging-port=9222', url], callback); } launchHeadlessChrome('https://www.chromestatus.com', (err, stdout, stderr) => { ... }); |
但是,如果您想要一个可在多个平台上运行的便携式解决方案,事情就会变得棘手。只需看一下Chrome的硬编码路径即可:(
使用ChromeLauncher
Lighthouse是测试网络应用程序质量的绝佳工具。在Lighthouse中开发了一个强大的Chrome浏览器启动模块,现已将其提取以供独立使用。在chrome-launcher
NPM模块 会发现其中Chrome的安装,设置一个调试实例,启动浏览器,并杀死它,当你的程序就完成了。最好的部分是,借助Node,它可以跨平台工作!
默认情况下,chrome-launcher
它将尝试启动Chrome Canary(如果已安装),但是您可以更改它以手动选择要使用的Chrome。要使用它,请首先从npm安装:
0 1 |
npm i --save chrome-launcher |
示例-chrome-launcher
用于启动Headless
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
const chromeLauncher = require('chrome-launcher'); // Optional: set logging level of launcher to see its output. // Install it using: npm i --save lighthouse-logger // const log = require('lighthouse-logger'); // log.setLevel('info'); /** * Launches a debugging instance of Chrome. * @param {boolean=} headless True (default) launches Chrome in headless mode. * False launches a full version of Chrome. * @return {Promise<ChromeLauncher>} */ function launchChrome(headless=true) { return chromeLauncher.launch({ // port: 9222, // Uncomment to force a specific port of your choice. chromeFlags: [ '--window-size=412,732', '--disable-gpu', headless ? '--headless' : '' ] }); } launchChrome().then(chrome => { console.log(`Chrome debuggable on port: ${chrome.port}`); ... // chrome.kill(); }); |
运行此脚本并没有多大作用,但是您应该在加载的任务管理器中看到Chrome实例启动about:blank
。请记住,不会有任何浏览器用户界面。我们无头。
要控制浏览器,我们需要DevTools协议!
检索有关页面的信息
让我们安装库:
0 1 |
npm i --save chrome-remote-interface |
例子
示例-打印用户代理
0 1 2 3 4 5 6 7 8 |
const CDP = require('chrome-remote-interface'); ... launchChrome().then(async chrome => { const version = await CDP.Version({port: chrome.port}); console.log(version['User-Agent']); }); |
结果如下: HeadlessChrome/60.0.3082.0
示例-检查网站是否具有Web应用程序清单
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
const CDP = require('chrome-remote-interface'); ... (async function() { const chrome = await launchChrome(); const protocol = await CDP({port: chrome.port}); // Extract the DevTools protocol domains we need and enable them. // See API docs: https://chromedevtools.github.io/devtools-protocol/ const {Page} = protocol; await Page.enable(); Page.navigate({url: 'https://www.chromestatus.com/'}); // Wait for window.onload before doing stuff. Page.loadEventFired(async () => { const manifest = await Page.getAppManifest(); if (manifest.url) { console.log('Manifest: ' + manifest.url); console.log(manifest.data); } else { console.log('Site has no app manifest'); } protocol.close(); chrome.kill(); // Kill Chrome. }); })(); |
示例-<title>
使用DOM API提取页面的。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
const CDP = require('chrome-remote-interface'); ... (async function() { const chrome = await launchChrome(); const protocol = await CDP({port: chrome.port}); // Extract the DevTools protocol domains we need and enable them. // See API docs: https://chromedevtools.github.io/devtools-protocol/ const {Page, Runtime} = protocol; await Promise.all([Page.enable(), Runtime.enable()]); Page.navigate({url: 'https://www.chromestatus.com/'}); // Wait for window.onload before doing stuff. Page.loadEventFired(async () => { const js = "document.querySelector('title').textContent"; // Evaluate the JS expression in the page. const result = await Runtime.evaluate({expression: js}); console.log('Title of page: ' + result.result.value); protocol.close(); chrome.kill(); // Kill Chrome. }); })(); |
使用Selenium,WebDriver和ChromeDriver
现在,Selenium打开了完整的Chrome实例。换句话说,这是一个自动化的解决方案,但并非完全没有意义。但是,只需完成一些工作,即可将Selenium配置为运行无头Chrome。 如果您想要有关如何自行设置的完整说明,我建议 使用Headless Chrome运行Selenium,但是我在下面的一些示例中为您入门。
使用ChromeDriver
ChromeDriver 2.32使用Chrome 61,并与无头Chrome兼容。
安装:
0 1 |
npm i --save-dev selenium-webdriver chromedriver |
例:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const fs = require('fs'); const webdriver = require('selenium-webdriver'); const chromedriver = require('chromedriver'); const chromeCapabilities = webdriver.Capabilities.chrome(); chromeCapabilities.set('chromeOptions', {args: ['--headless']}); const driver = new webdriver.Builder() .forBrowser('chrome') .withCapabilities(chromeCapabilities) .build(); // Navigate to google.com, enter a search. driver.get('https://www.google.com/'); driver.findElement({name: 'q'}).sendKeys('webdriver'); driver.findElement({name: 'btnG'}).click(); driver.wait(webdriver.until.titleIs('webdriver - Google Search'), 1000); // Take screenshot of results page. Save to disk. driver.takeScreenshot().then(base64png => { fs.writeFileSync('screenshot.png', new Buffer(base64png, 'base64')); }); driver.quit(); |
使用WebDriverIO
WebDriverIO是Selenium WebDriver之上的更高级别的API。
安装:
0 1 |
npm i --save-dev webdriverio chromedriver |
示例:在chromestatus.com上过滤CSS功能
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
const webdriverio = require('webdriverio'); const chromedriver = require('chromedriver'); const PORT = 9515; chromedriver.start([ '--url-base=wd/hub', `--port=${PORT}`, '--verbose' ]); (async () => { const opts = { port: PORT, desiredCapabilities: { browserName: 'chrome', chromeOptions: {args: ['--headless']} } }; const browser = webdriverio.remote(opts).init(); await browser.url('https://www.chromestatus.com/features'); const title = await browser.getTitle(); console.log(`Title: ${title}`); await browser.waitForText('.num-features', 3000); let numFeatures = await browser.getText('.num-features'); console.log(`Chrome has ${numFeatures} total features`); await browser.setValue('input[type="search"]', 'CSS'); console.log('Filtering features...'); await browser.pause(1000); numFeatures = await browser.getText('.num-features'); console.log(`Chrome has ${numFeatures} CSS features`); const buffer = await browser.saveScreenshot('screenshot.png'); console.log('Saved screenshot...'); chromedriver.stop(); browser.end(); })(); |
更多资源
以下是一些帮助您入门的有用资源:
文件
- DevTools协议查看器-API参考文档
工具类
- chrome-remote-interface-包装DevTools协议的节点模块
- Lighthouse-用于测试Web应用程序质量的自动化工具;大量使用该协议
- chrome-launcher-用于启动Chrome的节点模块,准备进行自动化
演示版
- “ The Headless Web ”-保罗·金兰(Paul Kinlan)在api.ai上使用Headless的精彩博客文章。
常问问题
我需要--disable-gpu
旗帜吗?
仅在Windows上。其他平台不再需要它。该--disable-gpu
标志是一些错误的临时解决方法。在以后的Chrome版本中,您将不需要此标志。有关 更多信息,请参见crbug.com/737678。
所以我仍然需要Xvfb吗?
不会。无头Chrome不会使用窗口,因此不再需要Xvfb之类的显示服务器。没有它,您可以愉快地运行自动化测试。
什么是Xvfb?Xvfb是用于类似Unix的系统的内存显示服务器,使您无需附加物理显示就可以运行图形应用程序(例如Chrome)。许多人使用Xvfb运行早期版本的Chrome进行“无头”测试。
如何创建运行Headless Chrome的Docker容器?
看看lighthouse-ci。它的 例子Dockerfile 使用node:8-slim
作为基础图像,安装+ 运行灯塔 上应用程序引擎的Flex。
我可以将其与Selenium / WebDriver / ChromeDriver一起使用吗?
是。请参阅使用Selenium,WebDrive或ChromeDriver。
这和PhantomJS有什么关系?
无头Chrome类似于PhantomJS之类的工具。两者均可用于无头环境中的自动化测试。两者之间的主要区别是Phantom使用旧版本的WebKit作为其渲染引擎,而Headless Chrome使用最新版本的Blink。
目前,Phantom还提供了比DevTools协议更高级别的API 。
我在哪里报告错误?
有关无头Chrome的错误,请将其归档在crbug.com上。
对于DevTools协议中的错误,请将其归档在github.com/ChromeDevTools/devtools-protocol上。
原文:https://developers.google.com/web/updates/2017/04/headless-chrome