Кастомные селекторы

Puppeteer — это библиотека для Node.js, предназначенная для автоматизации браузера через API Chrome или Chromium. Она предоставляет мощные средства для манипуляций с DOM, тестирования и веб-скрапинга. Важной частью работы с Puppeteer является выбор элементов на странице. Стандартные селекторы, такие как page.$(selector)</code>, дают возможность находить элементы по CSS-селекторам, однако для сложных страниц или специфических задач часто требуется создание кастомных селекторов.</p> <h3 id="зачем-нужны-кастомные-селекторы">Зачем нужны кастомные селекторы</h3> <p>Стандартные CSS-селекторы часто не могут покрыть все сценарии, встречающиеся при тестировании динамичных веб-страниц. Это может быть связано с:</p> <ul> <li><strong>Динамическими изменениями страницы</strong>: элементы, которые могут быть перерисованы или изменены на лету.</li> <li><strong>Уникальными атрибутами</strong>: например, отсутствие уникальных id или классов.</li> <li><strong>Необходимостью работы с состоянием элементов</strong>: например, нужно выбрать элемент только тогда, когда он доступен для взаимодействия.</li> </ul> <p>Для таких случаев могут быть полезны кастомные селекторы, которые могут учитывать дополнительные параметры, такие как состояние элемента, его видимость, расположение или конкретное поведение на странице.</p> <h3 id="создание-кастомных-селекторов-с-помощью-функции-page.eval">Создание кастомных селекторов с помощью функции <code>page.$eval

Одним из способов создания кастомного селектора в Puppeteer является использование метода page.$eval</code>. Этот метод позволяет выполнить произвольный JavaScript-код в контексте страницы, что дает возможность динамически вычислять или изменять селектор в зависимости от состояния страницы.</p> <pre class="javascript"><code>const element = await page.$eval(& // Логика для поиска нужного элемента return el.querySelector('.my-class'); });

В этом примере используется стандартный CSS-селектор для поиска первого элемента div. Однако, внутри функции обработчика, можно добавить любую логику, например, вычисление или выбор более специфического элемента.

Пример кастомного селектора для динамических данных

На сложных веб-страницах элементы могут изменяться в зависимости от состояния интерфейса. Примером такого элемента является список, который подгружается асинхронно. В этом случае нужно создать кастомный селектор, который будет ожидать появления нужного элемента в DOM.

const customSelector = async (page, className) => {
  const selector = `.${className}`;
  await page.waitForSelector(selector, { visible: true });
  return await page.$(selector);
};

Этот кастомный селектор использует waitForSelector, чтобы дождаться появления элемента с заданным классом. Таким образом, если элемент появляется динамически, Puppeteer подождет его загрузки, прежде чем продолжить выполнение.

Обработка состояния элементов с кастомными селекторами

Многие элементы на странице могут быть скрытыми, отключенными или находиться в состоянии загрузки. Использование кастомных селекторов дает возможность проверять эти состояния до выполнения действий с элементами.

Для этого можно использовать методы isIntersectingViewport и isVisible. Они позволяют оценивать, виден ли элемент на экране и готов ли он к взаимодействию.

const customSelector = async (page, className) => {
  const element = await page.$(`.${className}`);
  const isVisible = await page.evaluate((el) => {
    const rect = el.getBoundingClientRect();
    return rect.top >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight);
  }, element);

  if (!isVisible) {
    throw new Error(`Element .${className} is not visible.`);
  }

  return element;
};

В этом примере кастомный селектор проверяет, виден ли элемент на экране. Если элемент не видим, он выбрасывает ошибку.

Использование XPath для кастомных селекторов

В Puppeteer можно использовать не только CSS-селекторы, но и XPath, что значительно расширяет возможности поиска элементов, особенно когда требуется точность или выборка элементов с конкретными аттрибутами.

const customXPathSelector = async (page, xpathExpression) => {
  const [element] = await page.$x(xpathExpression);
  if (element) {
    return element;
  } else {
    throw new Error(`Element matching ${xpathExpression} not found`);
  }
};

В этом примере функция использует метод page.$x</code>, который позволяет искать элементы с помощью XPath. Это может быть полезно, если структура страницы сложная и требует более точного выбора элементов по тексту, аттрибутам или относительному расположению.</p> <h3 id="оптимизация-кастомных-селекторов">Оптимизация кастомных селекторов</h3> <p>Для повышения эффективности кастомных селекторов стоит учитывать несколько рекомендаций:</p> <ol type="1"> <li><p><strong>Использование <code>waitForSelector</code> с таймаутами</strong>: Это помогает избежать ситуаций, когда скрипт не может найти элемент из-за его задержки в рендеринге.</p> <pre class="javascript"><code>await page.waitForSelector(&#39;.my-element&#39;, { timeout: 5000 });</code></pre></li> <li><p><strong>Параллельные запросы</strong>: Когда необходимо искать несколько элементов, можно использовать параллельное выполнение запросов для ускорения работы.</p> <pre class="javascript"><code>const elements = await Promise.all([ page.$('.first-class'), page.$(&#39;.second-class&#39;) ]);</code></pre></li> <li><p><strong>Минимизация количества вызовов к странице</strong>: Чем меньше раз вы обращаетесь к странице для поиска элементов, тем быстрее будет работать тест. Поэтому лучше собрать все нужные элементы за один запрос и затем работать с ними.</p></li> <li><p><strong>Использование прямых ссылок</strong>: Вместо того чтобы каждый раз искать элемент через стандартный CSS-селектор, можно использовать ссылки на элементы, если они известны.</p></li> </ol> <h3 id="примеры-сложных-кастомных-селекторов">Примеры сложных кастомных селекторов</h3> <p>Иногда требуется делать сложные выборки на основе нескольких условий, таких как родительский элемент, тип контента или конкретные атрибуты. В таких случаях можно комбинировать различные подходы для создания эффективных кастомных селекторов.</p> <p>Пример:</p> <pre class="javascript"><code>const complexSelector = async (page) =&gt; { const element = await page.$eval('.parent-element', (parent) => { return parent.querySelector('.child-element[data-status="active"]'); });

if (!element) { throw new Error('Active child element not found'); }

return element; };

В этом примере используется комбинация стандартного CSS-селектора и логики на стороне клиента, чтобы найти элемент с заданными аттрибутами в родительском контейнере.

Заключение

Создание кастомных селекторов в Puppeteer позволяет значительно повысить гибкость и точность автоматизированных тестов. Они могут быть полезны для работы с динамическими элементами, сложными структурами DOM и улучшением производительности при тестировании веб-страниц. Комбинируя стандартные методы с пользовательскими решениями, можно добиться высокой надежности и скорости выполнения тестов.