Puppeteer предоставляет богатый функционал для взаимодействия с браузером и элементов на страницах, что делает его отличным инструментом для автоматизированного тестирования. Однако при работе с фреймами на веб-страницах могут возникать сложности, связанные с их асинхронной загрузкой. Стандартные методы ожидания в Puppeteer могут не всегда быть достаточными, так как фреймы загружаются отдельно от основной страницы, что требует применения специальных стратегий.
Фреймы (или iframe) — это элементы HTML, которые встраивают содержимое другой веб-страницы в текущую страницу. Это могут быть сторонние виджеты, рекламные баннеры, формы или другие элементы, загружаемые с внешних ресурсов. Важно понимать, что каждый фрейм в браузере существует в отдельном контексте и может содержать свой набор ресурсов, включая JavaScript, CSS и HTML.
В процессе автоматизированного тестирования фреймы представляют собой отдельную сложность. Для корректной работы с фреймами Puppeteer предоставляет специальные методы, которые позволяют взаимодействовать с ними, а также правильно синхронизировать действия с загрузкой этих фреймов.
При работе с фреймами важно правильно настроить ожидание их загрузки. Для этого можно использовать несколько методов, каждый из которых подходит для определенных ситуаций:
Ожидание загрузки фрейма по его селектору
Один из самых простых способов ожидания загрузки фрейма — это
использование метода waitForSelector. Этот метод позволяет
дождаться появления на странице фрейма с конкретным CSS-селектором.
Однако это будет работать только в том случае, если фрейм доступен на
странице сразу после её загрузки.
await page.waitForSelector(&
const iframe = await page.$('iframe');
Ожидание загрузки фрейма по его состоянию
Если фрейм загружается асинхронно, можно использовать метод
waitForFunction, чтобы дождаться его загрузки. Этот метод
позволяет задать условие, по которому Puppeteer будет ожидать
определённое состояние фрейма, например, загрузку содержимого.
await page.waitForFunction(() => {
const iframe = document.querySelector('iframe');
return iframe && iframe.contentWindow.document.readyState === 'complete';
});
Ожидание фрейма через объект frame
Для работы с фреймами в Puppeteer рекомендуется использовать объект
frame, который предоставляет доступ к контексту каждого
отдельного фрейма. Это позволяет взаимодействовать с содержимым фрейма
так же, как с основной страницей. Чтобы дождаться загрузки фрейма, можно
использовать метод frame.waitForSelector.
const frame = page.frames().find(f => f.url().includes('iframe-source-url'));
await frame.waitForSelector('body');
Ожидание загрузки с помощью события load
Иногда необходимо ожидать загрузку фрейма, основываясь на событии. Для
этого можно повесить обработчик события load на фрейм. Этот
подход полезен, когда нужно гарантировать, что фрейм загружен и готов к
взаимодействию.
const iframe = await page.$('iframe');
await iframe.evaluate((el) => {
return new Promise((resolve) => {
el.onl oad = resolve;
});
});
Когда на странице присутствует несколько фреймов, важно правильно идентифицировать и взаимодействовать с каждым из них. Для этого можно воспользоваться методами, которые позволяют искать фреймы по URL или другим признакам.
Поиск фреймов по URL
Если фрейм имеет уникальный URL, его можно найти с помощью метода
page.frames(), который возвращает все фреймы, загруженные
на странице. Затем можно использовать фильтрацию по URL для нахождения
нужного фрейма.
const iframe = page.frames().find(frame => frame.url().includes('iframe-source-url'));
Поиск фреймов по заголовкам или другим атрибутам
Если URL фрейма неизвестен или меняется, можно искать фреймы по заголовкам или атрибутам. Например, если фрейм имеет уникальный атрибут, можно использовать методы поиска элементов в DOM, чтобы найти его и затем взаимодействовать с содержимым.
const iframe = await page.$('iframe[data-id="unique-identifier"]');
const frame = await iframe.contentFrame();
После того как фрейм загружен и выбран, можно использовать стандартные методы Puppeteer для взаимодействия с его содержимым. Однако важно помнить, что действия, выполняемые в контексте фрейма, не будут влиять на основную страницу и наоборот.
Взаимодействие с элементами внутри фрейма
Чтобы выполнить действия внутри фрейма, нужно сначала получить доступ к
его контексту. Это делается с помощью метода
contentFrame():
const iframe = await page.$('iframe');
const frame = await iframe.contentFrame();
await frame.type('input[name="username"]', 'testuser');
Навигация внутри фрейма
Для перехода по ссылкам или выполнения других действий с элементами
внутри фрейма используется стандартный метод frame.goto():
const iframe = await page.$('iframe');
const frame = await iframe.contentFrame();
await frame.goto('https://example.com');
Если нужно дождаться загрузки всех фреймов на странице, можно использовать комбинацию методов ожидания. Например, можно дождаться, пока на странице не появятся все фреймы, а затем выполнить действия с каждым из них.
await page.waitForSelector('iframe');
const frames = page.frames();
for (const frame of frames) {
await frame.waitForSelector('body');
}
Динамически загружаемые фреймы могут требовать дополнительного внимания. В некоторых случаях фрейм может быть вставлен в DOM страницы после ее начальной загрузки, что делает стандартное ожидание неэффективным. Для таких случаев следует использовать методы, которые позволяют отслеживать изменения в DOM.
await page.waitForFunction(() => {
return document.querySelectorAll('iframe').length > 0;
});
Ожидание загрузки фреймов в Puppeteer требует внимательности и правильного выбора подхода в зависимости от ситуации. Использование специализированных методов для работы с фреймами помогает значительно упростить задачу автоматизации, обеспечивая корректное взаимодействие с элементами, которые загружаются асинхронно или внутри отдельных контекстов.