Puppeteer для JavaScript (Node.js): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

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. Ссылки

  • Официальная документация: <

Рекомендаций