Chrome Headless tidak diluncurkan di Windows
Beberapa kebijakan Chrome mungkin menerapkan Chrome atau Chromium dengan Ekstensi tertentu.
Puppeteer meneruskan flag --disable-extensions
secara default sehingga gagal
diluncurkan saat kebijakan tersebut aktif.
Untuk mengatasi hal ini, coba jalankan tanpa flag:
const browser = await puppeteer.launch({
ignoreDefaultArgs: ['--disable-extensions'],
});
Konteks: masalah 3681.
Chrome Headless tidak diluncurkan di UNIX
Pastikan semua dependensi yang diperlukan telah diinstal. Anda dapat menjalankan
ldd chrome | grep not
di mesin Linux untuk memeriksa dependensi mana yang
tidak ada.
Dependensi 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
Dependensi 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
Setelah menginstal dependensi, Anda perlu memperbarui library nss menggunakan perintah ini
yum update nss -y
Lihat diskusi:
Chrome Headless menonaktifkan komposisi GPU
Chrome dan Chromium memerlukan --use-gl=egl
untuk mengaktifkan
akselerasi GPU dalam mode headless.
const browser = await puppeteer.launch({
headless: true,
args: ['--use-gl=egl'],
});
Chrome telah didownload tetapi gagal diluncurkan di Node.js
Jika Anda mendapatkan error yang terlihat seperti ini saat mencoba meluncurkan 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
Artinya, browser telah didownload tetapi gagal diekstrak dengan benar.
Penyebab paling umum adalah bug di Node.js v14.0.0 yang merusak extract-zip
,
modul yang digunakan Puppeteer untuk mengekstrak download browser ke tempat yang tepat. Bug ini telah diperbaiki di Node.js v14.1.0, jadi pastikan Anda menjalankan versi tersebut atau yang lebih tinggi.
Menyiapkan sandbox Chrome Linux
Untuk melindungi lingkungan host dari konten web yang tidak tepercaya, Chrome menggunakan
beberapa lapisan sandbox.
Agar berfungsi dengan baik, {i>host<i} harus dikonfigurasi terlebih dahulu. Jika tidak ada
sandbox yang baik untuk digunakan Chrome, Chrome akan mengalami error dan menampilkan error No usable sandbox!
.
Jika Anda sangat memercayai konten yang dibuka di Chrome, Anda dapat meluncurkan
Chrome dengan argumen --no-sandbox
:
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
Ada 2 cara untuk mengonfigurasi sandbox di Chromium.
[direkomendasikan] Mengaktifkan cloning namespace pengguna
Kloning namespace Sser hanya didukung oleh kernel modern. Namespace pengguna yang tidak memiliki hak istimewa biasanya dapat diaktifkan, tetapi dapat membuka lebih banyak permukaan serangan kernel untuk proses non-root (yang tidak di-sandbox) guna meningkatkan hak istimewa kernel.
sudo sysctl -w kernel.unprivileged_userns_clone=1
[alternatif] Menyiapkan sandbox setuid
Sandbox setuid tersedia sebagai file yang dapat dieksekusi mandiri dan terletak di samping Chromium yang didownload Puppeteer. Anda dapat menggunakan kembali sandbox yang sama yang dapat dieksekusi untuk versi Chromium yang berbeda, sehingga hal berikut hanya dapat dilakukan sekali per lingkungan host:
# 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
Anda mungkin ingin mengekspor variabel env CHROME_DEVEL_SANDBOX
secara default. Dalam hal ini, tambahkan kode berikut ke ~/.bashrc
atau .zshenv
:
export CHROME_DEVEL_SANDBOX=/usr/local/sbin/chrome-devel-sandbox
Jalankan Puppeteer di Travis CI
Kami menjalankan pengujian untuk Puppeteer di Travis CI hingga v6.0.0, setelah itu kami bermigrasi ke GitHub Actions. Anda dapat melihat .travis.yml
(v5.5.0) untuk referensi.
Berikut ini beberapa praktik terbaik:
- Layanan xvfb harus diluncurkan untuk menjalankan Chromium dalam mode non-headless
- Berjalan di Xenial Linux di Travis secara default
- Menjalankan
npm install
secara default node_modules
disimpan di cache secara default
.travis.yml
mungkin terlihat seperti ini:
language: node_js
node_js: node
services: xvfb
script:
- npm run test
Jalankan Puppeteer di CircleCI
- Mulai dengan image NodeJS dalam konfigurasi Anda.
yaml docker: - image: circleci/node:14 # Use your desired version environment: NODE_ENV: development # Only needed if puppeteer is in `devDependencies`
- Dependensi seperti
libXtst6
mungkin perlu diinstal denganapt-get
, jadi gunakan threetreeslight/puppeteer orb (instructions), atau tempelkan bagian sumber ke dalam konfigurasi Anda sendiri. - Terakhir, jika menggunakan Puppeteer melalui Jest, Anda mungkin akan mengalami
error saat memunculkan proses turunan:
shell [00:00.0] jest args: --e2e --spec --max-workers=36 Error: spawn ENOMEM at ChildProcess.spawn (internal/child_process.js:394:11)
Hal ini kemungkinan disebabkan oleh Jest mendeteksi otomatis jumlah proses di seluruh mesin (36
), bukan jumlah yang diizinkan untuk container (2
). Untuk memperbaikinya, tetapkanjest --maxWorkers=2
dalam perintah pengujian Anda.
Jalankan Puppeteer di Docker
Mengaktifkan dan menjalankan Chrome headless di Docker bisa menjadi hal yang sulit. Chromium paket yang diinstal Puppeteer tidak memiliki dependensi library bersama yang diperlukan.
Untuk memperbaikinya, Anda harus menginstal dependensi yang hilang dan paket Chromium terbaru di Dockerfile Anda:
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"]
Buat container:
docker build -t puppeteer-chrome-linux .
Jalankan container dengan meneruskan node -e "<yourscript.js content as a string>"
sebagai perintah:
docker run -i --init --rm --cap-add=SYS_ADMIN \
--name puppeteer-chrome puppeteer-chrome-linux \
node -e "`cat yourscript.js`"
Terdapat contoh lengkap di https://github.com/ebidel/try-puppeteer yang menunjukkan cara menjalankan Dockerfile ini dari server web yang berjalan di App Engine Flex (Node).
Lari di Alpine
Paket Chromium terbaru yang didukung di Alpine adalah 100, yang sesuai dengan Puppeteer v13.5.0.
Contoh 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
...
Praktik terbaik dengan Docker
Secara default, Docker menjalankan container dengan ruang memori bersama /dev/shm
sebesar 64 MB.
Ukuran ini biasanya terlalu kecil
untuk Chrome dan akan menyebabkan Chrome error saat merender halaman yang besar. Untuk memperbaikinya,
jalankan penampung dengan docker run --shm-size=1gb
untuk meningkatkan ukuran
/dev/shm
. Mulai versi Chrome 65, tindakan ini tidak lagi diperlukan. Sebagai gantinya, luncurkan browser dengan flag --disable-dev-shm-usage
:
const browser = await puppeteer.launch({
args: ['--disable-dev-shm-usage'],
});
Tindakan ini menulis file memori bersama ke dalam /tmp
, bukan /dev/shm
. Tinjau
crbug.com/736452.
Apakah Anda melihat kesalahan aneh lainnya saat meluncurkan Chrome? Coba jalankan penampung dengan docker run --cap-add=SYS_ADMIN
saat melakukan pengembangan secara lokal. Karena Dockerfile menambahkan pengguna pptr
sebagai pengguna tanpa hak istimewa, pengguna tersebut mungkin tidak memiliki semua hak istimewa yang diperlukan.
dumb-init ada baiknya untuk dicoba jika Anda
mengalami banyak proses Chrome zombie yang terus berlanjut. Ada perlakuan khusus
untuk proses dengan PID=1
, yang menyulitkan penghentian Chrome
dengan benar dalam beberapa kasus (misalnya pada Docker).
Jalankan Puppeteer di cloud
Di Google App Engine
Runtime Node.js dari lingkungan standar App Engine dilengkapi dengan semua paket sistem yang diperlukan untuk menjalankan Headless Chrome.
Untuk menggunakan puppeteer
, cantumkan modul sebagai dependensi dalam package.json
Anda, lalu deploy ke Google App Engine. Baca lebih lanjut cara menggunakan puppeteer
di App Engine dengan
mengikuti tutorial resmi.
Di Google Cloud Functions
Runtime Node.js 10 dari Google Cloud Functions dilengkapi dengan semua paket sistem yang diperlukan untuk menjalankan Headless Chrome.
Untuk menggunakan puppeteer
, cantumkan modul sebagai dependensi dalam package.json
lalu deploy fungsi Anda ke Google Cloud Functions menggunakan runtime nodejs10
.
Jalankan Puppeteer di Google Cloud Run
Runtime Node.js default Google Cloud Run tidak dilengkapi dengan paket sistem yang diperlukan untuk menjalankan Headless Chrome. Siapkan Dockerfile
Anda sendiri dan
sertakan dependensi yang hilang.
Di Heroku
Menjalankan Puppeteer di Heroku memerlukan beberapa dependensi tambahan yang tidak disertakan di kotak Linux yang disiapkan Heroku untuk Anda. Untuk menambahkan dependensi pada deployment, tambahkan buildpack Puppeteer Heroku ke daftar buildpack untuk aplikasi Anda di bagian Settings > Buildpacks.
URL untuk buildpack adalah https://github.com/jontewks/puppeteer-heroku-buildpack
Pastikan Anda menggunakan mode '--no-sandbox'
saat meluncurkan Puppeteer. Hal ini dapat
dilakukan dengan meneruskannya sebagai argumen ke panggilan .launch()
:
puppeteer.launch({ args: ['--no-sandbox'] });
.
Saat mengklik tambahkan buildpack, tempelkan URL tersebut ke input, lalu klik save. Pada deployment berikutnya, aplikasi Anda juga akan menginstal dependensi yang perlu dijalankan Puppeteer.
Jika Anda perlu merender karakter bahasa China, Jepang, atau Korea, Anda mungkin perlu menggunakan buildpack dengan file font tambahan seperti https://github.com/CoffeeAndCode/puppeteer-heroku-buildpack
Ada juga panduan lain dari @timleland yang berisi contoh project.
Di AWS Lambda
AWS Lambda membatasi ukuran paket deployment menjadi ~50 MB. Hal ini menimbulkan tantangan untuk menjalankan Chrome headless (dan juga Puppeteer) di Lambda. Komunitas ini telah mengumpulkan beberapa referensi yang mengatasi masalah ini:
- Chromium Binary untuk AWS Lambda dan Google Cloud Functions (terus diupdate dengan rilis stabil terbaru Puppeteer)
- Chrome/Chromium di AWS Lambda dari Marco Lüthy adalah plugin serverless dan sudah tidak berlaku.
Instance AWS EC2 yang menjalankan Amazon-Linux
Jika Anda memiliki instance EC2 yang menjalankan amazon-linux di pipeline CI/CD, dan ingin menjalankan pengujian Puppeteer di amazon-linux, ikuti langkah-langkah berikut.
Untuk menginstal Chromium, Anda harus mengaktifkan
amazon-linux-extras
terlebih dahulu, yang merupakan bagian dari EPEL (Paket Tambahan untuk Enterprise Linux):sudo amazon-linux-extras install epel -y
Berikutnya, instal Chromium:
sudo yum install -y chromium
Sekarang Puppeteer dapat meluncurkan Chromium untuk menjalankan pengujian. Jika Anda tidak mengaktifkan EPEL
dan terus menginstal Chromium sebagai bagian dari npm install
, Puppeteer tidak dapat
meluncurkan Chromium karena tidak tersedia libatk-1.0.so.0
dan banyak paket lainnya.
Masalah transpilasi kode
Jika Anda menggunakan transpiler JavaScript seperti babel atau TypeScript, memanggil
evaluate()
dengan fungsi asinkron mungkin tidak berfungsi. Hal ini karena saat
puppeteer
menggunakan Function.prototype.toString()
untuk melakukan serialisasi fungsi,
sementara transpiler dapat mengubah kode output sedemikian rupa sehingga tidak kompatibel
dengan puppeteer
.
Beberapa solusi atas masalah ini adalah memerintahkan transpiler agar tidak mengacaukan
kode, misalnya, mengonfigurasi TypeScript agar menggunakan versi ecma terbaru
("target": "es2018"
). Solusi lainnya dapat menggunakan template string,
bukan fungsi:
await page.evaluate(`(async() => {
console.log('1');
})()`);