스토어 크롤링하기
예제 창고 스토어의 모든 데이터를 크롤링하려면, 먼저 모든 제품이 있는 페이지를 방문해야 합니다. 즉, 사용 가능한 모든 카테고리와 제품 상세 페이지를 살펴봐야 합니다.
목록 페이지 크롤링하기
이전 강의에서는 enqueueLinks()
함수를 다음과 같이 사용했습니다:
await enqueueLinks();
이 방식이 당시에는 유용했지만, 이제는 다른 방법이 필요합니다. 같은 호스트네임을 가진 모든 <a href="..">
요소의 링크를 찾는 대신, 크롤러가 다음 결과 페이지로 이동하게 해주는 특정 링크만 찾아야 합니다. 그렇지 않으면 크롤러가 관심 없는 많은 다른 페이지를 방문하게 됩니다. DevTools의 도움과 enqueueLinks()
의 또 다른 매개변수를 사용하면 이는 꽤 쉽게 해결됩니다.
import { PlaywrightCrawler } from 'crawlee';
const crawler = new PlaywrightCrawler({
requestHandler: async ({ page, request, enqueueLinks }) => {
console.log(`처리 중: ${request.url}`);
// 이 로직은 메인 카테고리 목록에서만 실행하고,
// 하위 페이지에서는 실행하지 않습니다.
if (request.label !== 'CATEGORY') {
// 카테고리 카드가 렌더링될 때까지 기다립니다.
// 그렇지 않으면 enqueueLinks가 아무것도 인큐하지 않습니다.
await page.waitForSelector('.collection-block-item');
// 제공된 선택자와 일치하는 요소에서만
// 링크를 큐에 추가합니다.
await enqueueLinks({
selector: '.collection-block-item',
label: 'CATEGORY',
});
}
},
});
await crawler.run(['https://warehouse-theme-metal.myshopify.com/collections']);
이 코드는 꽤 익숙해 보일 것입니다. 현재 처리 중인 URL을 콘솔에 로그로 출력하고 더 많은 링크를 인큐하는 매우 간단한 requestHandler
입니다. 하지만 몇 가지 새롭고 흥미로운 추가 사항이 있습니다. 하나씩 살펴보겠습니다.
enqueueLinks()
의 selector
매개변수
이전에 enqueueLinks()
를 사용할 때는 selector
매개변수를 제공하지 않았고, 기본값인 a
(모든 <a>
요소를 찾음)를 사용했기 때문에 문제가 없었습니다. 하지만 이제는 더 구체적이어야 합니다. 카테고리
페이지에는 여러 <a>
링크가 있고, 크롤러가 사용 가능한 결과 목록으로 이동하게 해주는 링크만 필요합니다. DevTools를 사용하면 .collection-block-item
선택자로 필요한 링크를 선택할 수 있다는 것을 알 수 있습니다. 이 선택자는 class=collection-block-item
속성이 있는 모든 요소를 선택합니다.
enqueueLinks()
의 label
Crawlee에서는 label
을 자주 볼 수 있습니다. 이는 나중에 빠르게 식별할 수 있도록 Request
인스턴스에 라벨을 붙이는 편리한 방법입니다. request.label
로 접근할 수 있으며 string
타입입니다. 원하는 대로 요청의 이름을 지정할 수 있습니다. 여기서는 제품 카테고리를 나타내는 페이지를 인큐하고 있다는 것을 표시하기 위해 CATEGORY
라벨을 사용했습니다. enqueueLinks()
함수는 RequestQueue
에 인큐하기 전에 이 라벨을 모든 요청에 추가합니다. 이것이 왜 유용한지는 곧 알게 될 것입니다.
상세 페이지 크롤링하기
비슷한 방식으로, 필요한 모든 데이터를 스크래핑할 수 있는 제품 상세 페이지의 모든 URL도 수집해야 합니다. 다음 코드는 이미 알고 있는 개념을 다른 링크 세트에 적용한 것입니다.
import { PlaywrightCrawler } from 'crawlee';
const crawler = new PlaywrightCrawler({
requestHandler: async ({ page, request, enqueueLinks }) => {
console.log(`처리 중: ${request.url}`);
if (request.label === 'DETAIL') {
// 아직 상세 정보는 처리하지 않습니다.
} else if (request.label === 'CATEGORY') {
// 이제 카테고리 페이지에 있습니다. 이를 통해 페이지네이션을 하면서
// 모든 제품과 발견하는 후속 페이지를 인큐할 수 있습니다.
await page.waitForSelector('.product-item > a');
await enqueueLinks({
selector: '.product-item > a',
label: 'DETAIL', // <= 다른 라벨에 주목하세요
});
// 이제 "다음" 버튼을 찾아서 다음 결과 페이지를 인큐해야 합니다(있는 경우)
const nextButton = await page.$('a.pagination__next');
if (nextButton) {
await enqueueLinks({
selector: 'a.pagination__next',
label: 'CATEGORY', // <= 같은 라벨에 주목하세요
});
}
} else {
// 이는 라벨이 없는 시작 페이지라는 의미입니다.
// 이 페이지에서는 모든 카테고리 페이지만 인큐하면 됩니다.
await page.waitForSelector('.collection-block-item');
await enqueueLinks({
selector: '.collection-block-item',
label: 'CATEGORY',
});
}
},
});
await crawler.run(['https://warehouse-theme-metal.myshopify.com/collections']);
이제 크롤링 코드가 완성되었습니다. 코드를 실행하면 크롤러가 모든 목록 URL과 모든 상세 URL을 방문하는 것을 볼 수 있습니다.
다음 단계
이것으로 크롤링 강의를 마칩니다. 크롤러가 필요한 모든 페이지를 방문하도록 가르쳤기 때문입니다. 이제 데이터 스크래핑을 계속해보겠습니다.