原文地址:Getting Started with Headless Chrome  By EricBidelman  Engineer @ Google working on web tooling: Headless Chrome, Puppeteer, Lighthouse

Headless Chrome在Chrome59中发布,用于在headless环境中运行Chrome浏览器,也就是在非Chrome环境中运行Chrome。它将Chromium和Blink渲染引擎提供的所有现代Web平台功能引入命令行。

它有什么用处呢?

headless浏览器是自动测试和服务器环境的绝佳工具,您不需要可见的UI shell。例如,针对真实的网页进行测试,创建网页的PDF,或者只是检查浏览器如何呈现URL。

0. 开始

最简单的开始使用headless模式的方法是从命令行打开Chrome。如果你已经安装了Chrome59+的版本,可以使用 --headless 标签:

chrome \
--headless \ # 在headless模式运行Chrome
--disable-gpu \ # 在Windows上运行时需要--remote-debugging-port= \
https://www.chromestatus.com # 打开URL. 默认为about:blank

注意:若在Windows中运行,则需要在命令行添加 --disable-gpu 。

chrome 命令需要指向Chrome的安装路径。(即在Chrome的安装路径下运行)

1. 命令行功能

在某些情况下,您可能不需要以编程方式编写Headless Chrome脚本。下面是一些有用的命令行标志来执行常见任务。

1.1 打印DOM --dump-dom

将 document.body.innerHTML 在stdout打印出来:

chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/

1.2 创建PDF --print-to-pdf :

chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/

演示:在chrome安装目录下运行 chrome --headless --disable-gpu --print-to-pdf https://www.baidu.com/

生成PDF文件:C:\Program Files (x86)\Google\Chrome\Application\69.0.3497.81\output.pdf

1.3 截屏 --screenshot

chrome --headless --disable-gpu --screenshot https://www.chromestatus.com/

# 标准屏幕大小
chrome --headless --disable-gpu --screenshot --window-size=, https://www.chromestatus.com/ # Nexus 5x
chrome --headless --disable-gpu --screenshot --window-size=, https://www.chromestatus.com/

运行 --screenshot将会在当前运行目录下生成一个 screenshot.png 文件。若想给整个页面的截图,那么会比较复杂。来自 David Schnurr 的一篇很棒的博文介绍了这一内容。请查看 使用 headless Chrome 作为自动截屏工具

1.4 REPL模式(read-eval-print loop) --repl

在REPL模式运行Headless,该模式允许通过命令行在浏览器中评估JS表达式:

$ chrome --headless --disable-gpu --repl --crash-dumps-dir=./tmp https://www.chromestatus.com/
[/112805.245285:INFO:headless_shell.cc()] Type a Javascript expression to evaluate or "quit" to exit.
>>> location.href
{"result":{"type":"string","value":"https://www.chromestatus.com/features"}}
>>> quit
$

注意:使用repl模式时需要添加 --crash-dumps-dir 命令。

2. 在没有浏览器界面情况下调试Chrome

当使用 --remote-debugging-port= 运行Chrome时,会启用DevTools协议的实例。该协议用于与Chrome通信并且驱动headless浏览器实例。除此之外,它还是一个类似于 Sublime, VS Code, 和Node的工具,可用于远程调试一个应用。

由于没有浏览器UI来查看页面,因此需要在另一个浏览器中导航到http:// localhost:9222以检查一切是否正常。这将看到一个可查看页面的列表,可以在其中单击并查看Headless正在呈现的内容:

DevTools远程调试界面

在这里,你可以使用熟悉的DecTools功能来查看、调试、修改页面。若以编程方式(programmatically)使用Headless,该页面的功能更强大,可以用于查看所有的DecTools协议的命令,并与浏览器进行通信。

3. 使用编程模式(Node)

3.1 Puppeteer

Puppeteer 由Chrome团队开发的Node库。它提供了控制headless Chrome的高阶API。类似于 Phantom 和 NightmareJS这样的自动测试库,但它只用于最新版本的Chrome。

除此之外,Puppeteer还可用于截屏,创建PDF,页面导航,以及获取有关这些页面的信息。如果需要快速进行浏览器的自动化测试,建议使用该库。它隐藏了DevTools协议的复杂性,并负责启动Chrome的调试实例等冗余任务。

安装:

npm i --save puppeteer

例子-打印用户代理信息:

const puppeteer = require('puppeteer');

