본문으로 건너뛰기

요청 저장소

Crawlee는 특정 작업에 유용한 여러 요청 저장소 유형을 제공합니다. 요청들은 CRAWLEE_STORAGE_DIR 환경 변수로 정의된 로컬 디렉토리에 저장됩니다. 이 변수가 정의되지 않은 경우, Crawlee는 기본적으로 현재 작업 디렉토리의 ./storageCRAWLEE_STORAGE_DIR로 설정합니다.

요청 큐

요청 큐는 크롤링할 URL들을 저장하는 공간입니다. 이 큐는 몇 개의 URL로 시작하여 다른 페이지의 링크를 재귀적으로 따라가는 웹사이트의 심층 크롤링에 사용됩니다. 이 데이터 구조는 너비 우선 및 깊이 우선 크롤링 순서를 모두 지원합니다.

각 Crawlee 프로젝트 실행은 기본 요청 큐와 연결됩니다. 일반적으로 특정 크롤러 실행에서 크롤링할 URL을 저장하는 데 사용되며, 선택적으로 사용할 수 있습니다.

Crawlee에서 요청 큐는 RequestQueue 클래스로 표현됩니다.

요청 큐는 MemoryStorage 클래스에 의해 관리되며, 데이터는 메모리에 저장되면서 동시에 CRAWLEE_STORAGE_DIR 환경 변수로 지정된 로컬 디렉토리에 다음과 같이 저장됩니다:

{CRAWLEE_STORAGE_DIR}/request_queues/{QUEUE_ID}/entries.json
노트

{QUEUE_ID}는 요청 큐의 이름 또는 ID입니다. CRAWLEE_DEFAULT_REQUEST_QUEUE_ID 환경 변수로 재정의하지 않는 한, 기본 큐의 ID는 default입니다.

노트

entries.json은 요청들의 배열을 포함합니다.

다음 코드는 요청 큐의 사용법을 보여줍니다:

import { CheerioCrawler } from 'crawlee';

// 크롤러는 큐에서 요청을 자동으로 처리합니다.
// Puppeteer/Playwright 크롤러에 대해 동일한 방식으로 사용됩니다.
const crawler = new CheerioCrawler({
// 여기서는 요청 큐를 지정하지 않습니다
async requestHandler({ $, crawler, enqueueLinks }) {
// 새 요청을 큐에 추가
await crawler.addRequests([{ url: 'https://example.com/new-page' }]);
// 페이지에서 찾은 링크를 큐에 추가
await enqueueLinks();
},
});

// 초기 요청 추가
// 여기서는 요청 큐를 명시적으로 열지 않습니다
await crawler.addRequests([
{ url: 'https://example.com/1' },
{ url: 'https://example.com/2' },
{ url: 'https://example.com/3' },
// ...
]);

// 크롤러 실행
await crawler.run();

크롤러에서 요청 큐를 사용하는 더 자세한 예제는 Puppeteer 크롤러 예제를 참조하세요.

요청 리스트

요청 리스트는 엄밀히 말해 저장소가 아닙니다 - 크롤러 실행 메모리에 저장된 크롤링할 URL 목록을 나타냅니다(선택적으로 실행과 연결된 기본 키-값 저장소에 저장할 수 있습니다). 이 리스트는 크롤러가 방문해야 할 모든 URL을 미리 알고 있고 실행 중에 URL이 추가되지 않을 때 많은 수의 URL을 크롤링하는 데 사용됩니다. URL은 코드에서 직접 제공하거나 웹에 호스팅된 텍스트 파일에서 파싱할 수 있습니다.

요청 리스트는 코드에서 명시적으로 지정한 경우에만 크롤러 실행을 위해 생성됩니다. 사용은 선택사항입니다.

Crawlee에서 요청 리스트는 RequestList 클래스로 표현됩니다.

다음 코드는 요청 리스트의 기본 작업을 보여줍니다:

import { RequestList, PuppeteerCrawler } from 'crawlee';

// 방문할 URL이 있는 sources 배열 준비
const sources = [
{ url: 'http://www.example.com/page-1' },
{ url: 'http://www.example.com/page-2' },
{ url: 'http://www.example.com/page-3' },
];

// 요청 리스트 열기
// 리스트 이름은 소스와 리스트 상태를 키-값 저장소에 유지하는 데 사용됩니다
const requestList = await RequestList.open('my-list', sources);

// 크롤러는 자동으로 리스트의 요청을 처리합니다
// Cheerio/Playwright 크롤러에서도 동일한 방식으로 사용됩니다
const crawler = new PuppeteerCrawler({
requestList,
async requestHandler({ page, request }) {
// 페이지 처리 (데이터 추출, 스크린샷 촬영 등)
// 여기서는 요청 리스트에 더 이상 요청을 추가할 수 없습니다
},
});

어떤 것을 선택해야 할까요?

