Как использовать Puppeteer в Yandex Cloud Serverless контейнере
Запустить браузер в Serverless окружении довольно просто. В этой статье я покажу как использовать Puppeteer в Yandex Cloud Serverless контейнере.
Установка Puppeteer
Для начала, создадим Dockerfile:
FROM node:22-slim
# Install dependencies mentioned in https://pptr.dev/troubleshooting#chrome-doesnt-launch-on-linux
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
fonts-ipafont-gothic \
fonts-wqy-zenhei \
fonts-thai-tlwg \
fonts-khmeros \
fonts-kacst \
fonts-freefont-ttf \
dbus \
dbus-x11 \
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
# Copy the package.json and package-lock.json
COPY package.json package-lock.json /app/
WORKDIR /app
# Install the dependencies
RUN npm install
# Copy the source code
COPY . /app
RUN npm run build
CMD ["node", "/app/dist/index.js"]
В этом Dockerfile мы устанавливаем зависимости, необходимые для запуска Chrome в Linux. Это нужно для Puppeteer.
Скрипт
Для того чтобы использовать Puppeteer, создадим скрипт index.ts
:
import express from 'express';
import bodyParser from 'body-parser';
import puppeteer from 'puppeteer';
import fs from 'fs';
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { RequestChecksumCalculation, ResponseChecksumValidation } from '@aws-sdk/middleware-flexible-checksums'
// 🛠 Конфигурация AWS S3
const S3_BUCKET = process.env.S3_BUCKET; // Укажите ваш бакет S3
const REGION = 'ru-central1'; // Укажите ваш регион
const ENDPOINT = 'https://storage.yandexcloud.net';
const s3Client = new S3Client({
region: REGION,
endpoint: ENDPOINT,
requestChecksumCalculation: RequestChecksumCalculation.WHEN_REQUIRED,
responseChecksumValidation: ResponseChecksumValidation.WHEN_REQUIRED
});
// 🏗 Настройка Express сервера
const app = express();
const PORT = process.env.PORT || 8080;
app.use(bodyParser.json());
async function captureAndUpload() {
console.log('📸 Запускаем Puppeteer...');
const browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--no-first-run',
'--no-zygote',
'--disable-gpu',
]
});
const page = await browser.newPage();
const url = 'https://ya.ru';
await page.goto(url, { waitUntil: 'networkidle2' });
const screenshotPath = 'screenshot.png';
await page.screenshot({ path: screenshotPath });
await browser.close();
console.log('📤 Загружаем скриншот в S3...');
const fileBuffer = fs.readFileSync(screenshotPath);
const fileName = `screenshots/${Date.now()}.png`;
const uploadParams = {
Bucket: S3_BUCKET,
Key: fileName,
Body: fileBuffer,
ContentType: 'image/png'
};
try {
const result = await s3Client.send(new PutObjectCommand(uploadParams));
console.log('✅ Скриншот загружен в S3:', result);
return [ENDPOINT, S3_BUCKET, fileName].join('/');
} catch (error) {
console.error('❌ Ошибка загрузки в S3:', error);
throw error;
}
}
const handler: express.Handler = async (req, res) => {
try {
const fileName = await captureAndUpload();
res.status(200).json({ message: 'Success', file: fileName });
} catch (error: any) {
res.status(500).json({ message: 'Error', error: error.toString() });
}
}
app.post('/', handler);
app.get('/', handler);
// 🚀 Запуск сервера
app.listen(PORT, () => {
console.log(`✅ Сервер запущен на порту ${PORT}`);
});
Этот скрипт запускает Puppeteer, делает скриншот страницы https://yandex.cloud
и загружает его в S3.
Отдельно хотел обратить внимание на флаги, которые мы передаем в puppeteer.launch
.
Когда у меня было только два флага --no-sandbox
и --disable-setuid-sandbox
, то я получал ошибку:
Protocol error (Page.navigate): Target closed.
Решение нашел на StackOverflow. Именно там посоветовали добавить остальные флаги.
Дополнительные файлы:
{
"name": "sls-puppeteer",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"scripts": {
"build": "tsc"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.740.0",
"body-parser": "^1.20.3",
"express": "^4.21.2",
"puppeteer": "^24.1.1"
},
"devDependencies": {
"@types/express": "^5.0.0",
"typescript": "^5.5.3"
},
"private": true
}
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"outDir": "dist"
},
"include": ["src"]
}
Запуск
Соберем Docker образ:
docker build --platform linux/amd64 -t cr.yandex/crp***/sls-puppetier:v1 -f ./Dockerfile .
Где cr.yandex/crp***
- это адрес вашего Container Registry.
Загрузим образ в Container Registry:
docker push cr.yandex/crp***/sls-puppetier:v1
Отлично! Теперь можно создать контейнер в Yandex Cloud Serverless и указать образ cr.yandex/crp***/sls-puppetier:v1
.
В качестве переменной окружения S3_BUCKET
укажите ваш бакет S3. А также укажите переменные окружения
AWS_ACCESS_KEY_ID
и AWS_SECRET_ACCESS_KEY
необходимые для доступа к S3.