問題排解
為了保持本頁面的更新,我們很大程度上依賴社群的貢獻。如果您發現有任何內容過時,請發送 PR。
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 將使用 os.homedir
將瀏覽器下載到 ~/.cache/puppeteer
中,以便在 Puppeteer 升級之間更好地進行快取。通常,主目錄定義良好(即使在 Windows 上也是如此),但偶爾主目錄可能不可用。在這種情況下,我們提供 PUPPETEER_CACHE_DIR
變數,讓您可以變更安裝目錄。
例如,
- npm
- Yarn
- pnpm
PUPPETEER_CACHE_DIR=$(pwd) npm install puppeteer
PUPPETEER_CACHE_DIR=$(pwd) node <script-path>
PUPPETEER_CACHE_DIR=$(pwd) yarn add puppeteer
PUPPETEER_CACHE_DIR=$(pwd) node <script-path>
PUPPETEER_CACHE_DIR=$(pwd) pnpm add 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 無法在 Windows 上啟動
某些 Chrome 政策可能會強制使用某些擴充功能來執行 Chrome/Chromium。
Puppeteer 預設會傳遞 --disable-extensions
旗標,並且在這些政策生效時將無法啟動。
為了解決此問題,請嘗試在不使用旗標的情況下執行
const browser = await puppeteer.launch({
ignoreDefaultArgs: ['--disable-extensions'],
});
背景資訊:issue 3681。
Chrome 在 Windows 上回報沙箱錯誤
Chrome 在 Windows 上使用沙箱,這需要下載的 Chrome 檔案具有額外權限。從 Puppeteer v22.14.0 開始,Puppeteer 會嘗試透過在瀏覽器安裝期間執行 Chrome 提供的 setup.exe
工具來設定這些權限。
如果您使用的是舊版的 Puppeteer,或者仍在瀏覽器輸出中看到以下錯誤
[24452:59820:0508/113713.058:ERROR:sandbox_win.cc(913)] Sandbox cannot access executable. Check filesystem permissions are valid. See https://bit.ly/31yqMJR.: Access is denied. (0x5)
您可以使用 icacls 手動設定權限
icacls %USERPROFILE%/.cache/puppeteer/chrome /grant *S-1-15-2-1:(OI)(CI)(RX)
在高安全性環境中,應使用更嚴格的 SID,例如來自 安裝程式的 SID。
請參閱 https://bit.ly/31yqMJR 以取得更多詳細資訊。
Chrome 無法在 Linux 上啟動
請確定已安裝所有必要的相依性。您可以在 Linux 電腦上執行 ldd chrome | grep not
來檢查缺少哪些相依性。下面提供常見的相依性。此外,請參閱 https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/dist_package_versions.json,以取得 Chrome 安裝程式宣告的最新相依性清單。
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 需要 --enable-gpu
才能在無頭模式中啟用 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 沙箱
為了保護主機環境免受不受信任的網頁內容侵害,Chrome 使用多層沙箱。為了使其正常運作,應先設定主機。如果 Chrome 沒有可用的沙箱,它將會因為錯誤 No usable sandbox!
而崩潰。
如果您完全信任您在 Chrome 中開啟的內容,您可以使用 --no-sandbox
引數啟動 Chrome
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
強烈不建議在沒有沙箱的情況下執行。請考慮改為設定沙箱。
建議的執行 Chrome 的方式是使用沙箱
Ubuntu 上 AppArmor 的問題
Ubuntu 23.10+(或未來可能出現的其他 Linux 發行版)提供適用於 /opt/google/chrome/chrome 安裝的 Chrome 穩定二進位檔(預設安裝路徑)的 AppArmor 設定檔。此政策儲存在 /etc/apparmor.d/chrome 中。此 AppArmor 政策會阻止 Puppeteer 下載的 Chrome for Testing 二進位檔使用使用者命名空間,導致嘗試啟動瀏覽器時發生 No usable sandbox!
錯誤。
如需解決方法,請參閱 https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md。
使用 setuid 沙箱
重要注意事項:Linux SUID 沙箱幾乎但未完全移除。請參閱 https://bugs.chromium.org/p/chromium/issues/detail?id=598454 本節大多已過時。
setuid 沙箱以獨立的可執行檔形式出現,位於 Puppeteer 下載的 Chrome 旁邊。重複使用相同沙箱可執行檔用於不同的 Chrome 版本是可以的,因此以下步驟在每個主機環境中只需執行一次
# 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
👋 我們在 v6.0.0 之前(當我們遷移到 GitHub Actions 時)在 Travis CI 上執行 Puppeteer 測試 - 請參閱我們歷史的
.travis.yml
(v5.5.0) 以供參考。
提示與技巧
- 為了在非無頭模式下運行 Chrome for Testing,應該啟動 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 Orb ( 說明 ),或將其 原始碼 的部分貼到您自己的設定中。 - 最後,如果您透過 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)36
),而不是您的容器允許的數量 (2
)。要解決此問題,請在您的測試命令中設定jest --maxWorkers=2
。
在 Docker 中執行 Puppeteer
👋 我們使用 Cirrus Ci 在 Docker 容器中為 Puppeteer 執行測試,直到 v3.0.x 版本 - 請參閱我們歷史的
Dockerfile.linux
(v3.0.1) 作為參考。從 v16.0.0 開始,我們透過 GitHub 註冊表發布 Docker 映像檔。Dockerfile 位於這裡,使用說明位於README.md中。如果您要建立自己的映像檔,以下說明可能仍然有幫助。
在 Docker 中啟動並運行無頭 Chrome 可能很棘手。Puppeteer 安裝的捆綁式 Chrome for Testing 缺少必要的共享程式庫相依性。
若要修正此問題,您需要在 Dockerfile 中安裝遺失的相依性和最新的 Chrome for Testing 套件。
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 Chrome for Testing 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 Chrome for Testing 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 "<您的 script.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 上執行
請注意,Chrome 不支援開箱即用的 Alpine,因此請確保您在 Alpine 上安裝了相容的系統相依性,並在使用前測試映像檔。請參閱 https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/dist_package_provides.json 和 https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/dist_package_versions.json,以取得支援的發行版本上所需的系統套件清單。
警告
Alpine 3.20 中的目前 Chromium 版本會導致 Puppeteer 逾時問題。降級到 Alpine 3.19 可以解決此問題。請參閱 #11640、#12637、#12189。
您需要找到最新的 Chromium 套件,然後查詢 Puppeteer 的支援的瀏覽器版本,並使用對應的版本。
範例
Alpine Chromium 版本:100
Puppeteer: Puppeteer v13.5.0
Dockerfile
FROM alpine
# Installs 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
您需要修補兩個地方。
- 您的
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 libgbm1 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);
它很慢,因為在 GCR 上,Puppeteer 是在發送回應後啟動的,因此會停用 CPU。您要做的是這個。
app.post('/test-puppeteer', (req, res) => {
puppeteer.launch().then(browser => {
// A second later...
res.json({
jobId: 123,
acknowledged: true,
});
});
});
如果您想在背景中執行內容,您需要「永遠啟用 CPU」(前往 Google Cloud Run 服務 > 編輯 & 部署修訂版本 > CPU 配置和定價),即使在發送回應後也是如此。這應該可以解決問題。
提示
預設情況下,Docker 運行的容器具有 64MB 的 /dev/shm
共享記憶體空間。對於 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'],
});
這會將共享記憶體檔案寫入 /tmp
而不是 /dev/shm
。請參閱 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 環境中。若要在部署時加入這些依賴項,請在「設定」>「Buildpacks」下,將 Puppeteer Heroku buildpack 加入您應用程式的 buildpack 清單中。
該 buildpack 的網址為 https://github.com/jontewks/puppeteer-heroku-buildpack
請確保在啟動 Puppeteer 時使用 '--no-sandbox'
模式。這可以透過將其作為參數傳遞到您的 .launch()
呼叫來完成:puppeteer.launch({ args: ['--no-sandbox'] });
。
當您點擊「新增 buildpack」時,只需將該網址貼入輸入框,然後點擊「儲存」。在下次部署時,您的應用程式也會安裝 Puppeteer 執行所需的依賴項。
如果您需要渲染中文、日文或韓文字符,您可能需要使用包含額外字型檔案的 buildpack,例如 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
)
在執行 Amazon-Linux 的 AWS EC2 執行個體上執行 Puppeteer
如果您在 CI/CD 管道中使用執行 amazon-linux 的 EC2 執行個體,並且想在 amazon-linux 中執行 Puppeteer 測試,請按照以下步驟操作。
-
若要安裝 Chromium,您必須先啟用
amazon-linux-extras
,它屬於 EPEL(適用於企業 Linux 的額外套件)的一部分。sudo amazon-linux-extras install epel -y
-
接下來,安裝 Chromium。
sudo yum install -y chromium
現在 Puppeteer 可以啟動 Chromium 來執行您的測試。如果您不啟用 EPEL,並且繼續將 chromium 作為 npm install
的一部分安裝,Puppeteer 將無法啟動 Chromium,因為缺少 libatk-1.0.so.0
和許多其他套件。
程式碼轉譯問題
如果您正在使用 JavaScript 轉譯器(如 babel 或 TypeScript),則使用異步函數呼叫 evaluate()
可能無法正常運作。這是因為當 puppeteer
使用 Function.prototype.toString()
來序列化函數時,轉譯器可能會以與 puppeteer
不相容的方式變更輸出程式碼。
解決此問題的一些方法是指示轉譯器不要干擾程式碼,例如,將 TypeScript 設定為使用最新的 ecma 版本 ("target": "es2018"
)。另一種方法是使用字串範本而不是函數。
await page.evaluate(`(async() => {
console.log('1');
})()`);