トラブルシューティング
このページを最新の状態に保つために、私たちは主にコミュニティの貢献に頼っています。情報が古くなっていることに気付いた場合は、プルリクエストを送信してください。
Cannot find module 'puppeteer-core/internal/...'
これは、Node.jsのバージョンが14未満の場合、またはカスタムリゾルバー(jest-resolve
など)を使用している場合に発生する可能性があります。前者の場合、非推奨のNode.jsバージョンはサポートしていません。後者の場合、通常はリゾルバー(または`jest`などの親モジュール)をアップグレードすることで解決します(例:https://github.com/puppeteer/puppeteer/issues/9121)
Could not find expected browser locally
v19.0.0以降、PuppeteerはPuppeteerのアップグレード間でより良いキャッシュを実現するために、os.homedir
を使用してブラウザを`~/.cache/puppeteer`にダウンロードします。一般的にホームディレクトリは明確に定義されていますが(Windowsでも)、ホームディレクトリが使用できない場合があります。この場合、インストールディレクトリを変更できる`PUPPETEER_CACHE_DIR`変数が提供されています。
例えば、
PUPPETEER_CACHE_DIR=$(pwd) npm install puppeteer
PUPPETEER_CACHE_DIR=$(pwd) node <script-path>
また、アプリケーションのルートに` .puppeteerrc.cjs`(または`puppeteer.config.cjs`)という名前の設定ファイルを作成し、以下の内容を記述することもできます。
const {join} = require('path');
/**
* @type {import("puppeteer").Configuration}
*/
module.exports = {
cacheDirectory: join(__dirname, '.cache', 'puppeteer'),
};
設定を有効にするには、`puppeteer`を再インストールする必要があります。詳細はPuppeteerの設定を参照してください。
Chrome headlessがWindowsで起動しない
一部のChromeポリシーでは、特定の拡張機能を使用してChrome/Chromiumを実行することが強制されている場合があります。
Puppeteerはデフォルトで`--disable-extensions`フラグを渡し、そのようなポリシーがアクティブな場合、起動に失敗します。
これを回避するには、フラグなしで実行してみてください。
const browser = await puppeteer.launch({
ignoreDefaultArgs: ['--disable-extensions'],
});
コンテキスト:issue 3681。
ChromeがLinuxで起動しない
必要なすべての依存関係がインストールされていることを確認してください。Linuxマシンで`ldd chrome | grep not`を実行すると、どの依存関係が不足しているかを確認できます。一般的なものは以下に示します。また、Chromeインストーラーによって宣言されている依存関係の最新リストについては、https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/dist_package_versions.jsonを参照してください。
Chromeは現在、Linux用のarm64バイナリを提供していません。Mac ARM用のarm64バイナリのみが存在します。つまり、デフォルトでダウンロードされるLinuxバイナリは、Linux arm64では動作しません。
Debian(例:Ubuntu)の依存関係
ca-certificates
fonts-liberation
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-headless-shellはGPUコンポジットを無効にする
chrome-headless-shellでは、ヘッドレスモードでGPUアクセラレーションを有効にするために`--enable-gpu`が必要です。
const browser = await puppeteer.launch({
headless: 'shell',
args: ['--enable-gpu'],
});
ChromeでGPUを設定する
一般的に、システムに適切なドライバがあれば、ChromeはGPUを検出して有効にすることができます。追加のヒントについては、ブログ記事https://developer.chrome.com/blog/supercharge-web-ai-testingを参照してください。
Chrome Linuxサンドボックスの設定
信頼できないWebコンテンツからホスト環境を保護するために、Chromeは複数層のサンドボックスを使用します。これが正しく機能するためには、最初にホストを設定する必要があります。Chromeが使用できる適切なサンドボックスがない場合、`No usable sandbox!`というエラーでクラッシュします。
Chromeで開くコンテンツを**絶対に信頼**できる場合は、`--no-sandbox`引数を使用してChromeを起動できます
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
サンドボックスなしで実行することは**強くお勧めしません**。代わりにサンドボックスを設定することを検討してください。
Chromiumでサンドボックスを設定するには、2つの方法があります。
[推奨] ユーザー名前空間のクローニングを有効にする
ユーザー名前空間のクローニングは、最新のカーネルでのみサポートされています。権限のないユーザー名前空間は、一般的に有効にしても問題ありませんが、場合によっては、(サンドボックス化されていない)非rootプロセスがカーネル権限に昇格するためのカーネル攻撃対象領域を広げてしまいます。
sudo sysctl -w kernel.unprivileged_userns_clone=1
[代替] setuidサンドボックスを設定する
setuidサンドボックスはスタンドアロンの実行可能ファイルとして提供され、PuppeteerがダウンロードするChromeの隣にあります。異なるChromeバージョンで同じサンドボックス実行可能ファイルを再利用しても問題ないため、ホスト環境ごとに1回だけ次の操作を実行できます。
# cd to Puppeteer cache directory (adjust the path if using a different cache directory).
cd ~/.cache/puppeteer/chrome/linux-<version>/chrome-linux64/
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
または、`Dockerfile`に以下を追加します
ENV CHROME_DEVEL_SANDBOX /usr/local/sbin/chrome-devel-sandbox
Travis CIでPuppeteerを実行する
👋 Puppeteerのテストは、v6.0.0(GitHub Actionsに移行したとき)までTravis CIで実行していました。参考までに、過去の`.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 test
WSL(Windows Subsystem for Linux)でPuppeteerを実行する
WSLに固有のヒントについては、このスレッドを参照してください。簡単に言うと、次のいずれかの方法で不足している依存関係をインストールする必要があります
- WSLにChromeをインストールして、すべての依存関係をインストールする
- 必要な依存関係を手動でインストールする:`sudo apt install libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2`。
必要な依存関係のリストは古くなる可能性があり、既にインストールされている内容によって異なります。
CircleCIでPuppeteerを実行する
CircleCIでPuppeteerをスムーズに実行するには、次の手順が必要です
- 設定でNodeJSイメージから始めます
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オーブ(手順)を使用するか、そのソースの一部を独自の設定に貼り付けます。
- 最後に、Jestを介してPuppeteerを使用している場合、子プロセスの生成でエラーが発生する可能性があります
これは、Jestがコンテナに許可されているプロセス数(
[00:00.0] jest args: --e2e --spec --max-workers=36
Error: spawn ENOMEM
at ChildProcess.spawn (internal/child_process.js:394:11)2
)ではなく、マシン全体のプロセス数(36
)を自動検出していることが原因と考えられます。これを修正するには、テストコマンドでjest --maxWorkers=2
を設定してください。
DockerでのPuppeteerの実行
👋 v3.0.xまでは、DockerコンテナでPuppeteerのテストを実行するためにCirrus CIを使用していました。過去の
Dockerfile.linux
(v3.0.1)を参照してください。 v16.0.0以降、GitHubレジストリを介してDockerイメージを提供しています。Dockerfileはこちらにあり、使用方法の説明はREADME.mdにあります。以下の手順は、独自のイメージをビルドする場合にも役立つ可能性があります。
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_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の内容を文字列として>"
を渡してコンテナを実行します。
docker run -i --init --rm --cap-add=SYS_ADMIN \
--name puppeteer-chrome puppeteer-chrome-linux \
node -e "`cat yourscript.js`"
https://github.com/ebidel/try-puppeteerには、App Engine Flex(Node)で実行されているWebサーバーからこのDockerfileを実行する方法を示す完全な例があります。
Alpineでの実行
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_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
...
GitlabCIでのPuppeteerの実行
これは上記の手順と非常によく似ていますが、最終的に成功するには少し異なる構成が必要です。
通常、問題は次のようになります。
Error: Failed to launch chrome! spawn /usr/bin/chromium-browser ENOENT
2か所を修正する必要があります。
gitlab-ci.yml
の設定- puppeteerを起動する際の引数リスト
gitlab-ci.yml
では、Docker環境でヘッドレスChromeを起動できるようにするために、いくつかのパッケージをインストールする必要があります。
before_script:
- apt-get update
- apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2
libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4
libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 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 ca-certificates fonts-liberation libnss3 lsb-release
xdg-utils wget
次に、Puppeteerを起動するときに、'--no-sandbox'
モードと'--disable-setuid-sandbox'
を使用する必要があります。これは、.launch()
呼び出しに引数として渡すことで実行できます:puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
。
Google Cloud RunでのPuppeteerの実行
Google Cloud Runは、HTTPレスポンスがクライアントに書き込まれた後、デフォルトでCPUを無効にします。これは、レスポンスが書き込まれた後に「バックグラウンドでpuppeteerを実行」すると、puppeteerが非常に遅く(起動に1〜5分かかります)なることを意味します。
そのため、この単純なexpressアプリは非常に遅く感じられます。
import express from 'express';
const app = express();
app.post('/test-puppeteer', (req, res) => {
res.json({
jobId: 123,
acknowledged: true,
});
puppeteer.launch().then(browser => {
// 2 minutes later...
});
});
app.listen(3000);
puppeteerはレスポンスが送信された後に起動されるため、GCRではCPUが無効になっているため、速度が遅くなります。代わりに、次のようにしてください。
app.post('/test-puppeteer', (req, res) => {
puppeteer.launch().then(browser => {
// A second later...
res.json({
jobId: 123,
acknowledged: true,
});
});
});
バックグラウンドで処理を実行する場合は、レスポンスが送信された後でも「常にCPUを有効にする」必要があります。これで問題は解決するはずです。
ヒント
デフォルトでは、Dockerは/dev/shm
共有メモリ空間を64MBでコンテナを実行します。これは、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
ユーザーを非特権ユーザーとして追加するため、必要なすべての権限がない場合があります。
ゾンビのChromeプロセスが多数残っている場合は、dumb-initを確認する価値があります。PID = 1のプロセスには特別な処理があり、場合によっては(たとえば、Docker内)Chromeを適切に終了することが困難になります。
クラウドでのPuppeteerの実行
Google App EngineでのPuppeteerの実行
App Engineスタンダード環境のNode.jsランタイムには、ヘッドレスChromeを実行するために必要なすべてのシステムパッケージが付属しています。
puppeteer
を使用するには、package.json
でモジュールを依存関係として指定し、アプリケーションのルートに.puppeteerrc.cjs
という名前のファイルを含めて、puppeteerキャッシュディレクトリを次の内容でオーバーライドします。
const {join} = require('path');
/**
* @type {import("puppeteer").Configuration}
*/
module.exports = {
cacheDirectory: join(__dirname, 'node_modules', '.puppeteer_cache'),
};
[!NOTE] Google App Engineは、ビルド間で
node_modules
をキャッシュします。Puppeteerキャッシュをnode_modules
のサブディレクトリとして指定すると、postinstall
が実行されないためにPuppeteerがブラウザの実行ファイルを見つけられないという問題が軽減されます。
Google Cloud FunctionsでのPuppeteerの実行
Google Cloud FunctionsのNode.jsランタイムには、ヘッドレスChromeを実行するために必要なすべてのシステムパッケージが付属しています。
puppeteer
を使用するには、package.json
でモジュールを依存関係として指定し、アプリケーションのルートに.puppeteerrc.cjs
という名前のファイルを含めて、puppeteerキャッシュディレクトリを次の内容でオーバーライドします。
const {join} = require('path');
/**
* @type {import("puppeteer").Configuration}
*/
module.exports = {
cacheDirectory: join(__dirname, 'node_modules', '.puppeteer_cache'),
};
[!NOTE] Google Cloud Functionsは、ビルド間で
node_modules
をキャッシュします。 puppeteerキャッシュを`node_modules`のサブディレクトリとして指定すると、キャッシュがヒットしたときにpuppeteerインストールプロセスが実行されないという問題が軽減されます。
Google Cloud RunでのPuppeteerの実行
Google Cloud RunのデフォルトのNode.jsランタイムには、ヘッドレスChromeを実行するために必要なシステムパッケージが付属していません。独自のDockerfile
を設定し、不足している依存関係を含める必要があります。
HerokuでのPuppeteerの実行
HerokuでPuppeteerを実行するには、Herokuが起動するLinuxボックスに含まれていない追加の依存関係が必要です。デプロイ時に依存関係を追加するには、[設定]>[ビルドパック]で、アプリのビルドパックのリストにPuppeteer Herokuビルドパックを追加します。
ビルドパックのURLはhttps://github.com/jontewks/puppeteer-heroku-buildpackです。
Puppeteerの起動時に'--no-sandbox'
モードを使用していることを確認してください。これは、.launch()呼び出しに引数として渡すことで実行できます:`puppeteer.launch({args:['--no-sandbox']});`。
ビルドパックの追加をクリックすると、そのURLが入力に貼り付けられ、保存をクリックします。次回のデプロイでは、アプリはPuppeteerの実行に必要な依存関係もインストールします。
中国語、日本語、または韓国語の文字をレンダリングする必要がある場合は、https://github.com/CoffeeAndCode/puppeteer-heroku-buildpackのような追加のフォントファイルを含むビルドパックを使用する必要がある場合があります。
@timlelandによるサンプルプロジェクトを含む別の簡単なガイドもあります:https://timleland.com/headless-chrome-on-heroku/。
AWS LambdaでのPuppeteerの実行
AWS Lambdaは、デプロイパッケージのサイズを〜50MBに制限しています。これは、LambdaでヘッドレスChrome(ひいてはPuppeteer)を実行する上で課題となります。コミュニティは、これらの問題を回避するいくつかのリソースをまとめています。
- https://github.com/sparticuz/chromium(最新の
chromium
バージョンをサポートする、ベンダーおよびフレームワークに依存しないライブラリ) - https://github.com/alixaxel/chrome-aws-lambda (puppeteer 10.1までサポート - 古くなっています)
- https://github.com/adieuadieu/serverless-chrome/blob/HEAD/docs/chrome.md (サーバーレスプラグイン - 古くなっています)
Amazon-Linuxを実行しているAWS EC2インスタンスでのPuppeteerの実行
CI / CDパイプラインでamazon-linuxを実行しているEC2インスタンスを使用していて、amazon-linuxでPuppeteerテストを実行する場合は、次の手順に従います。
-
Chromiumをインストールするには、最初にEPEL(Extra Packages for Enterprise Linux)の一部として提供される
amazon-linux-extras
を有効にする必要があります。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
と互換性のない方法で変更している可能性があるためです。
この問題の回避策としては、トランスパイラがコードを改変しないように指示する方法があります。たとえば、TypeScript で最新の ECMAScript バージョンを使用するように設定します("target": "es2018"
)。別の回避策としては、関数ではなく文字列テンプレートを使用する方法があります。
await page.evaluate(`(async() => {
console.log('1');
})()`);