Windows でヘッドレス Chrome が起動しない
一部の Chrome ポリシーでは、特定の拡張機能で Chrome または Chromium の実行が強制されている場合があります。
Puppeteer はデフォルトで --disable-extensions
フラグを渡すため、このようなポリシーが有効な場合、Puppeteer の起動に失敗します。
この問題を回避するには、フラグを指定せずに実行してみてください。
const browser = await puppeteer.launch({
ignoreDefaultArgs: ['--disable-extensions'],
});
コンテキスト: 問題 3681
UNIX でヘッドレス Chrome が起動しない
必要な依存関係がすべてインストールされていることを確認します。Linux マシンで ldd chrome | grep not
を実行すると、欠落している依存関係を確認できます。
Debian(Ubuntu)の依存関係
ca-certificates
fonts-liberation
libappindicator3-1
libasound2
libatk-bridge2.0-0
libatk1.0-0
libc6
libcairo2
libcups2
libdbus-1-3
libexpat1
libfontconfig1
libgbm1
libgcc1
libglib2.0-0
libgtk-3-0
libnspr4
libnss3
libpango-1.0-0
libpangocairo-1.0-0
libstdc++6
libx11-6
libx11-xcb1
libxcb1
libxcomposite1
libxcursor1
libxdamage1
libxext6
libxfixes3
libxi6
libxrandr2
libxrender1
libxss1
libxtst6
lsb-release
wget
xdg-utils
CentOS の依存関係
alsa-lib.x86_64
atk.x86_64
cups-libs.x86_64
gtk3.x86_64
ipa-gothic-fonts
libXcomposite.x86_64
libXcursor.x86_64
libXdamage.x86_64
libXext.x86_64
libXi.x86_64
libXrandr.x86_64
libXScrnSaver.x86_64
libXtst.x86_64
pango.x86_64
xorg-x11-fonts-100dpi
xorg-x11-fonts-75dpi
xorg-x11-fonts-cyrillic
xorg-x11-fonts-misc
xorg-x11-fonts-Type1
xorg-x11-utils
依存関係をインストールしたら、次のコマンドを使用して nss ライブラリを更新する必要があります
yum update nss -y
ディスカッションを確認:
ヘッドレス Chrome で GPU 合成を無効にする
Chrome と Chromium でヘッドレス モードでの GPU アクセラレーションを有効にするには、--use-gl=egl
が必要です。
const browser = await puppeteer.launch({
headless: true,
args: ['--use-gl=egl'],
});
Chrome がダウンロードされたが、Node.js で起動できない
Chromium を起動しようとしたときに次のようなエラーが表示された場合:
(node:15505) UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process!
spawn /Users/.../node_modules/puppeteer/.local-chromium/mac-756035/chrome-mac/Chromium.app/Contents/MacOS/Chromium ENOENT
これは、ブラウザはダウンロードされたものの、正しく抽出できなかったことを意味します。
最も一般的な原因は、Node.js v14.0.0 のバグで、ブラウザのダウンロードを適切な場所に抽出するために Puppeteer が使用するモジュール extract-zip
が破損していることです。このバグは Node.js v14.1.0 で修正されているため、このバージョン以降を使用していることを確認してください。
Chrome Linux サンドボックスを設定する
ホスト環境を信頼できないウェブ コンテンツから保護するために、Chrome では複数のサンドボックス レイヤを使用しています。これを正常に機能させるには、最初にホストを構成する必要があります。Chrome に適したサンドボックスがない場合は、No usable sandbox!
というエラーでクラッシュします。
Chrome で開くコンテンツを絶対に信頼できる場合は、--no-sandbox
引数を指定して Chrome を起動できます。
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
Chromium でサンドボックスを設定する方法は 2 つあります。
[推奨] ユーザーの名前空間のクローン作成を有効にする
Sser 名前空間のクローン作成は最新のカーネルでのみサポートされています。非特権ユーザーの名前空間を有効にしても問題ありませんが、(サンドボックス化されていない)非 root プロセスがカーネル特権に昇格するカーネル攻撃対象領域が増える可能性があります。
sudo sysctl -w kernel.unprivileged_userns_clone=1
[代替] setuid サンドボックスを設定する
setuid サンドボックスはスタンドアロンの実行ファイルとして提供され、Puppeteer がダウンロードする Chromium の隣にあります。同じサンドボックスの実行可能ファイルを異なる Chromium バージョンで再利用しても問題ありません。それによって、ホスト環境ごとに 1 回だけ実行できます。
# cd to the downloaded instance
cd <project-dir-path>/node_modules/puppeteer/.local-chromium/linux-<revision>/chrome-linux/
sudo chown root:root chrome_sandbox
sudo chmod 4755 chrome_sandbox
# copy sandbox executable to a shared location
sudo cp -p chrome_sandbox /usr/local/sbin/chrome-devel-sandbox
# export CHROME_DEVEL_SANDBOX env variable
export CHROME_DEVEL_SANDBOX=/usr/local/sbin/chrome-devel-sandbox
デフォルトで CHROME_DEVEL_SANDBOX
環境変数をエクスポートすることもできます。この場合、次のコードを ~/.bashrc
または .zshenv
に追加します。
export CHROME_DEVEL_SANDBOX=/usr/local/sbin/chrome-devel-sandbox
Travis CI で Puppeteer を実行する
v6.0.0 まで Travis CI で Puppeteer のテストを実行した後、GitHub Actions に移行しました。参考として、.travis.yml
(v5.5.0)をご覧ください。
ベスト プラクティスをいくつか紹介します。
- Chromium をヘッドレス以外のモードで実行するには、xvfb サービスを起動する必要があります
- デフォルトで Travis 上の Xenial Linux で実行
- デフォルトで
npm install
を実行する node_modules
はデフォルトでキャッシュに保存される
.travis.yml
は次のようになります。
language: node_js
node_js: node
services: xvfb
script:
- npm run test
CircleCI で Puppeteer を実行する
- 構成で NodeJS イメージから始めます。
yaml docker: - image: circleci/node:14 # Use your desired version environment: NODE_ENV: development # Only needed if puppeteer is in `devDependencies`
libXtst6
のような依存関係は、おそらくapt-get
でインストールする必要があります。そのため、threetreeslight/puppeteer ORB を使用するか(instructions)、そのソースの一部を独自の構成に貼り付けます。- 最後に、Jest を介して Puppeteer を使用している場合、子プロセスを生成するときにエラーが発生する可能性があります。
shell [00:00.0] jest args: --e2e --spec --max-workers=36 Error: spawn ENOMEM at ChildProcess.spawn (internal/child_process.js:394:11)
これは、Jest がコンテナに許可されている数(2
)ではなく、マシン全体のプロセス数(36
)を自動検出したことが原因と考えられます。この問題を解決するには、テストコマンドでjest --maxWorkers=2
を設定します。
Docker で Puppeteer を実行する
Docker でヘッドレス Chrome を使い始めるのは簡単ではありません。Puppeteer がインストールするバンドルされた Chromium に、必要な共有ライブラリの依存関係がありません。
この問題を解決するには、Dockerfile に不足している依存関係と最新の Chromium パッケージをインストールする必要があります。
FROM node:14-slim
# Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others)
# Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer
# installs, work.
RUN apt-get update \
&& apt-get install -y wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# If running Docker >= 1.13.0 use docker run's --init arg to reap zombie processes, otherwise
# uncomment the following lines to have `dumb-init` as PID 1
# ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_x86_64 /usr/local/bin/dumb-init
# RUN chmod +x /usr/local/bin/dumb-init
# ENTRYPOINT ["dumb-init", "--"]
# Uncomment to skip the chromium download when installing puppeteer. If you do,
# you'll need to launch puppeteer with:
# browser.launch({executablePath: 'google-chrome-stable'})
# ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
# Install puppeteer so it's available in the container.
RUN npm init -y && \
npm i puppeteer \
# Add user so we don't need --no-sandbox.
# same layer as npm install to keep re-chowned files from using up several hundred MBs more space
&& groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /node_modules \
&& chown -R pptruser:pptruser /package.json \
&& chown -R pptruser:pptruser /package-lock.json
# Run everything after as non-privileged user.
USER pptruser
CMD ["google-chrome-stable"]
コンテナを構築します。
docker build -t puppeteer-chrome-linux .
コマンドとして node -e "<yourscript.js content as a string>"
を渡し、コンテナを実行します。
docker run -i --init --rm --cap-add=SYS_ADMIN \
--name puppeteer-chrome puppeteer-chrome-linux \
node -e "`cat yourscript.js`"
App Engine Flex(Node)で実行されているウェブサーバーからこの Dockerfile を実行する方法については、https://github.com/ebidel/try-puppeteer の完全な例をご覧ください。
アルプスランニング
Alpine でサポートされている最新の Chromium パッケージは 100 です。これは、Puppeteer v13.5.0 に対応します。
Dockerfile の例:
FROM alpine
# Installs latest Chromium (100) package.
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont \
nodejs \
yarn
...
# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
# Puppeteer v13.5.0 works with Chromium 100.
RUN yarn add puppeteer@13.5.0
# Add user so we don't need --no-sandbox.
RUN addgroup -S pptruser && adduser -S -G pptruser pptruser \
&& mkdir -p /home/pptruser/Downloads /app \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /app
# Run everything after as non-privileged user.
USER pptruser
...
Docker のベスト プラクティス
デフォルトでは、Docker は /dev/shm
共有メモリ空間が 64 MB のコンテナを実行します。この値は Chrome には小さすぎるため、大きなページをレンダリングすると Chrome がクラッシュします。この問題を解決するには、docker run --shm-size=1gb
でコンテナを実行して /dev/shm
のサイズを増やします。Chrome 65 以降では、この作業は不要になりました。代わりに、--disable-dev-shm-usage
フラグを使用してブラウザを起動します。
const browser = await puppeteer.launch({
args: ['--disable-dev-shm-usage'],
});
これにより、共有メモリファイルが /dev/shm
ではなく /tmp
に書き込まれます。crbug.com/736452 を確認する。
Chrome の起動時に、他に不審なエラーは表示されますか?ローカルで開発する場合は、docker run --cap-add=SYS_ADMIN
を使用してコンテナを実行してみてください。Dockerfile は非特権ユーザーとして pptr
ユーザーを追加するため、必要な権限がすべて付与されていない可能性があります。
dumb-init は、Chrome プロセスが残っていて多数のゾンビを見つけているのであれば、チェックする価値があります。PID=1
を使用するプロセスには特別な処理があり、場合によっては(Docker などで)Chrome を適切に終了することが困難になります。
クラウドで Puppeteer を実行する
Google App Engine 上
App Engine スタンダード環境の Node.js ランタイムには、ヘッドレス Chrome の実行に必要なすべてのシステム パッケージが付属しています。
puppeteer
を使用するには、モジュールを package.json
の依存関係としてリストし、Google App Engine にデプロイします。App Engine で puppeteer
を使用する方法について詳しくは、公式チュートリアルをご覧ください。
Google Cloud Functions の場合
Google Cloud Functions の Node.js 10 ランタイムには、ヘッドレス Chrome の実行に必要なすべてのシステム パッケージが付属しています。
puppeteer
を使用するには、package.json
でモジュールを依存関係としてリストし、nodejs10
ランタイムを使用して関数を Google Cloud Functions にデプロイします。
Google Cloud Run で Puppeteer を実行する
Google Cloud Run のデフォルトの Node.js ランタイムには、ヘッドレス Chrome の実行に必要なシステム パッケージが付属していません。独自の Dockerfile
をセットアップし、欠落している依存関係を含めます。
Heroku の場合
Heroku で Puppeteer を実行するには、Heroku がスピンアップする Linux ボックスに含まれていない依存関係を追加する必要があります。deploy の依存関係を追加するには、[Settings] > [Buildpacks] で、アプリの Buildpack リストに Puppeteer Heroku Buildpack を追加します。
Buildpack の URL は https://github.com/jontewks/puppeteer-heroku-buildpack
です
Puppeteer を起動するときは、必ず '--no-sandbox'
モードを使用してください。これを行うには、引数として .launch()
呼び出し(puppeteer.launch({ args: ['--no-sandbox'] });
)に渡します。
[Add Buildpack] をクリックし、その URL を入力に貼り付け、[Save] をクリックします。次のデプロイでは、Puppeteer の実行に必要な依存関係もインストールされます。
中国語、日本語、韓国語の文字をレンダリングする必要がある場合は、https://github.com/CoffeeAndCode/puppeteer-herku-buildpack のような追加のフォント ファイルを含む Buildpack を使用する必要があります。
@timleland による別のガイドでも、サンプル プロジェクトが含まれています。
AWS Lambda の場合
AWS Lambda では、デプロイ パッケージのサイズが最大 50 MB に制限されています。このため、Lambda でヘッドレス Chrome(したがって Puppeteer)を実行することが課題となります。この問題の回避に役立つリソースをコミュニティがまとめています。
- AWS Lambda と Google Cloud Functions 用の Chromium バイナリ(Puppeteer の最新の安定版リリースで更新)
- Marco Lüthy の Chrome/Chromium on AWS Lambda はサーバーレス プラグインであり、古いバージョンです。
Amazon-Linux を実行している AWS EC2 インスタンス
CI/CD パイプラインで amazon-linux を実行している EC2 インスタンスがあり、amazon-linux で Puppeteer テストを実行する場合は、次の手順を行います。
Chromium をインストールするには、まず
amazon-linux-extras
を有効にする必要があります。これは、EPEL(Extra Packages for Enterprise Linux)の一部です。sudo amazon-linux-extras install epel -y
次に、Chromium をインストールします。
sudo yum install -y chromium
これで、Puppeteer で Chromium を起動してテストを実行できるようになりました。EPEL を有効にせず、npm install
の一部として Chromium のインストールを続行すると、libatk-1.0.so.0
とその他多くのパッケージを使用できないため、Puppeteer は Chromium を起動できません。
コードのトランスパイルに関する問題
babel や TypeScript などの JavaScript トランスパイラを使用している場合は、非同期関数で evaluate()
を呼び出せない可能性があります。これは、puppeteer
は Function.prototype.toString()
を使用して関数をシリアル化しますが、トランスパイラは puppeteer
と互換性のない方法で出力コードを変更する可能性があるためです。
この問題の回避策としては、コードを改ざんしないように Transpiler に指示することがあります。たとえば、最新の ecma バージョン("target": "es2018"
)を使用するように TypeScript を設定します。もう 1 つの回避策は、関数ではなく文字列テンプレートを使用することです。
await page.evaluate(`(async() => {
console.log('1');
})()`);