Crawlee는 무엇이며, 언제 사용해야 할까?

최종 업데이트: August 17, 2026
Crawlee는 무엇이며, 언제 사용해야 할까?
AI 요약
Crawlee는 HTTP 파싱과 브라우저 실행을 함께 지원하는 Node.js/TypeScript 웹 스크래핑 라이브러리다. 같은 크롤링 오케스트레이션과 큐 구조를 공유하지만, CheerioCrawler와 PlaywrightCrawler는 추출 방식과 준비 조건이 다르다. 정적 HTML과 JSON 응답에는 HTTP 경로가 잘 맞고, JavaScript 렌더링 페이지에는 브라우저 경로가 필요하다. 다만 Playwright를 쓰려면 Chromium을 별도 설치해야 하며, 프록시·세션·대규모 운영 같은 부분은 추가 검증이 필요하다.

Crawlee(https://github.com/apify/crawlee)가 유용한 이유는 크롤링 오케스트레이션이 HTTP 파싱과 브라우저 실행을 모두 지원하기 때문입니다. 그래서 같은 URL이라도 어떤 크롤러를 쓰느냐, 그리고 어떤 준비 상태 조건을 걸어두느냐에 따라 결과가 달라질 수 있습니다.

공개된 Quotes to Scrape JS 페이지에서 CheerioCrawler는 대상 인용구를 0개 찾았고, PlaywrightCrawler.quote를 기다린 뒤 10개를 찾아냈습니다. 크롤링 생명주기 자체는 비슷해 보였지만, 이건 단순히 클래스 한 줄 바꾸는 수준의 차이가 아니었습니다. Cheerio 핸들러는 $를 사용했고, Playwright 핸들러는 page, 명시적 대기, 그리고 브라우저 측 추출을 사용했습니다.

Crawlee가 실제로 무엇인지

Crawlee(apify/crawlee 프로젝트, 버전 3.17.0)는 Node.js와 TypeScript용 웹 스크래핑 및 브라우저 자동화 라이브러리입니다. Cheerio 또는 JSDOM 기반의 HTTP 크롤링을 지원하고, Playwright 또는 Puppeteer 기반의 브라우저 크롤링도 지원합니다. 이 프로젝트는 Apache-2.0 라이선스를 사용하므로, 배포할 때 notice와 attribution 의무를 확인해야 합니다.

핵심은 “페이지를 가져오는 일”과 “페이지를 읽는 일”을 분리해서 생각하는 것입니다. 한 경로는 원시 HTML을 내려받고 JavaScript를 실행하지 않습니다. 다른 경로는 Chromium을 실행해 페이지 스크립트를 돌릴 수 있지만, 여전히 적절한 준비 상태 조건이 필요하며, 사용자 상호작용이 필요한 콘텐츠, 지연 로딩, shadow DOM, API 실패, 봇 차단 콘텐츠는 놓칠 수 있습니다. Crawlee는 이 두 경로에 맞는 생명주기 개념을 제공하지, 서로 바꿔 쓸 수 있는 DOM 원시 객체를 제공하는 것은 아닙니다.

이 점을 이해하는 게 셀렉터를 하나 쓰기 전에 정말 중요합니다. 이 두 엔진 중 무엇을 고르느냐에 따라, 여러분의 스크래퍼가 데이터를 반환할지 아니면 아무것도 못 가져올지가 갈리기 때문입니다.

핵심 기능: 두 엔진, 하나의 API 표면

Crawlee two engines one API

CheerioCrawler는 HTML을 가져와 Cheerio로 파싱합니다. PlaywrightCrawler는 Chromium을 띄우고 스크린샷도 찍을 수 있습니다. 둘 다 requestHandler를 사용하고, run()을 제공하며, 큐와 링크 탐색 같은 크롤링 개념을 공유합니다. 다만 핸들러 컨텍스트는 다릅니다. 이번 테스트에서 Cheerio 경로는 $로 추출했고, 브라우저 경로는 page, waitForSelector, $$eval을 사용했습니다. 큐와 생명주기 연결부는 익숙하게 유지할 수 있지만, 추출 코드는 어댑터가 필요하거나 아예 다시 작성해야 할 수도 있습니다.

그 아래에서 Crawlee는 실제 크롤링에 필요한 기반 기능을 제공합니다. RequestQueue는 방문할 URL 목록을 관리하고, 중복을 제거하며, 완료 여부를 추적합니다. enqueueLinks는 새 URL을 찾아 큐에 넣어 주며(셀렉터 및 동일 호스트명 필터링 포함), 크롤링이 스스로 확장되도록 돕습니다. Dataset은 추출한 레코드를 저장해 내보내기 쉽게 만들어 줍니다. 기본적으로 Crawlee는 이 모든 것을 디스크의 로컬 storage/ 디렉터리에 저장합니다. 재시작할 때는 편리하지만, 프로젝트 안에 원치 않던 storage/ 폴더가 생겨 있는 걸 처음 보면 조금 거슬릴 수 있습니다(이번 테스트 하니스는 저장소를 임시 디렉터리로 돌리고 persistence를 꺼서 테스트를 깔끔하게 유지했습니다).

각 구성요소만 보면 딱히 특별할 건 없습니다. 중요한 건 이 요소들이 두 엔진 모두에서 공유된다는 점입니다. 즉, HTTP로 크롤링하든 브라우저로 크롤링하든 큐, 링크 탐색, 데이터셋의 동작 방식은 같습니다. 하나의 API만 익혀도 두 가지 수집 전략을 쓸 수 있습니다.

설치: 브라우저는 별도 설치가 필요함

테스트한 설치 환경에서는 패키지 설치 후 Chromium 실행 파일이 포함되어 있지 않았습니다.

Crawlee setup install weight

제 경우 npm install crawlee playwright는 문제 없이 끝났습니다. 85개 패키지, 취약점 0개, 별다른 이슈도 없었습니다. 여기서 멈추고 CheerioCrawler만 실행하면 모든 게 정상적으로 돌아갑니다. HTTP 크롤링은 브라우저가 필요 없기 때문입니다.

이 환경에서는 npx playwright install chromium으로 Chromium을 따로 설치해야 했습니다. 그렇지 않으면 PlaywrightCrawler가 실행에 실패했습니다. 관측된 브라우저 페이로드는 대략 82 MiB였지만, 원본 메모에는 그 수치가 전송 크기인지 디스크 크기인지가 남아 있지 않습니다. 이건 기계별 설정에서 관측한 값이지, 고정된 제품 속성은 아닙니다. 문서 경로나 패키지 동작은 바뀔 수 있으니, 이 글은 그 누락이 항상 그렇다거나 영구적으로 문서화되지 않았다고 말하는 건 아닙니다.

테스트 환경에서는 두 단계로 나눠서 준비하는 게 좋습니다. 먼저 Node 패키지를 설치하고, 그다음 Playwright 경로가 사용할 브라우저를 설치하세요. 실제 배포에 쓸 버전과 플랫폼에 맞춰 최신 Crawlee 및 Playwright 설치 안내도 다시 확인하는 게 좋습니다.

실전 테스트: 같은 페이지, 완전히 다른 결과

Crawlee Cheerio 0 vs Playwright 8/8

핵심 테스트는 동일한 JavaScript 렌더링 fixture를 두 크롤러 모두에 통과시키는 방식이었습니다. URL과 목표 필드는 같았지만, 추출 원시는 달랐습니다.

로컬 fixture에서는 CheerioCrawler가 원시 HTML에 카드가 없었기 때문에 대상 카드 0개를 반환했습니다. PlaywrightCrawler#dynamic-products article.product-card를 기다린 뒤, 예상된 카드 8개 전부를 반환하고 스크린샷도 저장했습니다. 이 결과는 해당 대기 조건 이후 선택한 필드에 대해 fixture 수준의 완전성을 보여줄 뿐이며, 브라우저가 모든 페이지 상태를 볼 수 있다는 뜻은 아닙니다. 원본 파일과 스크린샷은 벤치마크 저장소에 있습니다.

Crawlee public Quotes JS ten

공개 Quotes to Scrape JS 페이지에서는 CheerioCrawler가 대상 인용구를 0개 찾았고, PlaywrightCrawler.quote를 기다린 뒤 10개를 추출했습니다. 이건 공개 대상에서도 HTTP와 브라우저의 경계가 똑같이 적용된다는 걸 보여줍니다. 다만 크롤러 클래스, 핸들러 컨텍스트, 대기 조건, 추출 원시는 양쪽이 서로 다릅니다.

여기서 얻을 수 있는 실질적인 결론은 조금 더 좁습니다. 먼저 HTTP 경로에서 필수 필드가 있는지 확인하고, 원시 응답에 없을 때만 브라우저 크롤러로 올리세요. 브라우저 핸들러 역시 해당 필드와 연결된 조건을 기다려야 합니다.

HTTP 경로는 제어된 정적 카탈로그 및 기사 fixture에서 예상 레코드를 모두 만들었고, 직접 JSON 응답에서는 예상 항목 8개를 모두 디코딩했으며, 11페이지의 bounded graph를 순회했고, 500 응답 하나를 failedRequestHandler로 보냈습니다. 이건 하나의 정확도 점수라기보다 개별 기능 점검에 가깝습니다. 공개 Books to Scrape 페이지에서는 설정한 셀렉터가 20개 상품을 반환해서 스모크 테스트를 통과했습니다.

테스트엔진결과
정적 추출: 카탈로그 + 페이지네이션CheerioCrawler예상 상품 12/12개
기사 추출CheerioCrawler제목 + 문단 3/3개
전송: 직접 JSON 응답CheerioCrawler예상 상품 8/8개
탐색: 내부 링크 그래프CheerioCrawler11페이지, 깊이 {0:1, 1:3, 2:7}
실패 라우팅: HTTP 500CheerioCrawler상태가 실패 핸들러에 도달
렌더링: 로컬 fixtureCheerioCrawler원시 HTML에서 대상 카드 0개
렌더링: 로컬 fixturePlaywrightCrawler대상 셀렉터 대기 후 8/8개
렌더링: Quotes JSCheerioCrawler원시 HTML에서 대상 인용구 0개
렌더링: Quotes JSPlaywrightCrawler대상 셀렉터 대기 후 10개

전체 실행 시간과 테스트별 수치는 results/crawlee-test-summary.json에 있습니다.

이제 솔직한 한계도 짚어야 합니다. 단일 머신에서 단 한 번씩 실행한 결과이므로, 이를 과장하면 안 됩니다. 이건 벤치마크가 아니라 타이밍 기록에 가깝습니다. 즉, 브라우저 경로가 페이지당 더 비싼 건 사실이지만, 그걸 “sub-second Cheerio 실행보다 의미 있게 느리다” 정도로 받아들여야지, 공인 수치처럼 보면 안 됩니다. 그리고 이번 실행에서는 다음 항목들을 테스트하지 않았습니다: 프록시 로테이션, 세션 풀, 수백~수천 페이지 규모의 대규모 실행, RequestQueue persistence 및 크래시 후 재개, Puppeteer 엔진, Dataset/KeyValueStore export 사용성(여기서는 수동으로 내보냈습니다). 두 엔진 스토리와 fixture 수준의 정확도는 확인할 수 있습니다. 하지만 규모와 차단 회피 동작은 보장할 수 없으니, 그렇게 말하지 않겠습니다.

무엇이 공유되고, 무엇을 바꿔야 하는가

Crawlee one-line engine switch

공통 표면은 크롤링 오케스트레이션입니다. 두 크롤러 클래스 모두 requestHandler를 받고 run()을 제공합니다. 큐, 요청 메타데이터, 링크 탐색, 실패 훅, 저장소 개념은 어떤 실행 경로에서도 일관되게 구성할 수 있습니다. 덕분에 어떤 대상만 브라우저가 필요할 때 팀이 다시 배워야 하는 인프라가 줄어듭니다.

하지만 페이지 접근 표면은 공통이 아닙니다. CheerioCrawler 핸들러는 $ 같은 Cheerio 중심 접근을 받으며, 브라우저 없이 응답 본문만으로 작업할 수 있습니다. 테스트한 PlaywrightCrawler 핸들러는 page를 받았고, 셀렉터를 기다린 뒤 브라우저 DOM에서 평가합니다. 두 핸들러가 같은 레코드 스키마를 내보내더라도, 접근 방식은 서로 다릅니다. 재사용 가능한 어댑터가 이 차이의 일부를 감출 수는 있지만, 이번 하니스에서는 그런 어댑터를 구현하거나 보여주지 않았습니다.

이 구분은 비용 계산에서 중요합니다. 크롤러 클래스를 바꾸면 큐, 데이터셋, URL 정책은 유지될 수 있지만, 셀렉터, 준비 상태 체크, 스크린샷, 상호작용 단계, 에러 처리 방식은 여전히 달라질 수 있습니다. 그래서 이 글은 “공유되는 크롤링 기반”은 검증된 장점으로 보고, “한 줄 마이그레이션”은 근거 없는 약속으로 보지 않습니다.

실용적인 엔진 선택 흐름

반환된 HTML이나 직접 JSON 응답에 필요한 필드가 있다면 먼저 HTTP 경로를 사용하세요. 필수 키, 최소 항목 수, 또는 대상 셀렉터처럼 완전성 계약을 먼저 정하고, 충족되지 않으면 명시적으로 실패시키는 게 좋습니다. 빈 배열이 곧 데이터가 없다는 뜻은 아닙니다. 이번 두 JavaScript 사례에서는, 선택한 표현에 대상 요소가 없었다는 의미였습니다.

대상 조건먼저 시작할 것언제 확장할 것
필요한 필드가 반환 HTML에 존재CheerioCrawler필요한 셀렉터나 필드가 없음
재현 가능한 JSON 응답에 데이터가 있음CheerioCrawler요청이 브라우저 전용 상태에 의존
페이지가 실행 후 대상 요소를 삽입PlaywrightCrawler해당 없음; 대상별 준비 상태 체크를 정의
대상 조합을 모름완전성 검증과 함께 HTTP 우선검증 실패 시 typed “representation incomplete” 결과로 처리

실행이 필요할 때는 이 typed failure를 브라우저 핸들러로 올리세요. 이번 하니스에서 로컬 페이지는 #dynamic-products article.product-card를 기다렸고, 공개 quotes 페이지는 .quote를 기다렸습니다. 이런 조건은 추출 계약의 일부입니다. 일반적인 load 이벤트만으로 애플리케이션 데이터가 도착했음을 증명할 수는 없고, 이번 테스트 역시 보편적인 대기 규칙을 지지하지 않습니다.

확장한 뒤에는 DOM 원시 객체가 달라도 출력 스키마는 안정적으로 유지하세요. 어떤 엔진이 결과를 만들었는지, 어떤 준비 상태 조건을 통과했는지, 필수 필드 검증이 성공했는지를 기록해야 합니다. 그래야 HTTP에서 브라우저로의 폴백이 조용히 누락 필드를 허용된 레코드로 바꾸는 일이 아니라, 관측 가능한 동작이 됩니다.

마지막으로 브라우저 설치와 운영 비용은 배포 입력값으로 봐야 합니다. 대략 82 MiB라는 관측값은 로컬 기준의 대략적인 규모를 보여줄 뿐입니다. 여러분의 환경에서 정확한 브라우저 빌드, 플랫폼, 캐시 동작, 이미지 영향 등을 직접 측정하세요. 프록시 로테이션, 세션, persistence, 크래시 복구, 지속적 동시성은 이 fixture만으로는 프로덕션 규모의 선택 기준이 될 수 없으니, 별도 테스트가 필요합니다.

장단점

장점:

  • HTTP와 브라우저 크롤러가 엔진별 추출 컨텍스트를 유지하면서도 생명주기 개념을 공유합니다.
  • 정적 카탈로그, 기사, JSON API에서 HTTP 추출 정확도 100%를 기록했습니다.
  • RequestQueue, 깊이 제어가 포함된 enqueueLinks, Dataset 등 두 엔진 간 공통 기반이 있습니다.
  • 브라우저 경로는 fixture 스크립트를 실행했고, 두 JS 렌더링 테스트에서 모든 대상 항목을 복구했습니다.
  • 깔끔한 실패 처리 — HTTP 500이 크래시 없이 노출됐습니다.
  • Apache-2.0 라이선스로 배포되며, downstream 사용자는 notice와 attribution 의무를 확인해야 합니다.

단점:

  • 테스트 환경에서는 브라우저 엔진에 별도 Chromium 설치가 필요했고, 없으면 PlaywrightCrawler가 실행되지 않았습니다.
  • HTTP 경로는 원시 HTML에 없는 대상 요소를 보여줄 수 없습니다. 완전성 검증이 없으면 그 결과가 유효한 빈 응답처럼 보일 수 있습니다.
  • 브라우저 경로는 추가 브라우저 바이너리와 이 실행에서 더 높은 페이지당 비용을 수반했습니다. 크기와 시간은 빌드와 플랫폼에 따라 달라집니다.
  • 기본 실행은 디스크에 storage/ 디렉터리를 남깁니다.
  • Node/TypeScript 전용입니다. Python 스택이라면 도움이 되지 않습니다.

누구에게 맞고, 누구는 건너뛰어야 하는가

Crawlee는 HTTP와 브라우저 크롤링을 하나의 큐와 생명주기 개념 아래 다루고 싶은 Node 또는 TypeScript 팀에 잘 맞습니다. 실무적으로는 HTTP 크롤러를 먼저 시도하고, 필요한 필드를 검증한 뒤, typed completeness failure를 대상별 준비 상태 조건과 함께 브라우저 핸들러로 넘기는 방식이 좋습니다. 큐와 링크 탐색 기반은 공유되더라도, 핸들러의 DOM 접근 코드는 엔진별로 달라집니다.

반대로 Python 팀이라면 기대를 좀 낮추거나 다른 도구를 보는 편이 낫습니다(Crawlee는 Node/TS이며, 별도의 Python 포트가 있지만 이번 검증은 Node 라이브러리를 대상으로 했습니다). 모든 대상이 정적이라 더 가벼운 단일 목적 HTTP 스크래퍼가 더 좋다면, 또는 이번 실습에서 다루지 않은 프록시 로테이션, 세션 풀, 크래시 후 재개 같은 대규모 검증이 필요하다면 다른 선택이 더 맞을 수 있습니다. 그리고 PlaywrightCrawler를 쓸 거라면, Chromium을 먼저 설치하지 않으면 아예 실행되지 않습니다.

대안과 Thunderbit의 위치

Crawlee는 직접 실행하고 직접 관리하는 오픈소스 소프트웨어입니다. 호출당 벤더 비용은 없지만, 브라우저 컴퓨팅, 대역폭, 프록시, 저장소, 관측성, 엔지니어링은 전부 운영 비용입니다. 크롤러 선택, 브라우저 바이너리, 저장 상태, 준비 상태 로직은 전부 사용자가 책임져야 합니다.

관련 리뷰: scrapy-playwright 리뷰.

관리형 추출 서비스는 데이터 수집과 스키마 정리 책임을 공급자에게 넘깁니다. 저희는 Thunderbit을 만들고 있지만, 이 fixture들에 대해 Thunderbit를 실행하지는 않았습니다. 그래서 이 글은 품질, 지연 시간, 기능 동등성, 비용 비교를 주장하지 않습니다. 핵심 판단 기준은 팀이 Crawlee의 인프로세스 제어를 원하는지, 아니면 호출 단위 서비스 경계를 원하는지입니다.

관련 벤치마크 리뷰: 전체 오픈소스 스크래퍼 비교, 같은 페이지에서의 Playwright vs Puppeteer, 그리고 Scrapy의 브라우저 없는 요청 재생 리뷰.

웹 데이터 추출용 Thunderbit 체험하기

결론

Crawlee는 HTTP와 브라우저 실행 전반에서 공유되는 크롤링 오케스트레이션을 원하는 Node 또는 TypeScript 팀에게 강력한 후보입니다. 테스트한 핸들러들은 서로 대체 가능하지 않았습니다. Playwright로 옮기려면 page, 대상 셀렉터 대기, 브라우저 측 추출이 필요했습니다. 프록시, 세션, persistence, 재개, 대규모 동작은 여전히 미확인 영역입니다.

웹 데이터 추출용 Thunderbit 체험하기 Get Started Free

자주 묻는 질문

Crawlee의 두 크롤러는 실제로 뭐가 다른가요? CheerioCrawler는 HTTP로 HTML을 가져오며 JavaScript를 실행하지 않습니다. PlaywrightCrawler는 Chromium을 구동해 페이지 스크립트를 실행하고 스크린샷도 찍을 수 있지만, 로컬 페이지당 비용은 더 높습니다. 둘은 생명주기 개념은 공유하지만 핸들러 컨텍스트는 같지 않습니다. 이번 하니스에서는 HTTP 경로에서 $를 사용했고, Playwright 경로에서는 page, 대상 셀렉터 대기, 브라우저 측 평가를 사용했습니다.

Crawlee를 설치했는데 왜 PlaywrightCrawler가 실행되지 않나요? 테스트 환경에서는 패키지 설치만으로 브라우저 실행 파일이 제공되지 않았습니다. npx playwright install chromium으로 Chromium을 설치하자 실행 실패가 해결됐습니다. 관측된 페이로드는 대략 82 MiB였지만, 원본 측정값에는 전송 크기인지 디스크 크기인지가 남아 있지 않으니, 여러분의 플랫폼과 빌드에서 다시 측정해 보세요.

CheerioCrawler로 JavaScript 렌더링 페이지를 스크래핑할 수 있나요? 페이지의 JavaScript를 실행할 수는 없습니다. 다만 클라이언트가 사용하는 접근 가능한 JSON 엔드포인트를 요청하는 건 가능합니다. 직접 응답 fixture가 그 예입니다. 필요한 데이터가 브라우저 실행 이후에만 나타난다면, 브라우저 크롤러와 그 필드에 맞는 준비 상태 조건을 사용하세요.

Crawlee는 일반적인 정적 추출에서 정확한가요? 제어된 fixture에서는 12/12개의 예상 카탈로그 상품, 3/3개의 예상 기사 문단, 8/8개의 직접 JSON 항목을 모두 생성했습니다. 이건 fixture 완전성 확인이지, 테스트하지 않은 사이트 전반에 대한 일반 정확도 점수는 아닙니다.

Crawlee는 상업적 사용에 무료인가요? Apache-2.0으로 배포됩니다. 현재 라이선스는 repository에서 확인하고, 배포 시 notice와 attribution 의무를 검토하세요.

프로덕션에 넣기 전에 이 fixture가 남겨 둔 부분은 꼭 테스트하세요. 대표 페이지에서의 반복 동시성, 프록시 및 세션 동작, 인터럽트 후 지속 큐 복구, 브라우저 프로세스 정리, 실패 시 데이터셋 export 등을 확인해야 합니다. 그 결과와 함께 확인된 브라우저 버전과 설치 경로도 보관하세요. 두 크롤러 클래스는 오케스트레이션의 차이를 줄여 주지만, 엔진별 준비 상태 체크, 리소스 예산, 운영 실패 처리까지 없애 주지는 않습니다.

Ke
Ke
Thunderbit CTO | 시니어 데이터 사이언티스트 & ML 전문가 머신러닝과 데이터 과학 분야에서 약 10년에 가까운 경험을 쌓아온 Ke Shen은 컬럼비아 대학교 출신이며, 전 Walmart Labs의 시니어 데이터 사이언티스트였습니다. Python, R, Java, 통계 분야에서 동료들에게도 인정받는 깊은 전문성을 바탕으로, 복잡한 AI 알고리즘을 이론에서 실제 운영 수준의 아키텍처로 전환하는 데 필요한 실전 인사이트를 공유합니다.
목차
Thunderbit · AI 웹 데이터 에이전트

1회 클릭 안에 어떤 페이지든 데이터 추출

250,000명+ 사용자가 신뢰
무료 플랜 제공
웹페이지에서 스프레드시트까지
필요한 내용을 설명하세요 — Thunderbit의 AI Agent가 수집하고 Excel, Google Sheets, Airtable, Notion으로 내보냅니다. 시작은 무료입니다.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week