Puppeteer — это библиотека для автоматизации браузера Google Chrome или
Chromium, основанная на протоколе DevTools. Один из важнейших аспектов
работы с Puppeteer — это эффективная работа с асинхронными операциями,
так как взаимодействие с браузером часто включает задержки, такие как
загрузка страниц, рендеринг элементов или выполнение JavaScript на
странице. Для правильного выполнения таких задач необходима глубокая
работа с асинхронными функциями JavaScript, такими как
async/await и промисы.
Асинхронность в Puppeteer реализуется через промисы. Промисы позволяют работать с результатами асинхронных операций в JavaScript, таких как запросы к серверу, выполнение действий на странице, взаимодействие с элементами DOM и многое другое.
Каждая основная операция в Puppeteer, такая как
page.goto(), page.waitForSelector() или
page.evaluate(), возвращает промис. Для управления этим
процессом используется async/await, что позволяет писать
асинхронный код в более читаемом и удобном формате.
async/await с Puppeteer:
const puppeteer = require(&
async function run() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log(title);
await browser.close();
}
run();
В этом примере используется ключевое слово await для того,
чтобы дождаться завершения асинхронной операции, например, открытия
страницы или получения её заголовка. Это позволяет работать с
результатами этих операций, как с синхронным кодом.
Одним из наиболее распространённых случаев асинхронных операций является
ожидание загрузки определённых элементов на странице. Puppeteer
предоставляет несколько методов для ожидания:
waitForSelector, waitForXPath,
waitForFunction, которые позволяют задать условия, при
которых выполнение скрипта продолжится только после появления
определённых элементов на странице.
const element = await page.waitForSelector('.some-element');
await element.click();
Метод waitForSelector ожидает появления элемента с
указанным селектором на странице и возвращает объект, который можно
использовать для дальнейших действий (например, для клика по элементу).
Promise.all() для параллельного выполнения
В некоторых случаях необходимо выполнить несколько асинхронных операций
параллельно, чтобы ускорить процесс выполнения теста. Например, можно
открыть несколько страниц или выполнить несколько запросов в браузере
одновременно. В таких случаях удобно использовать
Promise.all(), который позволяет запустить несколько
промисов параллельно и дождаться их выполнения.
const [page1, page2] = await Promise.all([
browser.newPage(),
browser.newPage()
]);
await page1.goto('https://example.com');
await page2.goto('https://example.org');
В этом примере создаются две страницы одновременно, что позволяет значительно ускорить выполнение тестов, особенно если загрузка разных страниц не зависит друг от друга.
Поскольку асинхронные операции могут завершаться с ошибками (например,
элемент не найден или страница не загрузилась), важно правильно
обрабатывать ошибки с помощью try/catch. Это позволяет
обеспечить более надёжную работу тестов и избежать неожиданных сбоев.
try {
await page.goto('https://example.com');
await page.waitForSelector('.non-existent-element');
} catch (error) {
console.error('Ошибка при выполнении операции:', error);
}
Здесь в случае ошибки выполнение кода не будет прервано, а ошибка будет обработана и выведена в консоль, что позволяет продолжить выполнение тестов или корректно завершить их с учётом возникших проблем.
Для тестирования веб-приложений может быть важно дождаться завершения
сетевых запросов. Puppeteer предоставляет метод
page.waitForResponse(), который позволяет ожидать
завершения определённого HTTP-запроса.
await page.goto('https://example.com');
const response = await page.waitForResponse(response =>
response.url().includes('/api/data') && response.status() === 200
);
console.log('Ответ на запрос:', response.status());
Метод waitForResponse позволяет отслеживать запросы,
отправленные на сервер, и дожидаться получения ответа от сервера, что
полезно, например, для тестирования взаимодействий с API или ожидания
завершения загрузки данных.
page.evaluate()
Для выполнения JavaScript-кода на странице можно использовать метод
page.evaluate(), который позволяет запускать функции в
контексте страницы, что полезно для работы с DOM или выполнения
специфических скриптов.
const result = await page.evaluate(() => {
return document.querySelector('.example').innerText;
});
console.log(result);
Метод evaluate принимает функцию, которая выполняется
внутри браузера, и возвращает результат, который можно использовать в
тестах. Это позволяет работать с DOM-элементами страницы, получать их
значения и выполнять другие манипуляции.
timeout в методах waitForSelector или
goto.
await page.goto('https://example.com', { timeout: 5000 });
Асинхронные очереди: В некоторых случаях может потребоваться выполнение большого числа асинхронных операций с учётом их порядка. Для этого можно использовать очередь промисов, которая помогает контролировать параллельность.
Дебаггинг: Для отслеживания выполнения асинхронного
кода можно использовать опцию headless: false при запуске
браузера. Это позволяет видеть, как выполняются действия на странице,
что полезно при поиске ошибок или улучшении производительности тестов.
const browser = await puppeteer.launch({ headless: false });
Работа с асинхронным кодом в Puppeteer является основным элементом для эффективного тестирования и автоматизации браузера. Понимание работы с промисами, асинхронными функциями и обработкой ошибок позволяет создавать стабильные и производительные тесты, а использование возможностей для параллельного выполнения и ожидания сетевых запросов значительно ускоряет процесс.