Краулер Playwright
В этом примере показано, как использовать PlaywrightCrawler
вместе с RequestQueue
для рекурсивного сканирования сайта Hacker News с помощью безголового Chrome и Playwright.
Краулер начинает с одного URL-адреса, находит ссылки на следующие страницы, ставит их в очередь и продолжает работу, пока не закончатся нужные ссылки. Результаты сохраняются в датасет по умолчанию. При локальной конфигурации результаты сохраняются в виде JSON-файлов в директории ./storage/datasets/default
.
подсказка
Чтобы запустить этот пример на платформе Apify, выберите образ apify/actor-node-playwright-chrome
для вашего Dockerfile.
Run on
import { PlaywrightCrawler } from 'crawlee';
// Создаем экземпляр класса PlaywrightCrawler - краулера,
// который автоматически загружает URL-адреса в безголовом Chrome / Playwright.
const crawler = new PlaywrightCrawler({
launchContext: {
// Здесь вы можете установить опции, которые передаются функции .launch() браузера Playwright.
launchOptions: {
headless: true,
},
},
// Останавливаем краулинг после нескольких страниц
maxRequestsPerCrawl: 50,
// Эта функция будет вызываться для каждого URL для краулинга.
// Здесь вы можете написать скрипты Playwright, с которыми вы знакомы,
// за исключением того, что браузеры и страницы автоматически управляются Crawlee.
// Функция принимает один параметр, который является объектом с множеством свойств,
// наиболее важными из которых являются:
// - request: экземпляр класса Request с информацией, такой как URL и HTTP-метод
// - page: объект Page Playwright (см. https://playwright.dev/docs/api/class-page)
async requestHandler({ pushData, request, page, enqueueLinks, log }) {
log.info(`Processing ${request.url}...`);
// Функция, которая будет вычислена в контексте браузерного контекста Playwright.
const data = await page.$$eval('.athing', ($posts) => {
const scrapedData: { title: string; rank: string; href: string }[] = [];
// Мы получаем заголовок, ранг и URL каждого поста на Hacker News.
$posts.forEach(($post) => {
scrapedData.push({
title: $post.querySelector('.title a').innerText,
rank: $post.querySelector('.rank').innerText,
href: $post.querySelector('.title a').href,
});
});
return scrapedData;
});
// Сохраняем результаты в датасет по умолчанию.
await pushData(data);
// Находим ссылку на следующую страницу и ставим ее в очередь, если она существует.
const infos = await enqueueLinks({
selector: '.morelink',
});
if (infos.processedRequests.length === 0) log.info(`${request.url} is the last page!`);
},
// Эта функция вызывается, если обработка страницы завершилась неудачно более maxRequestRetries+1 раз.
failedRequestHandler({ request, log }) {
log.info(`Запрос ${request.url} не выполнен слишком много раз.`);
},
});
await crawler.addRequests(['https://news.ycombinator.com/']);
// Запускаем краулер и ждем, пока он закончит работу.
await crawler.run();
console.log('Краулер закончил работу.');