Прямая работа с CDP

Puppeteer предоставляет высокоуровневый API для управления браузером Chromium, однако полная мощь инструмента раскрывается при прямом взаимодействии с Chrome DevTools Protocol (CDP). CDP — это низкоуровневый протокол, позволяющий отправлять команды и получать события от браузера, контролируя все аспекты его работы: сетевые запросы, DOM, производительность, инспекцию страниц и многое другое.

Подключение к CDP

Для работы с CDP в Puppeteer используется метод page.target().createCDPSession(). Он создаёт сессию для текущей страницы, через которую можно напрямую посылать команды протокола:

const puppeteer = require(&

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  const client = await page.target().createCDPSession();
  
  await client.send('Network.enable');
  await client.send('Page.enable');
})();

Важно: CDP-сессия привязана к конкретной вкладке или целевому объекту (Target). Для управления всем браузером создаётся сессия через browser._connection.

Управление сетью

CDP предоставляет детальный контроль над сетевыми запросами. С помощью команд Network можно перехватывать, блокировать или модифицировать запросы:

await client.send('Network.setRequestInterception', {
  patterns: [{ urlPattern: '*', resourceType: 'Document', interceptionStage: 'HeadersReceived' }]
});

client.on('Network.requestIntercepted', async (event) => {
  const { interceptionId } = event;
  await client.send('Network.continueInterceptedRequest', { interceptionId });
});

Ключевые моменты:

  • setRequestInterception позволяет указать паттерны URL, тип ресурса и стадию перехвата.
  • continueInterceptedRequest разрешает или модифицирует запрос, включая изменение заголовков и тела.

Манипуляция DOM через CDP

CDP даёт прямой доступ к DOM и JavaScript-окружению страницы. Команды DOM и Runtime позволяют получать дерево элементов, изменять их или выполнять код:

const { root: { nodeId } } = await client.send('DOM.getDocument');
const { nodeId: buttonId } = await client.send('DOM.querySelector', { nodeId, selector: 'button#submit' });

await client.send('DOM.setAttributeValue', {
  nodeId: buttonId,
  name: 'disabled',
  value: 'true'
});

Для выполнения JavaScript на странице применяется Runtime.evaluate:

const result = await client.send('Runtime.evaluate', {
  expression: 'document.title'
});
console.log(result.result.value);

Особенности:

  • DOM работает с nodeId, который уникален для каждой сессии.
  • Изменения через CDP мгновенно отражаются в браузере, минуя Puppeteer API.

Работа с событиями

CDP активно использует событийную модель. Каждая команда может генерировать события, на которые можно подписаться через client.on:

client.on('Network.responseReceived', (event) => {
  console.log(`Ответ от ${event.response.url}: ${event.response.status}`);
});

client.on('Page.loadEventFired', () => {
  console.log('Страница полностью загружена');
});

Советы:

  • Подписка на события позволяет реализовать сложные сценарии тестирования без ожиданий (waitForTimeout).
  • События могут использоваться для логирования, анализа производительности и отслеживания AJAX-запросов.

Снимки производительности и профилирование

CDP открывает доступ к Performance и Profiler. Например, можно измерить время загрузки страницы, CPU-профилирование и использование памяти:

await client.send('Performance.enable');
const metrics = await client.send('Performance.getMetrics');
console.log(metrics.metrics);

Для CPU-профилирования используется Profiler.start и Profiler.stop:

await client.send('Profiler.start');
await page.evaluate(() => {
  for (let i = 0; i < 1e6; i++) Math.sqrt(i);
});
const profile = await client.send('Profiler.stop');
console.log(profile);

Ограничения и особенности

  • CDP работает только с Chromium-подобными браузерами.
  • Низкоуровневые команды могут конфликтовать с Puppeteer API, поэтому рекомендуется использовать их аккуратно.
  • Некоторые команды могут быть экспериментальными и изменяться в новых версиях Chromium.

Примеры применения

  1. Перехват сетевых ошибок: позволяет тестировать обработку неуспешных запросов.
  2. Масштабная модификация DOM: удобна для тестов, где Puppeteer API не предоставляет прямого метода.
  3. Профилирование производительности: измерение времени рендеринга, FPS и использования памяти.
  4. Отладка сложных сценариев: подписка на события и контроль над всеми аспектами страницы.

Прямая работа с CDP расширяет возможности Puppeteer, открывая доступ к низкоуровневым функциям браузера, которые недоступны через стандартные методы. Такой подход позволяет создавать точные, гибкие и производительные тесты, контролируя каждый аспект взаимодействия с веб-страницей.