(async() => {
const browser = await puppeteer.launch();
console.log(await browser.version());
await browser.close();
})();

例子-截屏

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's 文档 学习Puppeteer的更多用法。

3.2 CRI库

相对于Puppeteer's API来说,chrome-remote-interface 是一个低阶的库,推荐使用它更接近底层地直接使用DevTools协议。

打开Chrome

chrome-remote-interface不能打开Chrome,因此需要自己打开Chrome。

在CLI部分,我们使用--headless --remote-debugging-port = 9222手动打开Chrome。但是,要实现完全自动化测试,您可能希望从应用程序中生成Chrome。

使用 child——process 的一种方式:

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的硬编码路径吧:(

使用ChromeLaucher

Lighthouse 是测试web应用质量绝佳工具。用于启动Chrome的强大的模块就是在Lighthouse中开发的,现在可以单独使用。  chrome-launcher NPM module 可以找到Chrome的安装路径,设置调试实例,打开浏览器,并且当程序运行完成时关掉它。最棒的是,由于Node,它可以跨平台工作!

默认情况下,chrome-launcher会尝试启动Chrome Canary(如果已安装),但可以更改它以手动选择要使用的Chrome。要使用它,首先从npm安装:

npm i --save chrome-launcher

例子-使用 chrome-launcher 启动Headless模式

const chromeLauncher = require('chrome-launcher');

// 可选: 设置launcher的日志记录级别以查看其输出
// 安装:: npm i --save lighthouse-logger
// const log = require('lighthouse-logger');
// log.setLevel('info'); /**
* 启动Chrome的调试实例
* @param {boolean=} headless True (default) 启动headless模式的Chrome.
* False 启动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 。但是没有浏览器界面。因为是headless模式。

要控制浏览器,我们需要DevTools协议!

检索有关页面的信息

安装:

npm i --save chrome-remote-interface

例子-打印用户代理

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

例子-检查网站是否有应用列表

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.
}); })();

例子-使用DOM API提取页面的<title>

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.
}); })();

4. 使用Selenium,W​​ebDriver和ChromeDriver

现在,Selenium打开了一个完整地Chrome的实例,也就是说,换句话说,它是一种自动化解决方案,但并非完全headless。但是,Selenium可以通过一些配置来运行headless Chrome。我建议使用headless Chrome运行Selenium,若你还是想要如何自己设置的完整说明,我已经在下面的一些例子中展示了如何让你放弃。

使用ChromeDriver

ChromeDriver 2.32使用了Chrome61,并且在headless Chrome运行的更好。

安装:

npm i --save-dev selenium-webdriver chromedriver

例子

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'), ); // 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。

安装:

npm i --save-dev webdriverio chromedriver

例子-chromestatus.com上的CSS filter功能

const webdriverio = require('webdriverio');
const chromedriver = require('chromedriver'); const PORT = ; 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', );
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(); 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(); })();

5. 更多资源

以下是一些有用的资源,可帮助您入门:

文档:

工具:

演示:

6. FAQ

6.1 是否需要 --disable-gpu 命令?

仅Windows平台需要。其他平台不需要。--disable-gpu命令是一个临时解决一些错误的方案。在将来的Chrome版本中,不再需要此命令。有关更多信息,请参阅 crbug.com/737678

6.2 是否需要 Xvfb

不需要。Headless Chrome不使用窗口,因此不再需要像Xvfb这样的显示服务器。没有它,也可以愉快地运行自动化测试。

什么是Xvfb?Xvfb是一种用于类Unix系统的内存显示服务器,它使您能够运行图形应用程序(如Chrome)而无需附加物理显示设备。许多人使用Xvfb运行早期版本的Chrome进行“headless”测试。

6.3 如何创建运行Headless Chrome的Docker容器?

看看lighthouse-ci。它有一个示例Dockerfile ,它使用node:8-slim作为基本映像,在App Engine Flex上安装+ 运行Lighthouse 。

6.4 Headless Chrome与PhantomJS有什么关系?

Headless Chrome与PhantomJS等工具类似。两者都可用于headless环境中的自动化测试。两者之间的主要区别在于Phantom使用较旧版本的WebKit作为其渲染引擎,而Headless Chrome使用最新版本的Blink。

目前,Phantom还提供了比DevTools 协议更高级别的API。

6.5 在哪里提交bugs?

对于Headless Chrome的bugs,请在crbug.com上提交。

对于DevTools协议中的错误,请将它们发送到github.com/ChromeDevTools/devtools-protocol

