Перейти к основному содержимому

JavaScript-рендеринг

JavaScript-рендеринг - это процесс выполнения JavaScript на странице для изменения её структуры или содержимого. Его также называют клиентским рендерингом, в противоположность серверному рендерингу. Некоторые современные сайты используют клиентский рендеринг, некоторые - серверный, а многие передовые веб-сайты комбинируют оба подхода.

Сайт Crawlee не использует JavaScript-рендеринг для отображения контента, поэтому давайте рассмотрим другой пример. Магазин Apify - это библиотека скраперов и автоматизаций, называемых акторами, которые можно использовать бесплатно. Этот сайт использует JavaScript-рендеринг для отображения списка акторов, что делает его отличным примером для демонстрации.

src/main.mjs
import { CheerioCrawler } from 'crawlee';

const crawler = new CheerioCrawler({
async requestHandler({ $, request }) {
// Извлекаем текстовое содержимое карточки актора
const actorText = $('.ActorStoreItem').text();
console.log(`АКТОР: ${actorText}`);
}
})

await crawler.run(['https://apify.com/store']);

При запуске кода вы увидите, что краулер не выведет содержимое карточки актора.

АКТОР:

Это происходит потому, что Магазин Apify использует клиентский JavaScript для рендеринга контента, а CheerioCrawler не может его выполнить, поэтому текст никогда не появляется в HTML страницы.

Вы можете проверить это с помощью Chrome DevTools. Если перейти на https://apify.com/store, кликнуть правой кнопкой мыши и выбрать Просмотр исходного кода страницы, поиск ActorStoreItem не даст результатов. Но если снова кликнуть правой кнопкой, выбрать Инспектировать и искать тот же ActorStoreItem, вы найдете множество совпадений.

Как это возможно? Потому что Просмотр исходного кода показывает оригинальный HTML до выполнения JavaScript - то, что получает CheerioCrawler. А Инспектировать показывает текущий HTML после выполнения JavaScript. Понимая это, неудивительно, что CheerioCrawler не может найти данные. Для этого нам нужен безголовый браузер.

Безголовые браузеры

Чтобы получить содержимое .ActorStoreItem, необходимо использовать безголовый браузер. Можно выбрать одну из двух библиотек для управления браузером: Puppeteer или Playwright. Выбор прост: если вы знаете одну из них - используйте её. Если знаете обе или не знаете ни одной - выбирайте Playwright, так как в большинстве случаев он лучше.

Ожидание рендеринга элементов

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

src/main.mjs
import { PlaywrightCrawler } from 'crawlee';

const crawler = new PlaywrightCrawler({
async requestHandler({ page }) {
// page.locator указывает на элемент в DOM
// используя CSS-селектор, но он не обращается к нему ещё.
const actorCard = page.locator('.ActorStoreItem').first();
// При вызове одного из методов locator Playwright
// ожидает, пока элемент будет отрендерен, и затем обращается к нему.
const actorText = await actorCard.textContent();
console.log(`ACTOR: ${actorText}`);
},
});

await crawler.run(['https://apify.com/store']);

При запуске кода вы увидите неотформатированное содержимое первой карточки актора:

АКТОР: Web Scraperapify/web-scraperСканирует произвольные веб-сайты используя [...]

Мы не шутим

Если вы не верите, что нужно ждать появления элементов, запустите следующий код без ожидания:

src/main.mjs
import { PlaywrightCrawler } from 'crawlee';

const crawler = new PlaywrightCrawler({
async requestHandler({ page }) {
// Сразу извлекаем текст со страницы, не дожидаясь
// появления элемента в DOM
const actorText = await page.$eval('.ActorStoreItem', (el) => {
return el.textContent;
});
console.log(`ACTOR: ${actorText}`);
},
});

await crawler.run(['https://apify.com/store']);

В обоих случаях запрос будет повторен несколько раз и в итоге завершится с ошибкой:

ОШИБКА [...] Error: не удалось найти элемент, соответствующий селектору ".ActorStoreItem"

Это происходит потому, что при попытке доступа к элементу в браузере он еще не отрендерен в DOM.

подсказка

Это руководство лишь затрагивает концепцию JavaScript-рендеринга и использования безголовых браузеров. Чтобы узнать больше, продолжите с курсом по Puppeteer и Playwright в Академии Apify. Он бесплатный и с открытым исходным кодом ❤️.