Windows에서 헤드리스 Chrome이 실행되지 않음
일부 Chrome 정책에서는 특정 확장 프로그램을 사용하여 Chrome 또는 Chromium을 실행하도록 강제할 수 있습니다.
Puppeteer는 기본적으로 --disable-extensions
플래그를 전달하므로 이러한 정책이 활성 상태이면 실행되지 않습니다.
이 문제를 해결하려면 플래그 없이 실행해 보세요.
const browser = await puppeteer.launch({
ignoreDefaultArgs: ['--disable-extensions'],
});
맥락: 문제 3681.
헤드리스 Chrome이 Unix에서 실행되지 않음
필요한 모든 종속 항목이 설치되었는지 확인합니다. 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 합성을 사용 중지함
헤드리스 모드에서 GPU 가속을 사용하려면 Chrome 및 Chromium에서 --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에서 샌드박스를 구성하는 방법에는 두 가지가 있습니다.
[권장] 사용자 네임스페이스 클론 사용 설정
Sser 네임스페이스 클론은 최신 커널에서만 지원됩니다. 권한이 없는 사용자 네임스페이스는 일반적으로 사용해도 좋지만, 샌드박스 처리되지 않은 루트가 아닌 프로세스에 커널 공격 영역이 더 많이 노출되어 커널 권한으로 승격될 수 있습니다.
sudo sysctl -w kernel.unprivileged_userns_clone=1
[대안] setuid 샌드박스 설정
setuid sandbox는 독립형 실행 파일로 제공되며 Puppeteer에서 다운로드하는 Chromium 옆에 있습니다. 다음 작업은 호스트 환경당 한 번만 실행할 수 있으므로 Chromium 버전별로 동일한 샌드박스 실행 파일을 재사용해도 됩니다.
# 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)
36
2
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 (노드)에서 실행되는 웹 서버에서 이 Dockerfile을 실행하는 방법을 보여주는 전체 예시는 https://github.com/ebidel/try-puppeteer에 있습니다.
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_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
공유 메모리 공간 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
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 박스에 포함되지 않은 몇 가지 추가 종속 항목이 필요합니다. 배포 시 종속 항목을 추가하려면 Settings(설정) > Buildpacks(빌드팩)에서 앱의 빌드팩 목록에 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의 가이드도 있습니다.
AWS Lambda 기반
AWS Lambda는 배포 패키지 크기를 최대 50MB로 제한합니다. 따라서 Lambda에서 헤드리스 Chrome (따라서 Puppeteer)을 실행하는 데 어려움이 있습니다. 커뮤니티에서 문제를 해결하는 몇 가지 리소스가 준비되어 있습니다.
- AWS Lambda 및 Google Cloud Functions용 Chromium 바이너리(최신 Puppeteer 안정화 버전으로 업데이트됨)
- Marco Lüthy의 AWS Lambda의 Chrome/Chromium은 서버리스 플러그인이며 오래되었습니다.
Amazon-Linux를 실행하는 AWS EC2 인스턴스
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와 같은 자바스크립트 트랜스파일러를 사용하는 경우 비동기 함수로 evaluate()
를 호출하면 작동하지 않을 수 있습니다. 이는 puppeteer
가 Function.prototype.toString()
를 사용하여 함수를 직렬화하는 동안 트랜스파일러가 puppeteer
와 호환되지 않는 방식으로 출력 코드를 변경할 수 있기 때문입니다.
이 문제를 해결하는 방법으로는 트랜스파일러가 코드를 어지럽히지 않도록 지시하는 방법이 있습니다. 예를 들어 최신 ecma 버전("target": "es2018"
)을 사용하도록 TypeScript를 구성합니다. 함수 대신 문자열 템플릿을 사용할 수도 있습니다.
await page.evaluate(`(async() => {
console.log('1');
})()`);