Headless Chrome入门的更多相关文章

  1. Web自动化之Headless Chrome测试框架集成

    使用Selenium操作headless chrome 推荐 简介 WebDriver是一个W3C标准, 定义了一套检查和控制用户代理(比如浏览器)的远程控制接口,各大主流浏览器来实现这些接口以便调用 ...

  2. Puppeteer: 更友好的 Headless Chrome Node API

    很早很早之前,前端就有了对 headless 浏览器的需求,最多的应用场景有两个 UI 自动化测试:摆脱手工浏览点击页面确认功能模式 爬虫:解决页面内容异步加载等问题 也就有了很多杰出的实现,前端经常 ...

  3. selenium+headless chrome安装使用

    pip install selenium 因为phantomJS将停止维护,所以建议使用headless chromeChromeDriver is a separate executable tha ...

  4. Web自动化之Headless Chrome概览

    Web自动化 这里所说的Web自动化是所有跟页面相关的自动化,比如页面爬取,数据抓取,页面内容检测,页面功能测试,页面加载性能测试,页面回归测试等等,当前主要由如下几种解决方式: 文本数据获取 这就是 ...

  5. Web自动化之Headless Chrome编码实战

    API 概览 && 编码Tips 文档地址 github Chrome DevTools Protocol 协议本身的仓库 有问题可以在这里提issue github debugger ...

  6. puppeteer,新款headless chrome!

    puppeteer puppeteer是一种谷歌开发的Headless Chrome,因为puppeteer的出现,业内许多自动化测试库停止维护,比如PhantomJS,Selenium IDE fo ...

  7. Web自动化之Headless Chrome开发工具库

    命令行运行Headless Chrome Chrome 安装(需要带梯子) 下载地址 几个版本的比较 Chromium 不是Chrome,但Chrome的内容基本来源于Chromium,这个是开源的版 ...

  8. Headless Chrome:服务端渲染JS站点的一个方案【上篇】【翻译】

    原文链接:https://developers.google.com/web/tools/puppeteer/articles/ssr 注:由于英文水平有限,没有逐字翻译,可以选择直接阅读原文 tip ...

  9. Headless Chrome:服务端渲染JS站点的一个方案【中篇】【翻译】

    接上篇 防止重新渲染 其实说不对客户端代码做任何修改是忽悠人的.在我们的Express 应用中,通过Puppteer加载页面,提供给客户端响应,但是这个过程是有一些问题的. js脚本在服务端的Head ...

随机推荐

  1. 一起学libcef--给你的浏览器删除cookie

    long long ago, 我们讨论了如给你cef设置cookie. 如今来补充一点,假设给你的浏览器删除某一cookie. review一下设置cookie: std::wstring usern ...

  2. 【77.78%】【codeforces 625C】K-special Tables

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  3. [Vue] Build Vue.js Apps with the Vue-CLI and Nuxt.js

    The vue-cli allows you to easily start up Vue projects from the command line while Nuxt.js enables a ...

  4. php 中英文字符串截取,字符串长度

    在做PHP开发的时候,由于我国的语言环境问题,所以我们常常需要对中文进行处理.在PHP中,我们都知道有专门的mb_substr和mb_strlen函数,可以对中文进行截取和计算长度,但是,由于这些函数 ...

  5. 第一次使用docker for windows 遇到的坑

    原文:第一次使用docker for windows 遇到的坑 1. 目前win10安装docker, 不需要安装其他工具,可直接到官网下载 2. 此版本的docker可同时运行Windows con ...

  6. linux下Oracle11g RAC搭建(一)

    linux下Oracle11g RAC搭建(一) 文档说明 作者    深蓝 项目 Visualbox下模拟RAC搭建(双节点)(Redhat5+Oracle11G) 环境 RedHat Enterp ...

  7. Android Studio Gradle:Resolvedependencies':app:_debugCompile' 问题解决纪录

    问题描述: 第一次使用AndroidStudio打开已经存在的AndroidStudio项目,卡在Gradle:Resolvedependencies':app_debugCompile'步骤,即使进 ...

  8. [Vue] Use basic event handling in Vue

    Let's use a range of events and their modifiers to look at the cool ways we can deal with event hand ...

  9. 【codeforces 757B】 Bash's Big Day

    time limit per test2 seconds memory limit per test512 megabytes inputstandard input outputstandard o ...

  10. 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

    PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...