要約
ヘッドレス Chrome は Chrome 59 でリリースされています。これは、ヘッドレス環境で Chrome ブラウザを実行する方法です。つまり、Chrome なしで Chrome を実行することになります。Chromium と Blink レンダリング エンジンが提供する最新のウェブ プラットフォームのすべての機能をコマンドラインにもたらします。
なぜこれが有用なのでしょうか。
ヘッドレス ブラウザは、可視 UI シェルが必要ない自動テストやサーバー環境に最適なツールです。たとえば、実際のウェブページに対してテストを実行したり、その PDF を作成したり、ブラウザが URL をレンダリングする方法を確認したりできます。
ヘッドレスの開始(CLI)
ヘッドレス モードを開始する最も簡単な方法は、コマンドラインから Chrome バイナリを開くことです。Chrome 59 以降がインストールされている場合は、--headless
フラグを使用して Chrome を起動します。
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 の Stable チャンネルを使用している場合、Beta を入手できない場合は、chrome-canary
を使用することをおすすめします。
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 はこちらからダウンロードできます。
コマンドライン機能
場合によっては、ヘッドレス Chrome をプログラムでスクリプト化する必要がないことがあります。一般的なタスクを実行するための便利なコマンドライン フラグがいくつかあります。
DOM の印刷
--dump-dom
フラグは、document.body.innerHTML
を stdout に出力します。
chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/
PDF を作成する
--print-to-pdf
フラグを使用すると、ページの PDF が作成されます。
chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/
スクリーンショットを取得する
ページのスクリーンショットをキャプチャするには、--screenshot
フラグを使用します。
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 式を評価できるモードでヘッドレスが実行されます。
$ 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
$
ブラウザ UI なしで Chrome をデバッグする
--remote-debugging-port=9222
で Chrome を実行すると、DevTools プロトコルが有効なインスタンスが起動します。このプロトコルは、Chrome との通信とヘッドレス ブラウザ インスタンスの駆動に使用されます。また、Sublime、VS Code、Node などのツールがアプリケーションのリモート デバッグに使用するものでもある。#synergy
ページを表示するブラウザ UI がないため、別のブラウザで http://localhost:9222
に移動して、すべてが機能していることを確認します。検査可能なページのリストが表示されます。クリックして、ヘッドレスがレンダリングしている内容を確認できます。

そこから、使い慣れた DevTools 機能を使用して、通常どおりにページを検査、デバッグ、調整できます。プログラムでヘッドレスを使用している場合、このページは、ブラウザと通信するワイヤーを介したすべての未加工の DevTools プロトコル コマンドを表示するための強力なデバッグツールでもあります。
プログラムによる使用(Node)
操り人形師
Puppeteer は、Chrome チームが開発した Node ライブラリです。ヘッドレス(またはフル)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();
})();
API の詳細については、Puppeteer のドキュメントをご覧ください。
CRI ライブラリ
chrome-remote-interface は、Puppeteer の API よりも低レベルのライブラリです。メタルに近づいて DevTools プロトコルを直接使用する場合、この方法をおすすめします。
Chrome の起動
chrome-remote-interface は Chrome を起動しません。そのため、自分で起動する必要があります。
CLI セクションでは、--headless --remote-debugging-port=9222
を使用して Chrome を手動で起動しました。ただし、テストを完全に自動化するには、アプリケーションから Chrome を起動することをおすすめします。
1 つの方法は、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 へのハードコードされたパスをご覧ください。
ChromeLauncher を使用する
Lighthouse は、ウェブアプリの品質をテストするための優れたツールです。Lighthouse 内で開発された、Chrome を起動するための堅牢なモジュールが抽出され、スタンドアロンで使用できるようになりました。chrome-launcher
NPM モジュールは、Chrome がインストールされている場所を見つけ、デバッグ インスタンスを設定し、ブラウザを起動して、プログラムが完了したら終了します。最大のメリットは、Node のおかげでクロス プラットフォームで動作することです。
デフォルトでは、chrome-launcher
は Chrome Canary を起動しようとします(インストールされている場合)。ただし、使用する Chrome を手動で選択するように変更することもできます。使用するには、まず npm からインストールします。
npm i --save chrome-launcher
例 - chrome-launcher
を使用してヘッドレスを起動する
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();
});
このスクリプトを実行してもあまり効果はありませんが、タスク マネージャーに about:blank
を読み込んだ Chrome のインスタンスが起動します。ブラウザの UI は表示されません。ヘッドレスです。
ブラウザを制御するには、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.
});
})();
Selenium、WebDriver、ChromeDriver の使用
現在、Selenium は Chrome の完全なインスタンスを開きます。つまり、自動化されたソリューションですが、完全にヘッドレスではありません。ただし、少し手間をかけて Selenium を構成すると、ヘッドレス Chrome を実行できます。自分でセットアップする方法の詳細については、ヘッドレス Chrome で Selenium を実行するをおすすめしますが、以下に簡単な例をいくつか示します。
ChromeDriver の使用
ChromeDriver 2.32 は Chrome 61 を使用し、ヘッドレス 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'), 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 です。
インストール:
npm i --save-dev webdriverio chromedriver
例: chromestatus.com で CSS 機能をフィルタする
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 - ウェブアプリの品質をテストするための自動化ツール。プロトコルを多用します。
- chrome-launcher - Chrome を起動するためのノード モジュール。自動化に対応しています。
デモ
- 「ヘッドレス ウェブ」- api.ai でヘッドレスを使用する方法に関する Paul Kinlan の優れたブログ投稿。
よくある質問
--disable-gpu
フラグは必要ですか?
Windows のみ。他のプラットフォームでは、この設定は不要になりました。--disable-gpu
フラグは、いくつかのバグに対する一時的な回避策です。Chrome の今後のバージョンでは、このフラグは必要ありません。詳しくは、crbug.com/737678 をご覧ください。
Xvfb は引き続き必要ですか?
いいえ。ヘッドレス Chrome はウィンドウを使用しないため、Xvfb などのディスプレイ サーバーは必要ありません。自動テストは、この機能がなくても実行できます。
Xvfb とは何ですか?Xvfb は、物理ディスプレイを接続しなくてもグラフィック アプリケーション(Chrome など)を実行できる、Unix 系システム用のインメモリ ディスプレイ サーバーです。多くのユーザーは、Xvfb を使用して以前のバージョンの Chrome を実行し、「ヘッドレス」テストを行っています。
ヘッドレス Chrome を実行する Docker コンテナを作成するにはどうすればよいですか?
lighthouse-ci をご覧ください。node:8-slim
をベースイメージとして使用し、App Engine Flex に Lighthouse をインストールして実行する Dockerfile の例が含まれています。
Selenium / WebDriver / ChromeDriver で使用できますか?
はい。Selenium、WebDriver、ChromeDriver の使用をご覧ください。
これは PhantomJS とどのように関連していますか?
ヘッドレス Chrome は、PhantomJS などのツールに似ています。どちらも、ヘッドレス環境での自動テストに使用できます。2 つの主な違いは、Phantom がレンダリング エンジンとして古いバージョンの WebKit を使用するのに対し、Headless Chrome は最新バージョンの Blink を使用する点です。
Phantom は現在、DevTools プロトコルよりも上位レベルの API も提供しています。
バグを報告するにはどうすればよいですか?
ヘッドレス Chrome に関するバグについては、crbug.com で報告してください。
DevTools プロトコルのバグについては、github.com/ChromeDevTools/devtools-protocol に報告してください。