要約
ヘッドレス Chrome は Chrome 59 でリリースされます。Chrome ブラウザをヘッドレス環境で実行する方法です。基本的には Chrome を使わずに Chrome を実行しますこれにより、Chromium と Blink レンダリング エンジンが提供する最新のウェブ プラットフォーム機能がすべてコマンドラインに組み込まれます。
なぜこれが有用なのでしょうか
ヘッドレス ブラウザは、UI シェルを表示する必要のない自動テストやサーバー環境に最適なツールです。たとえば、実際のウェブページに対してテストを実行したり、そのウェブページを PDF 化したりできます。また、ブラウザが URL をどのようにレンダリングするかを検査することもできます。
Headless(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 の安定版チャンネルを使っているのに 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 モード(read-eval-print ループ)
--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 リモート](https://developer.chrome.google.cn/static/blog/headless-chrome/image/devtools-remote-012fcea42f334.jpg?authuser=4&hl=ja)
ここから、使い慣れた DevTools の機能を使用して、通常どおりにページの検査、デバッグ、微調整を行うことができます。プログラムによってヘッドレスを使用している場合、このページは、ブラウザと通信する未加工の DevTools プロトコル コマンドをすべて確認するための優れたデバッグツールでもあります。
プログラムによる使用(ノード)
操り人形師
Puppeteer は、Chrome チームが開発した Node ライブラリです。ヘッドレス(またはフル)の Chrome を制御するための高レベル API を提供します。Phantom や NightmareJS などの他の自動テスト ライブラリに似ていますが、最新バージョンの Chrome でのみ動作します。
特に、スクリーンショットの撮影、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 を生成することをおすすめします。
一つの方法として、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 は、ウェブアプリの品質をテストするための優れたツールです。Chrome を起動するための堅牢なモジュールが Lighthouse 内で開発され、現在はスタンドアロンで使用できるように抽出されています。chrome-launcher
NPM モジュールは、Chrome がインストールされている場所の検出、デバッグ インスタンスの設定、ブラウザの起動、プログラムの終了後にブラウザを終了します。Node のおかげで、クロス プラットフォームで機能する点もメリットです。
デフォルトでは、chrome-launcher
は Chrome Canary の起動を試みます(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 を起動するためのノード モジュール
デモ
- 「The Headless Web」 - api.ai でのヘッドレスの使用に関する Paul Kinlan の優れたブログ投稿。
よくある質問
--disable-gpu
フラグは必要ですか?
Windows でのみ発生します。他のプラットフォームでは不要です。--disable-gpu
フラグは、いくつかのバグに対する一時的な回避策です。Chrome の今後のバージョンでは、このフラグは必要なくなります。詳しくは、crbug.com/737678 をご覧ください。
Xvfb は必要ですか?
いいえ。ヘッドレス Chrome はウィンドウを使用しないため、Xvfb などのディスプレイ サーバーは必要ありません。特に指定しなくても自動テストを実行できます。
Xvfb とは何ですか?Xvfb は、Unix 系のシステム向けのインメモリ ディスプレイ サーバーです。物理ディスプレイを接続せずにグラフィカル アプリケーション(Chrome など)を実行できます。多くのユーザーが Xvfb を使用して以前のバージョンの Chrome を実行し、「ヘッドレス」テストを行っています。
ヘッドレス Chrome を実行する Docker コンテナを作成するにはどうすればよいですか?
lighthouse-ci を確認します。このファイルにはサンプル Dockerfile が含まれており、node:8-slim
をベースイメージとして使用し、App Engine Flex にインストールして Lighthouse を実行します。
Selenium、WebDriver、ChromeDriver で使用できますか?
はい。Selenium、WebDriver、ChromeDriver を使用するをご覧ください。
これは PhantomJS とどのように関連していますか?
ヘッドレス Chrome は PhantomJS などのツールに似ています。どちらもヘッドレス環境の自動テストに使用できます。この 2 つの主な違いは、Pantom ではレンダリング エンジンとして古いバージョンの WebKit を使用しているのに対し、ヘッドレス Chrome では最新バージョンの Blink を使用していることです。
現時点では、DevTools プロトコルよりも上位の API も提供されています。
バグはどこに報告すればよいですか?
ヘッドレス Chrome に関するバグについては、crbug.com で報告してください。
DevTools プロトコルのバグについては、github.com/ChromeDevTools/devtools-protocol で報告してください。