본문으로 건너뛰기

Playwright 크롤러

이 예제는 PlaywrightCrawlerRequestQueue를 함께 사용하여 헤드리스 Chrome/Playwright로 해커 뉴스 웹사이트를 재귀적으로 스크래핑하는 방법을 보여줍니다.

크롤러는 단일 URL에서 시작하여 다음 페이지의 링크를 찾고, 이를 대기열에 추가한 다음 원하는 링크가 더 이상 없을 때까지 계속 진행합니다. 결과는 기본 데이터셋에 저장됩니다. 로컬 환경에서는 결과가 ./storage/datasets/default 경로의 JSON 파일로 저장됩니다.

Apify 플랫폼에서 이 예제를 실행하려면 Dockerfile에서 apify/actor-node-playwright-chrome 이미지를 선택하세요.

Run on
import { PlaywrightCrawler } from 'crawlee';

// PlaywrightCrawler 클래스의 인스턴스를 생성합니다.
// 헤드리스 Chrome/Playwright에서 URL을 자동으로 로드합니다.
const crawler = new PlaywrightCrawler({
launchContext: {
// playwright .launch() 함수에 전달되는 옵션을 설정할 수 있습니다.
launchOptions: {
headless: true,
},
},

// 크롤링할 페이지 수 제한
maxRequestsPerCrawl: 50,

// 각 URL을 크롤링할 때마다 이 함수가 호출됩니다.
// Playwright 스크립트를 작성할 수 있으며,
// 브라우저와 페이지는 Crawlee가 자동으로 관리합니다.
// 이 함수는 여러 속성을 포함하는 객체를 매개변수로 받습니다.
// 주요 속성:
// - request: URL 및 HTTP 메서드와 같은 정보가 포함된 Request 클래스의 인스턴스
// - page: Playwright의 Page 객체 (참조: 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 }[] = [];

// Hacker News의 각 게시물의 제목, 순위, URL을 가져옵니다.
$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}이(가) 마지막 페이지입니다!`);
},

// 페이지 처리가 maxRequestRetries+1회 이상 실패한 경우 이 함수가 호출됩니다.
failedRequestHandler({ request, log }) {
log.info(`${request.url} 요청이 너무 많이 실패했습니다.`);
},
});

await crawler.addRequests(['https://news.ycombinator.com/']);

// 크롤러를 실행하고 완료될 때까지 대기합니다.
await crawler.run();

console.log('크롤러가 완료되었습니다.');