Puppeteer для JavaScript (Node.js): полное руководство с примерами
1. Что это и зачем нужна
Puppeteer — это библиотека для Node.js, предоставляющая высокоуровневый API для управления браузером Chrome (или Chromium) через протокол DevTools Protocol. По умолчанию Puppeteer работает в headless-режиме (без графического интерфейса), что делает её идеальным инструментом для автоматизации веб-задач на серверной стороне. Однако при необходимости можно запустить и полноценный браузер с интерфейсом для отладки.
Основные сценарии использования Puppeteer включают: веб-скрапинг (извлечение данных с динамических сайтов, использующих JavaScript), автоматизированное тестирование веб-приложений (e2e-тесты), генерацию скриншотов и PDF страниц, эмуляцию действий пользователя (клики, заполнение форм, навигация), а также мониторинг производительности веб-страниц. В отличие от простых HTTP-запросов, Puppeteer выполняет JavaScript на странице, что позволяет получать контент, сгенерированный динамически.
Библиотека активно поддерживается командой Google и используется в продакшене тысячами компаний. Puppeteer предоставляет полный контроль над браузером: от управления вкладками и перехвата сетевых запросов до эмуляции мобильных устройств и геолокации. Это универсальный инструмент, который заменяет собой целый набор утилит для работы с веб-содержимым.
2. Установка
Для установки Puppeteer через npm (Node Package Manager) выполните команду в терминале в корне вашего проекта:
npm install puppeteer
Эта команда загрузит саму библиотеку и автоматически скачает совместимую версию Chromium (около 300-400 МБ). Если вы хотите использовать уже установленный Chrome/Chromium в системе, установите puppeteer-core:
npm install puppeteer-core
При использовании puppeteer-core вам нужно будет указать путь к исполняемому файлу браузера при запуске. Для работы с библиотекой требуется Node.js версии 18.0.0 или выше (рекомендуется LTS-версия).
3. Быстрый старт — минимальный рабочий пример
Создайте файл example.js и добавьте следующий код, который делает скриншот веб-страницы:
const puppeteer = require('puppeteer');
(async () => {
// Запускаем браузер
const browser = await puppeteer.launch();
// Открываем новую страницу
const page = await browser.newPage();
// Переходим на сайт
await page.goto('https://example.com');
// Делаем скриншот
await page.screenshot({ path: 'example.png' });
// Закрываем браузер
await browser.close();
})();
Запустите скрипт командой node example.js. В папке появится файл example.png со скриншотом страницы example.com. Это минимальный, но полностью рабочий пример автоматизации браузера.
4. Основные методы/функции/классы
Ниже приведены 8 ключевых методов и классов Puppeteer с описанием и примерами кода.
4.1. puppeteer.launch()
Сигнатура: puppeteer.launch([options]) → Promise<Browser>
Что делает: Запускает экземпляр браузера Chromium/Chrome. Принимает объект опций (headless, slowMo, args и др.). Возвращает объект Browser.
const browser = await puppeteer.launch({
headless: false, // Показать браузер
slowMo: 100, // Замедление действий (мс)
args: ['--window-size=1920,1080']
});
4.2. browser.newPage()
Сигнатура: browser.newPage() → Promise<Page>
Что делает: Создает новую вкладку (страницу) в браузере. Каждая страница — изолированная среда для работы с одним документом.
const page = await browser.newPage();
await page.goto('https://example.com');
4.3. page.goto()
Сигнатура: page.goto(url[, options]) → Promise<HTTPResponse|null>
Что делает: Переходит по указанному URL. Опции включают waitUntil (когда считать навигацию завершенной: 'load', 'domcontentloaded', 'networkidle0', 'networkidle2').
await page.goto('https://example.com', {
waitUntil: 'networkidle0' // Ждем, пока сеть не будет бездействовать 500 мс
});
4.4. page.waitForSelector()
Сигнатура: page.waitForSelector(selector[, options]) → Promise<ElementHandle>
Что делает: Ожидает появления элемента, соответствующего CSS-селектору. Полезно для ожидания динамического контента.
await page.waitForSelector('.content-loaded', { timeout: 5000 });
const text = await page.$eval('.content-loaded', el => el.textContent);
console.log(text);
4.5. page.click()
Сигнатура: page.click(selector[, options]) → Promise<void>
Что делает: Эмулирует клик мыши по элементу, найденному по селектору. Автоматически ожидает появления элемента.
await page.click('#submit-button'); // Клик по кнопке с id="submit-button"
4.6. page.type()
Сигнатура: page.type(selector, text[, options]) → Promise<void>
Что делает: Вводит указанный текст в поле ввода, найденное по селектору. Эмулирует реальный ввод с клавиатуры.
await page.type('#search-input', 'Puppeteer guide');
await page.keyboard.press('Enter'); // Нажать Enter
4.7. page.evaluate()
Сигнатура: page.evaluate(pageFunction[, ...args]) → Promise<Serializable>
Что делает: Выполняет JavaScript-функцию в контексте страницы (браузера). Позволяет взаимодействовать с DOM и получать данные.
const title = await page.evaluate(() => {
return document.title;
});
console.log('Заголовок страницы:', title);
4.8. page.screenshot()
Сигнатура: page.screenshot([options]) → Promise<Buffer|String>
Что делает: Делает скриншот страницы (или её части). Опции: path, fullPage (полная страница), type (png/jpeg), clip (область).
await page.screenshot({
path: 'fullpage.png',
fullPage: true // Скриншот всей страницы, включая прокрутку
});
5. Реальный практический пример (100-200 строк кода)
В этом примере мы создадим скрипт для автоматизации поиска на сайте Wikipedia и извлечения первого абзаца статьи. Скрипт демонстрирует работу с формами, ожиданием элементов и извлечением данных.
const puppeteer = require('puppeteer');
async function searchWikipedia(query) {
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
try {
const page = await browser.newPage();
// Устанавливаем таймаут для всех операций
page.setDefaultTimeout(30000);
// Переходим на Wikipedia
await page.goto('https://en.wikipedia.org', {
waitUntil: 'networkidle2'
});
// Находим поле поиска и вводим запрос
await page.waitForSelector('#searchInput');
await page.type('#searchInput', query, { delay: 50 }); // Задержка для имитации ввода
// Нажимаем кнопку поиска
await page.click('button[type="submit"]');
// Ждем загрузки результатов
await page.waitForSelector('#mw-content-text', { timeout: 10000 });
// Извлекаем первый абзац статьи
const firstParagraph = await page.evaluate(() => {
const content = document.querySelector('#mw-content-text');
if (!content) return 'Контент не найден';
// Ищем первый абзац с текстом (не пустой)
const paragraphs = content.querySelectorAll('p');
for (let p of paragraphs) {
const text = p.textContent.trim();
if (text.length > 50) {
return text;
}
}
return 'Абзац не найден';
});
// Получаем заголовок страницы
const title = await page.evaluate(() => document.title);
console.log(`Результаты поиска для "${query}":`);
console.log(`Заголовок: ${title}`);
console.log(`Первый абзац: ${firstParagraph.substring(0, 200)}...`);
// Делаем скриншот для отладки
await page.screenshot({
path: `wikipedia_${query.replace(/\s+/g, '_')}.png`,
fullPage: false
});
return { title, firstParagraph };
} catch (error) {
console.error('Ошибка при выполнении скрипта:', error.message);
throw error;
} finally {
await browser.close();
}
}
// Запуск примера
(async () => {
try {
const result = await searchWikipedia('Puppeteer');
console.log('Готово!');
} catch (e) {
console.error('Критическая ошибка:', e);
}
})();
Этот скрипт можно легко адаптировать для парсинга других сайтов: достаточно изменить URL, селекторы и логику извлечения данных.
6. Советы по производительности и типичные ошибки
Советы по производительности:
- Используйте
puppeteer.launch({ headless: true })— headless-режим работает быстрее, так как не требует отрисовки графики. - Отключайте ненужные функции:
args: ['--disable-gpu', '--disable-dev-shm-usage']для серверных окружений. - Переиспользуйте браузер и страницы: запускайте браузер один раз и создавайте новые страницы для каждой задачи, вместо повторного
launch(). - Используйте
page.setRequestInterception()для блокировки ненужных ресурсов (картинки, шрифты, аналитика) — это может ускорить загрузку в 2-3 раза. - Устанавливайте разумные таймауты:
page.setDefaultTimeout(15000)— 15 секунд обычно достаточно. - Избегайте
waitForTimeout(): вместо фиксированных задержек используйтеwaitForSelector()илиwaitForFunction().
Типичные ошибки и их решение:
- Ошибка: "Failed to launch the browser process" — обычно из-за отсутствия зависимостей в Linux. Установите:
sudo apt-get install -y libx11-xcb1 libxcomposite1 libxcursor1 libxdamage1 libxi6 libxtst6 libnss3 libcups2 libxss1 libxrandr2 libasound2 libatk1.0-0 libatk-bridge2.0-0 libgtk-3-0. - Ошибка: "TimeoutError: waiting for selector" — селектор не найден. Проверьте правильность селектора, используйте
page.waitForSelector()с увеличенным таймаутом или проверьте, не блокирует ли что-то загрузку. - Ошибка: "Node is either not visible or not an HTMLElement" — элемент есть в DOM, но не видим. Используйте
page.evaluate()для скролла к элементу:element.scrollIntoView(). - Проблема: утечка памяти — всегда закрывайте страницы и браузер в блоке
finallyили используйтеtry...finally. - Проблема: блокировка сайтом — некоторые сайты блокируют headless-браузеры. Используйте
puppeteer-extra-plugin-stealthдля обхода.
7. Ссылки
- Официальная документация: <
Также в библиотеке
Интернационализация (i18n) в Rust: лучшие библиотеки и практики
ORM для Java: сравнение Hibernate, MyBatis и JPA с примерами
Конфигурация приложений Swift: библиотека SwiftyConfiguration
Elasticsearch клиент для Java: полное руководство по работе с Java Client