요청 큐를 사용할 때는 일반적으로 몇 개의 시작 URL(예: 이커머스 웹사이트의 카테고리 페이지)이 있고 프로그래밍 방식으로 더 많은 URL(예: 개별 상품 페이지)을 재귀적으로 큐에 추가합니다. 요청의 동적 추가와 제거를 지원합니다. 요청 리스트는 초기화 후에는 변경할 수 없어서 URL을 추가하거나 제거할 수 없습니다.

반면에 요청 큐는 많은 수의 URL을 일괄적으로 추가하거나 제거하는 데 최적화되어 있지 않습니다. 기술적으로는 가능하지만, 요청이 큐에 하나씩 추가되므로 많은 수의 요청이 있을 경우 상당한 시간이 걸립니다. 하지만 요청 리스트는 수백만 개의 URL도 포함할 수 있으며, 큐에 비해 추가하는 데 걸리는 시간이 훨씬 적습니다.

요청 큐와 요청 리스트는 동일한 크롤러에서 함께 사용할 수 있습니다. 이 경우 요청 리스트의 각 요청은 먼저 요청 큐의 맨 앞에 추가된 후(요청 큐가 비어있지 않더라도) 큐에서 처리됩니다. 이는 동일한 URL이 두 번 처리되는 것을 방지하기 위해 필요합니다(리스트에서 한 번, 큐에서 한 번). 실제로 이러한 조합은 초기 URL이 많고 크롤러가 동적으로 더 많은 URL을 추가할 때 유용할 수 있습니다.

Crawlee에서는 요청 큐와 요청 리스트를 함께 사용할 필요성이 크게 줄었습니다(기술적으로는 가능하지만).

이전에는 초기 요청을 일괄적으로 큐에 추가할 방법이 없었습니다(요청 배열을 추가하는 것). 즉, addRequest() 함수를 사용하여 요청을 하나씩만 큐에 추가할 수 있었습니다.

하지만 이제는 요청을 일괄적으로 추가하는 addRequests() 함수를 사용할 수 있습니다. 따라서 요청 큐와 요청 리스트를 조합하는 대신, 이러한 사용 사례에는 요청 큐만 사용할 수 있습니다. 아래 예제를 참조하세요.

// 이 방법을 권장합니다.
// 요청 목록을 사용하지 않으며, 여기서는 요청 큐를 명시적으로 사용하지 않습니다.

import { PuppeteerCrawler } from 'crawlee';

// 방문할 URL을 포함하는 소스 배열 준비 (수백만 개의 URL을 포함할 수 있음)
const sources = [
{ url: 'http://www.example.com/page-1' },
{ url: 'http://www.example.com/page-2' },
{ url: 'http://www.example.com/page-3' },
// ...
];

// 크롤러는 큐에서 요청을 자동으로 처리합니다.
// Cheerio/Playwright 크롤러에 대해 동일한 방식으로 사용됩니다
const crawler = new PuppeteerCrawler({
async requestHandler({ crawler, enqueueLinks }) {
// 새 요청을 큐에 추가
await crawler.addRequests(['http://www.example.com/new-page']);

// 페이지에서 찾은 링크를 큐에 추가
await enqueueLinks();

// 위의 요청은 큐에 추가되지만 목록에는 추가되지 않습니다
// 목록이 비어있으면 요청이 처리됩니다
// 여기서는 목록에 더 이상 요청을 추가할 수 없습니다
},
});

// 초기 소스 배열을 큐에 추가하고 크롤러 실행
await crawler.run(sources);

저장소 정리하기

달리 지정하지 않는 한 기본 저장소는 크롤러가 시작되기 전에 정리됩니다. 이는 저장소를 열 때(RequestQueue.open()을 통해) 또는 기본 저장소를 헬퍼 메서드 중 하나를 통해 사용하려고 할 때(내부적으로 RequestQueue.open()을 호출하는 crawler.addRequests() 등) 발생합니다. 코드에서 저장소를 명시적으로 사용하지 않는 경우, 정리는 결국 크롤러의 run 메서드가 실행될 때 발생합니다. 저장소를 더 일찍 정리해야 하는 경우 purgeDefaultStorages() 헬퍼를 명시적으로 사용할 수 있습니다:

import { purgeDefaultStorages } from 'crawlee';

await purgeDefaultStorages();

이 함수를 호출하면 기본 요청 저장소 디렉토리(그리고 기본 키-값 저장소에 저장된 요청 리스트도)가 정리됩니다. 이는 StorageClient 인터페이스의 (선택적) purge 메서드를 실행하는 단축키입니다. 다시 말해, 현재 사용 중인 기본 저장소 구현의 purge 메서드를 호출합니다. options 객체에서 onlyPurgeOncetrue로 설정하면 주어진 실행 컨텍스트에서 저장소가 한 번만 정리되도록 할 수 있습니다.