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

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

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

Начать курс

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

Playwright — это современная библиотека с открытым исходным кодом для автоматизации браузеров, разработанная компанией Microsoft. Она предоставляет единый API для управления Chromium, Firefox и WebKit (движок Safari) через протокол DevTools. В отличие от Selenium, Playwright изначально проектировался для работы с современными веб-приложениями и поддерживает такие сценарии, как перехват сетевых запросов, эмуляция мобильных устройств, работа с несколькими страницами и вкладками, а также автоматическое ожидание элементов.

Основное назначение Playwright — это end-to-end (E2E) тестирование веб-приложений. Однако его возможности выходят далеко за рамки тестирования: библиотека используется для парсинга динамических сайтов (SPA), автоматизации рутинных задач (например, заполнение форм), создания скриншотов и PDF-отчётов, а также для мониторинга производительности веб-страниц. Благодаря поддержке всех трёх основных браузерных движков, вы можете быть уверены, что ваше приложение работает корректно в любом окружении.

Ключевое преимущество Playwright перед конкурентами — это скорость и надёжность. Библиотека использует асинхронную архитектуру на основе промисов, автоматически ожидает появления элементов (нет необходимости писать sleep()), а также умеет работать с iframe, всплывающими окнами и перехватывать консольные сообщения браузера. Playwright также предоставляет встроенный генератор тестов (codegen), который записывает ваши действия в браузере и превращает их в готовый код.

Установка Playwright

Для установки Playwright в проекте на Node.js выполните следующие команды в терминале:

npm init -y
npm install playwright
npx playwright install

Первая команда создаёт файл package.json, вторая — устанавливает саму библиотеку, а третья — загружает браузеры (Chromium, Firefox и WebKit). Если вы хотите установить только один браузер, используйте npx playwright install chromium.

Для TypeScript дополнительно установите типы:

npm install -D @playwright/test

Если вы используете Playwright в качестве тестового фреймворка, рекомендуется установить @playwright/test, который включает в себя тест-раннер, фикстуры и конфигурацию.

Быстрый старт: минимальный рабочий пример

Создайте файл example.js и вставьте следующий код:

const { chromium } = require('playwright');

(async () => {
  // Запускаем браузер (headless: true — без графического интерфейса)
  const browser = await chromium.launch({ headless: true });
  // Создаём новую страницу (вкладку)
  const page = await browser.newPage();
  
  // Переходим на сайт
  await page.goto('https://example.com');
  
  // Получаем заголовок страницы
  const title = await page.title();
  console.log('Заголовок страницы:', title);
  
  // Делаем скриншот
  await page.screenshot({ path: 'example.png' });
  
  // Закрываем браузер
  await browser.close();
})();

Запустите скрипт командой node example.js. В результате вы увидите в консоли заголовок страницы, а в папке появится файл example.png со скриншотом.

Этот пример демонстрирует базовый цикл работы с Playwright: запуск браузера, создание страницы, навигация, взаимодействие с DOM и закрытие.

Основные методы и классы Playwright

Ниже приведены ключевые методы и классы библиотеки. Для каждого указана сигнатура, краткое описание и рабочий пример.

1. browser.newPage()

Сигнатура: async browser.newPage(options?: BrowserContextOptions): Promise<Page>

Описание: Создаёт новую страницу (вкладку) в текущем контексте браузера. Каждая страница изолирована от других — у неё свои cookies, localStorage и сессионные данные.

const { chromium } = require('playwright');
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();

2. page.goto(url, options?)

