Puppeteer: когда браузерный automation перестаёт быть болью

#puppeteer#e2e#testing#scraping

Вчера снова пришлось допиливать E2E-тест, который падал из-за timing issue. Знакомый сценарий: page.waitForSelector не срабатывает, скриншоты пустые, а в логах — мутные ошибки про detached DOM. В такие моменты Puppeteer одновременно и спасает, и бесит. Давайте разберёмся, где этот инструмент действительно выручает, а где проще найти альтернативу.

Headless — не значит headache-free

Puppeteer позиционируется как “high-level API to control Chrome/Chromium”, но на практике это скорее набор строительных блоков, чем готовое решение. Вот типичные грабли, на которые наступают новички:

  1. Timing hell. Казалось бы, что может быть проще:
await page.goto('https://example.com');
await page.click('#submit');

Но в реальности между этими строчками нужно вставить waitForNavigation, waitForSelector или waitForFunction, иначе тест упадёт с ошибкой про detached element. Особенно весело, когда страница использует client-side routing.

  1. Селекторная рулетка. page.$('button') часто находит не тот элемент, потому что:

Лайфхак: используем page.waitForSelector с visible: true:

await page.waitForSelector('button:not([disabled])', { visible: true });
  1. Мемори лики. Headless Chrome жрёт память как не в себя. На CI-сервере с ограниченными ресурсами это может привести к OOM-kill. Фиксится ручным вызовом browser.close(), но забыть его — проще простого.

Скрапинг без нервотрёпки

Несмотря на сложности в тестировании, для веб-скрапинга Puppeteer — один из лучших вариантов. Вот почему:

Пример скрипта для сбора данных с lazy-loaded страницы:

const results = [];
let shouldScroll = true;

while (shouldScroll) {
  await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
  await page.waitForTimeout(1000); // Даём время на подгрузку
  
  const newItems = await page.$$eval('.item', nodes => 
    nodes.map(n => n.innerText)
  );
  
  if (newItems.length === 0) shouldScroll = false;
  else results.push(...newItems);
}

Но и здесь есть подводные камни:

Puppeteer vs Playwright: что выбрать в 2024?

Playwright — это форк Puppeteer от Microsoft, который развивается быстрее оригинала. Вот их ключевые отличия:

КритерийPuppeteerPlaywright
БраузерыChrome, FirefoxChrome, FF, WebKit
СкоростьМедленнееБыстрее
APIБазовоеРасширенное
ПоддержкаCommunityMicrosoft

Личный опыт: Playwright лучше подходит для комплексного тестирования, но если вам нужен быстрый скрапинг или PDF-генерация, Puppeteer пока проще в настройке.

Куда двигаться дальше

Если застряли на проблеме с Puppeteer, попробуйте:

  1. Добавить больше waitFor* с кастомными таймаутами
  2. Включить headless: false и посмотреть, что происходит в реальном времени
  3. Использовать page.on('console') для отладки сообщений из браузера

Для серьёзных проектов стоит рассмотреть:

Puppeteer — не silver bullet, но один из немногих инструментов, который позволяет автоматизировать браузер без необходимости писать на C++ или разбираться с DevTools Protocol. Главное — принять его причуды и всегда держать под рукой page.screenshot({ path: 'debug.png' }) для отладки.


Источник: https://github.com/puppeteer/puppeteer