Chrome のヘッドレス モードのアップグレード: --headless=new

Chrome のヘッドレス モードがさらに便利になりました。

Peter Kvitek
Peter Kvitek

Chrome のヘッドレス モードがさらに便利になりました。この記事では、デベロッパーにとって Headless をより便利なものにするために、Headless を Chrome の通常の「headful」モードに近づけるための最近のエンジニアリングの取り組みの概要を説明します。

背景

2017 年の Chrome 59 では、いわゆるヘッドレス モードが導入されました。このモードでは、UI が表示されない無人環境でブラウザを実行できます。基本的には、Chrome なしで Chrome を実行することです。

ヘッドレス モードは、PuppeteerChromeDriver などのプロジェクトによるブラウザの自動化に広く使用されています。ヘッドレス モードを使用して指定された URL の PDF ファイルを作成する最小限のコマンドライン例を次に示します。

chrome --headless --print-to-pdf https://developer.chrome.com/

ヘッドレスの新機能

ヘッドレスの最近の改善点について説明する前に、以前のヘッドレスの仕組みを理解することが重要です。先ほど紹介したコマンドライン スニペットでは、--headless コマンドライン フラグを使用しています。これは、ヘッドレスが通常の Chrome ブラウザの動作モードにすぎないことを示しています。驚いたことに、これは実際には事実ではありませんでした。技術的には、古いヘッドレスは別個の代替ブラウザ実装であり、たまたま同じ Chrome バイナリの一部として出荷されていました。//chrome の Chrome ブラウザのコードが共有されることはありません。

ご想像のとおり、このヘッドレス ブラウザを個別に実装して維持するには、エンジニアリングのオーバーヘッドが大きく発生しました。しかし問題はそれだけではありません。Headless は別個の実装であるため、Headful Chrome にはない独自のバグや機能がありました。これにより、自動ブラウザテストがヘッドフル モードでは合格するがヘッドレス モードでは不合格(またはその逆)という混乱する状況が生じました。これは自動化エンジニアにとって大きな課題となっています。また、ブラウザ拡張機能のインストールに依存する自動テストも除外されました。他のブラウザレベルの機能についても同様です。Headless が独自の個別の実装を行っていない限り、サポートされていませんでした。

2021 年、Chrome チームはこの問題の解決に着手し、ヘッドレス モードとヘッドフル モードを完全に統合しました。

新しい Chrome ヘッドレスは個別のブラウザに実装されるのではなく、Chrome とコードを共有するようになりました。

このたび、Chrome 112 で新しいヘッドレス モードをご利用いただけるようになりました。このモードでは、Chrome はプラットフォーム ウィンドウを作成しますが、表示はしません。その他の機能はすべて、既存のものも今後追加されるものも、制限なしでご利用いただけます。

新しいヘッドレスを試そう

新しいヘッドレス モードを試すには、--headless=new コマンドライン フラグを渡します。

chrome --headless=new

現時点では、以下の方法で以前のヘッドレス モードをご利用いただけます。

chrome --headless=old

現時点では、明示的な値を指定せずに --headless コマンドライン フラグを渡すと、引き続き古いヘッドレス モードが有効になりますが、今後このデフォルトを新しいヘッドレス モードに変更する予定です。

今年後半には、古いヘッドレス モードを Chrome バイナリから完全に削除し、Puppeteer でこのモードのサポートを終了する予定です。今回の削除の一環として、まだアップグレードできないユーザーのために、古いヘッドレスを個別のスタンドアロン バイナリとして提供する予定です。

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 で実行できる)こととは異なります。Chrome では、--dump-dom の出力を取得するために、まず HTML コードを解析し、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 フラグを追加すると、印刷ヘッダー(現在の日時を含む)とフッター(URL とページ番号を含む)を省略できます。

chrome --headless=new --print-to-pdf --no-pdf-header-footer https://developer.chrome.com/

--timeout

--timeout フラグは、最大待機時間(ミリ秒単位)を定義します。この時間が経過すると、ページの読み込み中であってもページのコンテンツが --dump-dom--screenshot--print-to-pdf によってキャプチャされます。

chrome --headless=new --print-to-pdf --timeout=5000 https://developer.chrome.com/

--timeout=5000 フラグを指定すると、Chrome は PDF を印刷する前に最大 5 秒待機します。したがって、このプロセスの実行にかかる時間は最大 5 秒です。

--virtual-time-budget

--virtual-time-budget を使用すると、タイムトラベルが可能になります。まあ、ある程度はね。仮想時間は、時間に依存するコード(setTimeout/setInterval など)の「早送り」として機能します。ブラウザはページのコードをできるだけ速く実行させ、ページが実際に時間を過ぎていると認識させます。

使用例として、setTimeout(fn, 1000) を使用して 1 秒ごとにカウンタをインクリメント、記録、表示するこちらのデモページをご覧ください。関連するコードは次のとおりです。

<output>0</output>
<script>
  const element = document.querySelector('output');
  let counter = 0;
  setInterval(() => {
    counter++;
    console.log(counter);
    element.textContent = counter;
  }, 1_000);
</script>

1 秒が経過するとページには「1」が表示され、2 秒が経過すると「2」というようになります。42 秒後にページの状態をキャプチャして PDF として保存する方法は以下のとおりです。

chrome --headless=new --print-to-pdf --virtual-time-budget=42000 https://mathiasbynens.be/demo/time

--allow-chrome-scheme-url

chrome:// URL にアクセスするには、--allow-chrome-scheme-url フラグが必要です。このフラグは Chrome 123 以降で使用できます。次の例をご覧ください。

chrome --headless=new --print-to-pdf --allow-chrome-scheme-url chrome://gpu

デバッグ

ヘッドレス モードでは Chrome は実質的に何も表示されないため、問題が発生した場合に何が起こっているのかを把握するのが難しいように思えるかもしれません。幸いなことに、ヘッドレス Chrome のデバッグは Headful Chrome とよく似ています。--remote-debugging-port コマンドライン フラグを指定して、Chrome をヘッドレス モードで起動するのがコツです。

chrome --headless=new --remote-debugging-port=0 https://developer.chrome.com/

これにより、次のような一意の WebSocket URL が stdout に出力されます。

DevTools listening on ws://127.0.0.1:60926/devtools/browser/b4bd6eaa-b7c8-4319-8212-225097472fd9

通常の Headful Chrome インスタンスでは、Chrome DevTools リモート デバッグを使用してヘッドレス ターゲットに接続して検査できます。これを行うには、chrome://inspect に移動して [Configure...] ボタンをクリックし、WebSocket URL の IP アドレスとポート番号を入力します。上記の例では、127.0.0.1:60926 を入力しました。[完了] をクリックすると、リモート ターゲットが、その下のすべてのタブと他のターゲットとともに表示されます。[inspect] をクリックすると、Chrome DevTools にアクセスして、リモートのヘッドレス ターゲットを検査できるようになります。ページのライブビューも確認できます。

Chrome DevTools でリモートのヘッドレス ターゲット ページを検査できます

フィードバック

新しいヘッドレス モードについて、皆様からのフィードバックをお待ちしております。問題が発生した場合は、ご報告ください