Сигнатура: async page.goto(url: string, options?: { waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit' }): Promise<Response | null>

Описание: Переходит по указанному URL. Параметр waitUntil определяет, когда считать навигацию завершённой. По умолчанию — 'load' (событие window.load).

await page.goto('https://github.com', { waitUntil: 'networkidle' });

3. page.click(selector, options?)

Сигнатура: async page.click(selector: string, options?: { button?: 'left' | 'right' | 'middle', clickCount?: number, delay?: number }): Promise<void>

Описание: Кликает по элементу, найденному по CSS-селектору. Playwright автоматически ожидает, пока элемент станет видимым и стабильным (не анимированным).

await page.click('button#submit'); // Клик по кнопке с id="submit"
await page.click('a.link', { button: 'right' }); // Правый клик

4. page.fill(selector, value)

Сигнатура: async page.fill(selector: string, value: string): Promise<void>

Описание: Очищает поле ввода (input, textarea) и вводит указанный текст. Это предпочтительный способ ввода текста, так как он эмулирует реальное поведение пользователя.

await page.fill('input[name="email"]', 'user@example.com');
await page.fill('#message', 'Привет, мир!');

5. page.waitForSelector(selector, options?)

Сигнатура: async page.waitForSelector(selector: string, options?: { state?: 'attached' | 'detached' | 'visible' | 'hidden', timeout?: number }): Promise<ElementHandle>

Описание: Ожидает появления элемента в DOM. Параметр state позволяет уточнить условие: 'visible' — элемент видим, 'hidden' — скрыт.

await page.waitForSelector('.loading-spinner', { state: 'hidden' }); // Ждём, пока спиннер исчезнет

6. page.evaluate(pageFunction, arg?)

Сигнатура: async page.evaluate(pageFunction: Function | string, arg?: any): Promise<any>

Описание: Выполняет JavaScript-код в контексте страницы. Позволяет получить доступ к глобальным переменным, изменить DOM или вызвать функции, недоступные через Playwright API.

const result = await page.evaluate(() => {
  return document.title + ' - ' + window.location.href;
});
console.log(result); // Пример: "Example Domain - https://example.com"

7. page.screenshot(options?)

Сигнатура: async page.screenshot(options?: { path?: string, fullPage?: boolean, clip?: { x: number, y: number, width: number, height: number } }): Promise<Buffer>

Описание: Делает скриншот текущей страницы. Если fullPage: true, захватывается вся страница, включая прокручиваемые области.

await page.screenshot({ path: 'fullpage.png', fullPage: true });
// Скриншот только определённой области
await page.screenshot({ path: 'clip.png', clip: { x: 100, y: 100, width: 300, height: 200 } });

8. page.setViewportSize(viewportSize)

Сигнатура: async page.setViewportSize(viewportSize: { width: number, height: number }): Promise<void>

Описание: Изменяет размер окна просмотра (viewport). Полезно для тестирования адаптивного дизайна или эмуляции мобильных устройств.

await page.setViewportSize({ width: 375, height: 812 }); // iPhone X

9. page.waitForNavigation(options?)

Сигнатура: async page.waitForNavigation(options?: { url?: string | RegExp, waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' }): Promise<Response | null>

Описание: Ожидает завершения навигации. Часто используется после клика по ссылке или отправки формы, когда нужно дождаться загрузки новой страницы.

await page.click('a.next-page');
await page.waitForNavigation(); // Ждём, пока загрузится следующая страница

10. browser.newContext(options?)

Сигнатура: async browser.newContext(options?: BrowserContextOptions): Promise<BrowserContext>

Описание: Создаёт новый изолированный контекст браузера. Контексты позволяют симулировать несколько независимых сессий (разные пользователи, cookies, localStorage) в одном браузере.

const context = await browser.newContext({
  viewport: { width: 1920, height: 1080 },
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
});
const page = await context.newPage();

Реальный практический пример: парсинг интернет-магазина

Рассмотрим сценарий: нам нужно собрать информацию о товарах со страницы каталога интернет-магазина (название, цена, ссылка). Сайт использует динамическую подгрузку (JavaScript). Playwright отлично справляется с такими задачами.

const { chromium } = require('playwright');

async function parseCatalog(url) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({
    viewport: { width: 1280, height: 720 },
    locale: 'ru-RU'
  });
  const page = await context.newPage();

  try {
    // Переходим на страницу каталога
    await page.goto(url, { waitUntil: 'networkidle', timeout: 30000 });
    
    // Ждём появления карточек товаров
    await page.waitForSelector('.product-card', { timeout: 10000 });
    
    // Прокручиваем страницу вниз, чтобы подгрузить все товары (если есть lazy load)
    await page.evaluate(async () => {
      await new Promise((resolve) => {
        let totalHeight = 0;
        const distance = 300;
        const timer = setInterval(() => {
          window.scrollBy(0, distance);
          totalHeight += distance;
          if (totalHeight >= document.body.scrollHeight) {
            clearInterval(timer);
            resolve();
          }
        }, 200);
      });
    });
    
    // Извлекаем данные
    const products = await page.evaluate(() => {
      const items = [];
      const cards = document.querySelectorAll('.product-card');
      
      cards.forEach(card => {
        const title = card.querySelector('.product-title')?.innerText.trim();
        const price = card.querySelector('.product-price')?.innerText.trim();
        const link = card.querySelector('a')?.href;
        
        if (title && price) {
          items.push({ title, price, link });
        }
      });
      
      return items;
    });
    
    console.log(`Найдено товаров: ${products.length}`);
    console.log('Первый товар:', products[0]);
    
    // Сохраняем в JSON
    const fs = require('fs');
    fs.writeFileSync('products.json', JSON.stringify(products, null, 2));
    
    return products;
  } catch (error) {
    console.error('Ошибка при парсинге:', error.message);
    await page.screenshot({ path: 'error.png' });
    throw error;
  } finally {
    await browser.close();
  }
}

// Запуск
parseCatalog('https://example-shop.com/catalog')
  .then(data => console.log('Готово!'))
  .catch(err => console.error('Фатальная ошибка:', err));

В этом примере мы:

  • Создаём изолированный контекст с настройками viewport и локали
  • Ожидаем полной загрузки страницы (networkidle)
  • Прокручиваем страницу для подгрузки контента
  • Извлекаем данные через page.evaluate()
  • Сохраняем результат в JSON
  • Обрабатываем ошибки и делаем скриншот при сбое

Советы по производительности и типичные ошибки

Советы по производительности

  1. Используйте контексты вместо новых браузеров. Создание нового контекста (browser.newContext()) значительно быстрее, чем запуск нового экземпляра браузера. Для параллельных тестов используйте один браузер и несколько контекстов.
  2. Отключайте ненужные функции. Если вам не нужны скриншоты или видео, отключите их в конфигурации. Также можно отключить загрузку изображений и CSS для ускорения:
const context = await browser.newContext({
  viewport: { width: 1280, height: 720 },
  userAgent                    

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