Crawl4AI(https://github.com/unclecode/crawl4ai) 주변에는 묘하게도 한 가지 이야기가 계속 따라다닙니다. 사이트의 HTML 구조가 바뀌어도 데이터를 다시 찾아내는, 스스로 복구하는 똑똑한 도구라는 소문이죠. 하지만 사실은 그렇지 않습니다. 그런 역할은 오히려 다른 도구인 Scrapling에 더 가깝습니다. Crawl4AI는 훨씬 더 분명하고, 그래서 더 이해하기 쉬운 도구입니다. 즉, 셀레니움이 아니라 브라우저를 기반으로 돌면서 Markdown으로 바꿔주는 변환기이고, 옆에 CSS/XPath 추출기를 붙여둔 형태입니다.
이번 리뷰를 위해 정적 페이지, JavaScript로 렌더링되는 카탈로그, 일부러 깨뜨린 500 페이지, 그리고 작은 딥 크롤까지 실제로 돌려봤습니다. 핵심 기능 자체는 꽤 훌륭했습니다. 다만 설치 무게, 딥 크롤 동작 방식, 그리고 헷갈리게 만드는 오류 메시지 같은 부분은 사람들이 잘 이야기하지 않죠. 이번 글은 그 지점들을 짚습니다. 아래 내용은 제가 직접 실행한 테스트를 바탕으로 한 잠정적인 평가이며, 최종 벤치마크는 아닙니다. 제가 확인하지 않은 부분은 따로 표시해 두었으니, 제가 손대지 않은 것까지 인용하는 일은 없었으면 합니다.
Crawl4AI는 정확히 무엇이고, 무엇이 아닌가
포지셔닝 문구를 걷어내고 보면, Crawl4AI는 사실 세 가지가 겹쳐진 도구입니다.
첫째, 실제 브라우저입니다. 내부적으로 Playwright와 Patchright라는 스텔스 패치 버전을 사용해 Chrome이 하듯 페이지를 불러옵니다. JavaScript를 실행하고, DOM을 만들고, 필요하면 콘텐츠가 로드될 때까지 기다립니다. 이게 핵심입니다. 원시 HTML만 내려받는 HTTP 클라이언트가 아닙니다. 실제 렌더링 엔진을 띄우는 구조입니다.
둘째, Markdown 생성기입니다. 페이지가 렌더링되면 Crawl4AI는 DOM을 Markdown으로 바꿉니다. LLM과 RAG 파이프라인이 바로 쓰기 좋은 형식이죠. 유지보수팀이 이 프로젝트를 LLM 친화적 크롤러라고 부르는 이유도 바로 여기에 있습니다. URL을 넣으면 모델이 이해할 수 있는 텍스트가 돌아옵니다.
셋째, 구조화 추출기입니다. 서술형 텍스트 대신 깔끔한 JSON이 필요하다면, JsonCssExtractionStrategy를 통해 필드명에 CSS 또는 XPath 셀렉터를 매핑한 스키마를 넘기면 됩니다. 그러면 레코드를 돌려줍니다. LLM 기반 추출 경로도 있지만, 이건 API 키가 필요하고 제가 테스트하지 않았기 때문에 동작을 아는 척하진 않겠습니다.
여기서 중요한 포인트가 있고, 바로 “adaptive intelligence”라는 소문이 틀린 이유이기도 합니다. 이 스키마는 정적이고, 사용자가 직접 작성해야 합니다. 예를 들어 제품명이 .product-card h3에 있고 가격이 .price에 있다고 Crawl4AI에 알려주면, 사이트가 내일 그 클래스 이름을 바꾸는 순간 셀렉터는 깨지고 그대로 망가집니다. 자동 복구는 없습니다. fuzzy 매칭도 없습니다. 그냥 브라우저와 변환기, 그리고 사용자가 관리하는 셀렉터일 뿐입니다. 이걸 처음부터 알고 있으면, 다른 저장소에 있는 기능을 기대하며 실망하는 일을 피할 수 있습니다.
실제로 다루게 되는 기본 요소도 이름이 꽤 직관적입니다. AsyncWebCrawler가 엔진이고, BrowserConfig가 브라우저 설정, CrawlerRunConfig가 단일 실행을 제어합니다. 여기에는 나중에 다시 언급할 wait_for도 포함됩니다. 비동기 우선 Python API라서, 이름만 익숙해지면 구조는 깔끔하게 읽힙니다.
참고로 이 저장소는 2026-07-07 기준 71,259 stars, 7,326 forks, Apache-2.0 라이선스이며(unclecode/crawl4ai), 릴리스는 v0.9.0입니다. 별점 수는 계속 변하니 실시간 수치라기보다 스냅샷으로 보는 게 맞습니다. 그래도 이 수치는 이 프로젝트가 주말용 실험이 아니라, 실제로 많이 쓰이고 자유롭게 활용 가능한 프로젝트라는 걸 보여줍니다.
설치: 두 개의 브라우저 스택이 디스크에 내려앉는 순간
Crawl4AI의 설치 단계에서부터 이 도구는 가벼운 라이브러리처럼 움직이지 않습니다. 그리고 이 부분은 거의 모든 리뷰에서 빠져 있습니다.
pip 설치 자체는 문제없었습니다. pip install -U crawl4ai는 깔끔하게 끝났고, 특히 주목할 점은 제가 Python 3.14.2 환경에서 설치했다는 것입니다. 공식 문서는 >=3.10을 요구하지만, 제 머신에는 3.10~3.13 런타임이 따로 없었습니다. 최신 인터프리터 사용자에게는 꽤 좋은 신호입니다.
그다음 crawl4ai-setup을 실행하면, 그때부터 디스크 사용량이 확 늘어납니다.

설정 단계는 브라우저 하나만 받는 게 아닙니다. Playwright와 Patchright, 두 개의 완전한 브라우저 스택을 모두 내려받습니다. 여기에 Chrome for Testing, FFmpeg, Headless Shell까지 추가로 끌고 옵니다. 이게 진짜 브라우저 기반 도구의 비용입니다. 브라우저는 어딘가에 설치돼 있어야 하고, 여기서는 그것들이 내 기기 안에 두 벌씩 깔립니다. SSD 용량이 빠듯한 노트북이거나, 용량 한 푼이 아까운 슬림 컨테이너 이미지를 만들고 있다면 이 점을 반드시 고려해야 합니다. 순수 HTTP 파서와는 비교가 안 되는 발자국입니다.
다행히 도구 자체는 상태를 꽤 정직하게 보여줍니다. crawl4ai-doctor를 실행하니 정상 통과했고, https://crawl4ai.com을 14.65초 만에 크롤링해 브라우저 경로가 끝까지 제대로 작동한다는 걸 증명했습니다. 실제 라이브 페이지를 렌더링해서 확인하는 내장 진단 명령은 꽤 좋은 구성입니다. 즉, “설치가 잘 됐나?”에 대해 어깨만 으쓱하는 대신 명확한 답을 줍니다.
설치에 대한 결론은 이렇게 나뉩니다. Python 쪽은 매끄럽고 관대합니다. 반면 브라우저 쪽은 묵직합니다. 둘 다 사실이며, 도입 전에 이 둘을 함께 알아야 합니다.
실전 테스트: 무엇이 버텼고, 숫자는 어땠는가
정적 상품, JS 렌더링 상품, 일부러 잡음을 섞은 기사, 고장난 500 페이지, 작은 링크 그래프가 있는 로컬 테스트 사이트를 만들고, 여기에 공개 데모 사이트 두 곳을 더해 Crawl4AI를 돌렸습니다. 결과는 다음과 같습니다.

정적 페이지: 완승. 공식 quickstart를 example.com에 돌리면 1.81초 만에 Markdown이 나왔습니다. 제 로컬 정적 카탈로그에서는 Markdown이 기대한 제품명 6/6을 모두 보존했고, CSS 스키마 추출은 이름, 카테고리, 가격, 평점, 상세 URL까지 포함한 6개 레코드를 JSON으로 가져왔습니다. 전혀 문제 없었습니다.
동적 페이지: 올바르게 요청하면 역시 완승. 여기서 중요한 전제 조건이 있습니다. 제 JS 렌더링 카탈로그에서는 실행 설정에 wait_for="css:.product-card"를 넣자 Markdown과 스키마 추출 모두에서 제품 8/8을 정확히 회수했습니다. 공개 quotes.toscrape.com/js 페이지에서도 JavaScript로 주입된 인용문을 렌더링했고, 내용이 실제로 그려졌다는 증거로 쓸 수 있는 스크린샷도 저장했습니다. 여기서 말하는 “dynamic”은 그냥 마케팅 용어가 아닙니다. 브라우저가 진짜 렌더링합니다. 다만 무엇을 기다릴지 알려줘야 합니다. wait_for를 빼면 반쯤 만들어진 페이지를 긁게 됩니다.

배치 처리: 안정적입니다. 로컬 제품 URL 여섯 개에 대해 arun_many()를 돌렸을 때, 한 번의 동시 실행으로 6/6 모두 200 응답으로 돌아왔습니다. 샘플 수는 작지만, 동시 처리 경로는 설명대로 작동했습니다.
실제 사이트 Markdown 양. 공개 Books to Scrape 홈에서 Crawl4AI는 단일 호출로 살아 있는 페이지에서 13,476자 분량의 Markdown을 생성했습니다. 실제 카탈로그에서 한 번 긁었을 때 LLM이 먹을 수 있는 텍스트가 얼마나 나오는지 감을 잡게 해 줍니다.

이제부터는 거친 부분입니다. 행복한 경로를 벗어나야만 보이는 지점들이죠.
Raw Markdown은 넓게 잡습니다. 기사용 테스트 페이지에서는 제목과 본문 3개 문단 3/3을 가져오는 동시에, 내비게이션 텍스트, 관련 링크 블록, 가짜 구독 문구, 푸터까지 함께 가져왔습니다. 이건 결함이 아니라 raw Markdown 변환의 성격입니다. 렌더된 페이지 전체가 Markdown이 되기 때문에 잡다한 요소도 같이 들어옵니다. 정말 깔끔한 기사만 원한다면, 문서에 나온 방식은 콘텐츠 필터를 켜는 것입니다. PruningContentFilter는 텍스트 대비 링크 밀도로 노드를 점수화해 불필요한 요소를 제거하고, BM25ContentFilter는 쿼리 기준으로 순위를 매깁니다. 이번 테스트에서는 그 필터들을 실행하지 않았기 때문에 정화 점수는 매기지 않았습니다. 다만 사고방식은 분명합니다. raw Markdown은 넓게, clean Markdown은 필터를 켰을 때 얻는 결과입니다. 설정 없는 경로에서 편집 수준의 결과를 기대하진 마세요.
500 페이지는 조금 거짓말을 했습니다. 의도적으로 HTTP 500을 반환하는 페이지를 넣어봤습니다. Crawl4AI는 success=false와 상태 코드 500을 제대로 보고했지만, 오류 메시지는 “Blocked by anti-bot protection: Structural: minimal_text on small page.”라고 나왔습니다. 실제로는 안티봇 차단이 없었습니다. 아주 짧은 오류 페이지였고 visible text도 거의 없었는데, Crawl4AI의 구조적 휴리스틱이 이 얇은 본문을 보고 안티봇 라벨을 붙여버린 겁니다. 대규모 운영 시 기억해 둘 교훈은 이겁니다. “anti-bot” 문구를 문자 그대로 믿지 마세요. 상태 코드와 실제 상황을 먼저 보세요. 때로는 그냥 작은 페이지일 뿐입니다.

딥 크롤은 자동으로 대기 설정을 이어받지 않습니다. 이건 실제로 연결해 두기 전에 꼭 알고 싶었던 부분입니다. 직접 dynamic 페이지를 크롤할 때는 wait_for를 명시하니 8/8로 완벽했습니다. 하지만 BFS 딥 크롤러에게 홈에서 링크를 발견하고 따라가게 했더니, 5페이지를 발견했고 3개는 성공, 2개는 실패했습니다. 실패한 것 중 하나가 바로 그 JS 기반 카탈로그 페이지였습니다. 명시적 wait가 있으면 잘 되는 페이지죠. 딥 크롤에서는 JavaScript가 끝나기도 전에 페이지가 너무 얇다고 판단해 버렸고, 결국 같은 오해의 소지가 있는 “anti-bot” 메시지와 함께 중단됐습니다.
여기서 얻어야 할 교훈은 정확합니다. “Crawl4AI는 동적 페이지를 지원한다”는 말은 맞습니다. 하지만 “딥 크롤이 발견하는 모든 동적 페이지를 자동으로 기다려 준다”는 말은 아닙니다. 이 둘은 별개의 문서화된 기능입니다. 페이지별 대기와 딥 크롤 전략은 자동으로 합쳐지지 않습니다. 딥 크롤에서 JS가 많은 페이지를 다뤄야 한다면, 기다림 설정을 크롤 구성에 의도적으로 넣어야 합니다. 버그라기보다 설정의 문제지만, 발견된 링크에도 그대로 적용될 거라고 생각하면 반드시 발목을 잡습니다.
장단점, 돌려 말하지 않기
별을 받을 만한 이유:
- 렌더링된 Markdown, 구조화 JSON 추출, 스크린샷, 배치 크롤링, 딥 크롤까지 하나의 라이브러리로 커버합니다. 도구 네 개를 억지로 붙일 필요가 없습니다.
- 정적 추출은 매우 안정적입니다. 제 테스트에서는 Markdown 회수율 6/6, 구조화 레코드 6/6으로 빠르고 손실 없이 잘 나왔습니다.
- 실제 브라우저가 렌더링하므로 동적 렌더링도 진짜로 잘 됩니다. 명시적 wait를 주면 8/8, 스크린샷으로도 확인했습니다.
- Apache-2.0 라이선스라 상업적 사용에 친화적이고, v0.9.0까지 활발히 배포되는 큰 커뮤니티 프로젝트입니다.
- 설치가 실제로 제대로 되었는지 라이브 페이지 렌더링으로 확인하는
crawl4ai-doctor가 내장되어 있습니다.
대신 감수해야 할 점:
- 첫 설치가 무겁습니다. 두 개의 브라우저 스택에 FFmpeg와 Headless Shell까지 디스크에 깔립니다. 저장 공간이 부족한 환경에서는 꽤 큰 부담입니다.
- 콘텐츠 필터를 켜지 않으면 raw Markdown에는 잡음이 섞입니다. 깔끔한 경로는 기본값이 아니라 의도적인 선택입니다.
- 딥 크롤은 동적 페이지를 자동으로 기다려 주지 않습니다. 크롤 도중 발견한 JS 페이지는 추가 설정 없이는 실패할 수 있습니다.
- 오류 메시지가 헷갈릴 수 있습니다. 얇은 500 페이지가 아무 차단도 없는데 “anti-bot protection”이라고 표시된 사례가 있었습니다.
- 자기복구 셀렉터는 없습니다. CSS/XPath 스키마는 정적이며, 마크업이 바뀌면 사용자가 직접 유지보수해야 합니다.
누구에게 적합하고, 누구에게는 아닌가
이런 분께 추천합니다: RAG나 에이전트 파이프라인을 만드는 개발자라면, 같은 렌더링된 페이지에서 LLM용 Markdown과 구조화 JSON을 모두 얻을 수 있는 단일 도구가 필요할 때 잘 맞습니다. 타깃 사이트가 JavaScript 의존적이고, 명시적 wait를 직접 작성하는 데 익숙하며, 자체 인프라에서 실제 headless 브라우저를 돌릴 수 있다면 Crawl4AI는 꽤 강력하고 관리도 잘 되는 선택입니다. 모델용 Markdown과 데이터베이스용 스키마를 한 Apache-2.0 라이브러리에서 함께 다룰 수 있다는 점은 분명한 장점입니다.
이런 분께는 비추천합니다: 초경량 HTTP 파서처럼 밀리초 단위로 정적 HTML만 긁고 싶다면 Crawl4AI는 맞지 않습니다. 이 도구는 의도적으로 더 무겁고, 브라우저 다운로드만으로도 거슬릴 수 있습니다. 디스크나 대역폭이 빠듯하거나, 두 개의 브라우저 스택이 곧바로 문제 되는 최소 컨테이너에 배포한다면 피하는 편이 낫습니다. 그리고 자기복구 셀렉터를 찾고 왔다면 절대 맞지 않습니다. 그런 기능은 실제로 존재하지만, 이 도구의 기능은 아닙니다.
관리형 API는 어디에 들어맞나 — Thunderbit 관점
웹 데이터 추출을 위해 Thunderbit 사용해 보기
위의 모든 이야기는 브라우저를 직접 운영한다는 전제를 깔고 있습니다. 그건 충분히 합리적인 선택이고, 많은 팀에게는 오히려 더 좋은 선택입니다. 완전한 제어권, 호출당 비용 0원, 끝까지 내가 소유하는 코드. 하지만 어떤 트레이드오프를 선택하는지 분명히 말해 둘 필요가 있습니다. Thunderbit에서는 개발자 스택을 정반대 방향으로 설계했습니다. 브라우저, 안티봇 대응, JavaScript 렌더링을 사용자 기기에서 아예 떼어내는 방식입니다.
비교도 꽤 깔끔하게 됩니다. POST /distill 엔드포인트는 Crawl4AI의 Markdown 경로와 같은 일을 합니다. 페이지를 받아서 LLM 친화적인 Markdown으로 정리해 반환하죠. 차이라면 JS 렌더링과 안티봇 처리 레이어가 사용자의 브라우저가 아니라 저희 쪽에서 돌아간다는 점입니다. POST /extract 엔드포인트는 구조화 측면을 담당하고, 사용자가 정의한 스키마에 따라 JSON을 돌려줍니다. 수동으로 wait_for를 조정하는 대신 renderMode(none, basic, full)를 고르는 방식입니다. 둘 다 배치 버전이 있습니다. MCP 서버도 제공해서 thunderbit_distill, thunderbit_extract, 무료로 쓸 수 있는 thunderbit_suggest_fields를 Claude나 Cursor의 에이전트가 직접 호출할 수 있고, 터미널·CI·크론용으로는 npx @thunderbit/thunderbit-cli도 있습니다.
결국 누구의 어깨에 무게를 올리느냐의 차이입니다. Crawl4AI는 무료 오픈소스이고 셀프 호스팅이라, 브라우저 다운로드와 딥 크롤 연결, 실행 인프라 같은 운영 부담을 직접 떠안습니다. 저희 개발자 스택은 관리형 API라 그 부담을 저희가 지고, 비용은 호출당 사용량으로 전환됩니다. 어느 쪽이 절대적으로 더 낫다고는 할 수 없습니다. 모든 레이어를 직접 소유하고 요청당 비용을 내고 싶지 않다면 Crawl4AI를 쓰면 됩니다. 반대로 브라우저 운영 부담을 지우고 엔드포인트만 호출하고 싶다면 관리형 방식이 맞습니다. 이 API 뒤에는 10만 명 이상의 사용자를 가진 저희 확장 프로그램과 같은 엔진이 돌아가므로, 장난감 수준은 아닙니다.
이 카테고리 전반을 더 넓게 보고 싶다면, AI 웹 스크래핑에 관한 저희 글과 직접 비교해 본 오픈소스 GitHub 스크래퍼들도 함께 보면 좋습니다. 여기서 다 풀기엔 다른 글이 되어버릴 만큼 더 깊게 다뤄져 있습니다.
결론: Crawl4AI를 써야 할까?
네 — 렌더링된 같은 페이지에서 LLM용 Markdown과 구조화 JSON을 둘 다 얻고 싶고, RAG나 에이전트용으로 만들고 있으며, 실제 headless 브라우저를 자신의 인프라에서 돌릴 수 있는 개발자라면 그렇습니다. 제 테스트에서 핵심 기능은 약속한 대로 동작했습니다. 정적 추출 6/6, 명시적 wait가 있는 동적 페이지 8/8, 라이브 카탈로그에서 Markdown 13,476자, 깔끔한 배치 크롤까지. 라이선스도 좋고, 유지보수도 활발하며, 실제 일에 잘 맞는 도구입니다.
다만 세 가지는 분명히 알고 시작해야 합니다. 설치하면 브라우저 스택 두 벌이 디스크에 깔리고, 딥 크롤은 발견한 동적 페이지를 자동으로 기다려 주지 않으며, 얇은 오류 페이지가 오해의 소지가 있는 “anti-bot” 라벨을 달 수 있습니다. 하지만 이 셋은 치명적 결함이 아닙니다. “기적을 기대하는 것”과 “실제 도구를 사용하는 것” 사이의 차이일 뿐입니다. 다시 말해 이 도구는 브라우저이고, Markdown 변환기이며, 사용자가 관리하는 셀렉터입니다. 그 관점으로 이해하면, 살아 있는 페이지를 모델이 쓸 수 있는 텍스트로 바꾸는 가장 좋은 방법 중 하나가 됩니다.
이 평가는 단 한 번의 테스트 러닝을 바탕으로 한 잠정적인 읽기입니다. 천 페이지짜리 크롤을 돌린 것도 아니고, 콘텐츠 필터를 모두 시험한 것도 아니며, LLM 추출 경로나 Docker 서버 모드도 건드리지 않았습니다. 그러니 제 머릿속 평점은 최종 합격점이라기보다 “강력하지만 숙제가 남아 있는 상태”로 받아들이는 편이 맞습니다. 그리고 메타데이터를 인용하기 전에 별점과 버전은 다시 확인하세요. 둘 다 움직이는 값이니까요.
웹 데이터 추출을 위해 Thunderbit 사용해 보기 Get Started Free
자주 묻는 질문
Crawl4AI에 자기복구형 또는 적응형 셀렉터가 있나요? 아니요. 이 도구에 대해 가장 흔한 오해입니다. Crawl4AI는 사용자가 작성하고 유지보수하는 정적 CSS/XPath 스키마를 사용합니다. 사이트가 셀렉터가 의존하는 클래스명을 바꾸면, 사용자가 스키마를 고칠 때까지 추출은 실패합니다. 적응형·자가 복구 셀렉터는 Scrapling 같은 다른 도구의 기능이지, Crawl4AI의 기능은 아닙니다.
Crawl4AI를 돌리려면 풀 브라우저가 꼭 필요한가요?
사실상 그렇습니다. 핵심 가치가 실제 브라우저로 JavaScript를 렌더링하는 데 있기 때문에 crawl4ai-setup은 Playwright와 Patchright 두 브라우저 스택에 FFmpeg와 Headless Shell까지 내려받습니다. 브라우저 흔적이 전혀 없는 작은 HTTP 전용 파서를 원한다면 Crawl4AI는 방향이 다르며, 더 가벼운 프레임워크를 찾는 편이 낫습니다.
왜 Crawl4AI가 차단되지도 않은 페이지에 “anti-bot protection”이라고 했나요? 구조적 휴리스틱이 visible text가 매우 적은 페이지를 그렇게 표시하기 때문입니다. 제 테스트에서는 의도적으로 만든 HTTP 500 페이지가 내용이 거의 없다는 이유로 그 라벨을 달았습니다. 실제로는 아무 차단도 없었습니다. 사이트가 적극적으로 막는다고 결론내리기 전에 상태 코드와 실제 상황을 반드시 확인하세요. 때로는 그냥 얇거나 깨진 페이지일 뿐입니다.
Crawl4AI의 딥 크롤은 JavaScript 페이지를 자동으로 처리하나요?
자동으로는 아닙니다. 직접 크롤할 때 명시적인 wait_for를 넣으면 제 dynamic 페이지는 8/8로 잘 처리됐지만, 같은 페이지를 발견하는 BFS 딥 크롤에서는 실패했습니다. 5페이지를 찾고 3개는 성공, 2개는 실패했는데, JavaScript가 렌더링되기 전에 페이지가 너무 얇다고 판단했기 때문입니다. 딥 크롤에서 동적 페이지를 다뤄야 한다면 대기 설정을 직접 구성해야 합니다.
Crawl4AI는 Thunderbit 같은 관리형 스크래핑 API와 어떻게 다른가요?
Crawl4AI는 무료 오픈소스 셀프 호스팅 도구입니다. 브라우저와 인프라는 사용자가 직접 운영·관리하고, 호출당 비용은 없습니다. 반면 Thunderbit의 개발자 스택(/distill은 Markdown, /extract는 구조화 JSON, 여기에 MCP와 CLI 포함)은 관리형 API라서 렌더링, 안티봇 처리, 브라우저 운영을 저희가 맡고 사용자는 호출당 비용을 지불합니다. 차이는 완전한 제어권과 요청당 비용 0원, 또는 운영 부담을 외부로 넘기는 것 사이입니다.


