pip install crawl4ai 한 줄과 crwl <url> 한 줄로 시작한다. GitHub에서 가장 별을 많이 받은(50k+★) 웹 크롤러이며, API 키 없이 100% 로컬로 돌아간다. (저장소: unclecode/crawl4ai · Apache-2.0 · v0.8.6)LLM에게 웹페이지 내용을 물어보려면, 먼저 그 페이지를 모델이 읽기 좋은 텍스트로 바꿔야 한다. Crawl4AI는 그 "웹 → 텍스트" 첫 단계를 담당한다. 브라우저로 페이지를 실제로 띄워 자바스크립트까지 실행한 뒤, 본문만 골라 마크다운으로 정제해 돌려준다.
Crawl4AI는 "원두 → 에스프레소" 추출기다. 웹페이지(생두)에는 광고·메뉴·추천글·쿠키 배너 같은 껍데기가 잔뜩 붙어 있다. 사람이라면 눈으로 본문만 읽지만, LLM에게 페이지 HTML을 통째로 던지면 이 잡동사니까지 다 삼켜서 토큰을 낭비하고 헷갈려 한다.
Crawl4AI는 이 생두를 갈아 진짜 본문만 농축한 에스프레소(마크다운)로 뽑아낸다. 그 결과물은 RAG 파이프라인이나 AI 에이전트라는 "바리스타"가 바로 받아 쓸 수 있다.
RAG와 AI 에이전트가 퍼지면서, 모델에 넣을 고품질 텍스트를 어떻게 확보하느냐가 핵심 문제로 떠올랐다. 예전 크롤러(Scrapy 등)는 사람이 볼 HTML을 긁는 데 초점이 있었지, "LLM이 먹기 좋은 형태"는 신경 쓰지 않았다. Crawl4AI는 처음부터 출력 목표를 "LLM-ready 마크다운"으로 못 박고 설계됐다 — 제목·표·코드·인용을 살린 깔끔한 마크다운을 기본 출력으로 내놓는다.
같은 일을 하는 상용 서비스가 여럿 있다. Firecrawl·Jina Reader 같은 SaaS는 편하지만 호출당 과금되고, 파일·URL을 외부 서버로 보낸다. Crawl4AI는 pip install 한 줄로 내 컴퓨터에서 돌고, 외부로 데이터가 나가지 않으며, 비용이 0이다. 제작자(UncleCode)가 README에서 밝힌 동기 자체가 "계정·토큰·16달러를 요구하던 기존 도구에 화가 나서 며칠 만에 만들었다"는 것이다.
"구조적 데이터 추출"이라고 하면 보통 LLM에게 시키는 걸 떠올리지만, 그건 토큰 비용이 든다. Crawl4AI는 JsonCssExtractionStrategy로 CSS 선택자·XPath 스키마만 정의하면 LLM 호출 0회로 반복 패턴(상품 목록 등)을 JSON으로 뽑아낸다. 정말 비정형인 부분만 LLM에 맡기는 식으로 비용을 통제할 수 있다.
AdaptiveCrawler는 질문(query)을 주면, 답을 충분히 모았다고 판단될 때까지만 페이지를 탐색하고 멈춘다. 통계적 신뢰도(confidence)가 임계값을 넘으면 자동 중단 — 무작정 사이트 전체를 긁는 대신 "필요한 만큼만" 크롤링해 시간과 자원을 아낀다.
Docker 이미지로 띄우면 FastAPI 서버 + 모니터링 대시보드 + 플레이그라운드가 따라온다. 특히 MCP 통합이 핵심인데, Claude Code 같은 AI 코딩 도구에 Crawl4AI를 "웹을 읽는 도구"로 바로 꽂을 수 있다. 2026년의 "에이전트가 도구를 쓴다" 흐름을 정확히 탔다.
페이지 소스를 통째로 프롬프트에 붙이면 토큰이 폭발하고(수만 토큰), 광고·스크립트·메뉴가 노이즈로 섞여 답 품질이 떨어진다. 비용은 늘고 정확도는 내려가는 최악의 조합.
Crawl4AI의 콘텐츠 필터(PruningContentFilter·BM25)로 본문만 추린 "fit markdown"을 만들어 넣으면, 토큰은 몇 배 줄고 핵심만 남아 답 품질이 올라간다. 같은 페이지에서 raw_markdown과 fit_markdown 길이를 찍어보면 차이가 한눈에 보인다.
| 항목 | Crawl4AI | Firecrawl | Jina Reader | Scrapy |
|---|---|---|---|---|
| 형태 | 오픈소스 라이브러리 | SaaS + 오픈소스 | SaaS (API) | 오픈소스 프레임워크 |
| 가격 | 완전 무료 | 호출당 과금 | 호출당 과금 | 무료 |
| 실행 위치 | 로컬 | 주로 클라우드 | 클라우드 | 로컬 |
| LLM-ready 마크다운 | 핵심 기능 | O | O | X (직접 구현) |
| JS 렌더링 | O (Playwright) | O | O | 제한적 |
| LLM 없는 추출 | O (CSS/XPath 스키마) | 일부 | X | O |
| 안티봇/스텔스 | O (3단계 + 프록시) | O | 일부 | X (직접) |
Crawl4AI는 "직접 다 만든 크롤러"가 아니라, 검증된 라이브러리들을 똑똑하게 조립한 파이프라인에 가깝다. pyproject.toml의 의존성 목록을 뜯어보면 각 계층이 어떤 도구 위에 서 있는지 명확하게 드러난다.
patchright는 봇 탐지를 피하도록 다듬은 Playwright 포크이고, playwright-stealth는 "나 자동화 브라우저예요" 흔적을 지운다.단순 HTTP 요청(requests)으로는 자바스크립트가 그리는 페이지를 못 읽는다. Crawl4AI가 브라우저를 통째로 띄우는 이유다. fake-useragent로 사람처럼 보이는 헤더를 쓰고, antibot_detector가 차단을 감지하면 proxy_strategy가 프록시를 갈아끼우며 재시도한다. 구버전 호환을 위한 동기 방식(selenium)은 옵션으로만 남아 있다.
Crawl4AI의 메인 클래스 이름이 AsyncWebCrawler인 데서 보이듯, 전부 asyncio 비동기로 짜여 있다. 한 페이지가 응답을 기다리는 동안 다른 페이지를 처리해 처리량을 끌어올린다.
| 라이브러리 | 역할 |
|---|---|
asyncio / anyio | 비동기 동시성의 토대 (코루틴 스케줄링) |
aiohttp / httpx[http2] | 브라우저 없이 빠르게 받는 경량 HTTP 경로 (HTTP/2 지원) |
aiofiles | 파일 입출력도 비동기로 (디스크 대기에 멈추지 않게) |
aiosqlite | 크롤 결과 캐시를 비동기 SQLite에 저장 |
xxhash | URL을 빠르게 해싱해 캐시 키로 사용 |
받아온 HTML을 LLM-ready 마크다운으로 바꾸는 핵심 단계다. lxml·beautifulsoup4·cssselect로 HTML을 파싱하고, 저장소 안에 html2text를 포크해 내장(crawl4ai/html2text/)해 HTML→마크다운 변환을 직접 통제한다.
rank-bm25로 질문과 무관한 본문 블록을 걸러낸다. 단어 어근을 맞추려고 nltk·snowballstemmer(어간 추출기)도 함께 쓴다.마크다운이 아니라 "필드가 정해진 JSON"이 필요할 때 쓰는 계층이다. pydantic v2로 추출 스키마를 정의하고, LLM 추출이 필요하면 unclecode-litellm이 100여 개 LLM 프로바이더(OpenAI·Anthropic·Ollama 등)를 하나의 인터페이스로 묶어준다.
v0.8.6에서 원래 쓰던 litellm이 PyPI 공급망 공격(악성 패키지 주입)에 노출돼, 제작자가 직접 포크한 unclecode-litellm으로 교체했다. 오픈소스 의존성도 보안 위협이 될 수 있다는 실사례 — v0.8.5 이하 사용자는 업그레이드가 권장된다.
lark(파서 생성기)로 C4A-Script라는 자체 브라우저 자동화 DSL을 컴파일하고, click·rich로 컬러풀한 crwl 커맨드라인을 제공한다. 배포는 FastAPI 서버를 Docker로 감싸고, 옵션으로 torch·transformers·sentence-transformers(코사인 유사도 추출)와 pypdf(PDF 처리)를 붙일 수 있다.
script/ 폴더의 c4a_compile.py가 이걸 실제 실행 코드로 번역한다.crawler.arun(url) 한 줄을 호출하면 내부에서 다음 단계가 차례로 돈다. 각 단계가 교체 가능한 "전략(Strategy) 객체"라는 게 이 구조의 핵심이다.
여러 URL을 한꺼번에 처리하는 arun_many()는 여기에 MemoryAdaptiveDispatcher가 더해진다. 메모리 사용량을 보면서 동시 처리 개수를 자동 조절해, 메모리가 빠듯하면 동시성을 낮추고 여유가 있으면 올린다.
스크래핑·필터·마크다운·추출·청킹·딥크롤링 모든 단계가 인터페이스를 공유하는 교체 가능한 클래스다. 기본 동작이 마음에 안 들면 같은 인터페이스로 내 클래스를 만들어 꽂으면 된다. 이게 Crawl4AI가 기능을 계속 늘리면서도 코어가 안 무너지는 비결이다.
커피 머신의 "필터 바스켓"을 생각하면 된다. 머신(크롤러) 본체는 그대로 두고, 1잔용·2잔용·종이필터 바스켓을 끼웠다 뺐다 한다. Crawl4AI도 본체는 두고 필터 전략·추출 전략만 바꿔 끼운다.
설정 객체를 일부러 둘로 나눴다. BrowserConfig는 "브라우저를 어떻게 띄울까"(헤드리스 여부, 프록시, 유저 프로필) 같은 오래 유지되는 설정이고, CrawlerRunConfig는 "이번 요청을 어떻게 처리할까"(캐시 모드, 어떤 필터, JS 코드) 같은 요청마다 바뀌는 설정이다. 브라우저는 한 번 띄워 재사용하면서, 요청별로 다른 설정을 줄 수 있다.
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
async def main():
browser_cfg = BrowserConfig(headless=True, verbose=True) # 오래 유지
run_cfg = CrawlerRunConfig(cache_mode=CacheMode.ENABLED) # 요청마다
async with AsyncWebCrawler(config=browser_cfg) as crawler:
result = await crawler.arun("https://example.com", config=run_cfg)
print(result.markdown.fit_markdown) # 정제된 본문
asyncio.run(main())
브라우저를 매번 새로 띄우면 느리다. browser_manager.py는 컨텍스트를 최대 20개(_max_contexts)까지 유지하는 LRU(Least Recently Used) 풀로 관리한다. 참조 카운트(_context_refcounts)와 마지막 사용 시각(_context_last_used)을 추적해, 용량 초과 시 가장 오래 안 쓴 컨텍스트를 축출해 메모리를 관리한다.
deep_crawling/에는 BFS(너비 우선)·DFS(깊이 우선)·Best-First(점수 높은 링크 먼저) 세 가지 탐색 전략이 있고, filters.py·scorers.py가 "어떤 링크를 따라갈지"를 정한다. v0.8.0부터는 긴 크롤이 중간에 죽어도 resume_state로 체크포인트부터 이어서 할 수 있다 — 각 URL 처리 후 on_state_change 콜백으로 상태를 Redis 등에 저장해 두는 방식이다.
저장소의 핵심은 crawl4ai/ 파이썬 패키지다. 파일 이름만 봐도 "전략별로 모듈을 쪼갠" 설계 철학이 드러난다. 실제 트리를 단순화하면 다음과 같다.
이 트리를 읽는 법: 접두사 async_가 붙은 파일들이 핵심 런타임이고, *_strategy.py로 끝나는 파일들이 "갈아끼울 수 있는 부품"이다. js_snippet/의 작은 자바스크립트들(쿠키 팝업 제거, Shadow DOM 펼치기, 오버레이 제거)은 브라우저 안에서 직접 실행되어 "사람이 봤을 때의 화면"을 만들어 준다.
Crawl4AI는 단순한 크롤러가 아니라 "잘 설계된 비동기 파이썬 시스템"의 교과서에 가깝다. 분야별로 배울 거리를 정리하면:
async/await로 I/O 대기 시간을 어떻게 겹쳐서 처리량을 올리는지, 그리고 MemoryAdaptiveDispatcher가 메모리를 모니터링하며 동시 작업 수를 동적으로 조절하는 패턴을 볼 수 있다. "무작정 많이 띄우면 빠르다"가 틀린 이유를 코드로 배운다.
실제 브라우저를 코드로 조종하고, CDP(Chrome DevTools Protocol)로 원격 제어하며, 봇 탐지를 어떻게 회피하는지(undetected 모드, UA 위장, 프록시 교체) 실전 기법이 담겨 있다.
"기능을 추가해도 코어가 안 무너지는" 구조를 어떻게 만드는지가 핵심 교훈이다. 인터페이스 하나를 정해두고 구현체를 갈아끼우는 방식 — 디자인 패턴 책의 예제가 아니라 5만 스타 프로젝트의 실제 적용 사례로 본다.
"본문 vs 잡동사니"를 가르는 PruningContentFilter의 휴리스틱과, 질문 관련도로 거르는 BM25를 보면 검색 엔진의 기본 원리를 자연스럽게 익힌다. LLM 없이도 꽤 똑똑하게 거를 수 있다는 걸 알게 된다.
추출 결과의 "모양"을 pydantic 스키마로 강제하고, litellm으로 여러 LLM 프로바이더를 한 인터페이스 뒤로 숨기는 패턴. 모델을 바꿔도 코드를 안 고치는 추상화 설계를 배운다.
라이브러리를 어떻게 서버로 감싸 배포하는지, 브라우저 풀링으로 응답 속도를 올리고, 모니터링·WebSocket 스트리밍·JWT 인증을 붙이는지, 그리고 MCP로 AI 에이전트에 도구를 노출하는 최신 패턴까지 한 저장소에서 본다.
기본 설치는 가볍지만, 브라우저를 통째로 띄운다는 점이 자원의 핵심 변수다.
| 항목 | 요구 사항 / 메모 |
|---|---|
| 파이썬 | 3.10 이상 (3.10~3.13 지원) |
| 브라우저 | crawl4ai-setup이 Playwright Chromium 자동 설치 (수백 MB 다운로드) |
| 메모리 | 브라우저 인스턴스당 수백 MB — 동시 크롤 수만큼 곱해서 생각해야 함 |
| Docker | 이미지 실행 시 --shm-size=1g 권장, 포트 11235 노출, AMD64/ARM64 자동 감지 |
| 옵션 (무거움) | [torch]·[transformer]·[cosine]는 수 GB + 가능하면 GPU. 코사인 유사도 추출이 필요할 때만 |
| 설치 점검 | crawl4ai-doctor로 브라우저·의존성 상태를 진단 |
대부분의 작업은 기본(pip install crawl4ai + Chromium)만으로 충분하다. torch 계열은 "LLM 없이 의미 기반으로 본문을 고르고 싶을 때"만 선택적으로 깐다.
pip install -U crawl4ai && crawl4ai-setup 후 crwl https://www.nbcnews.com/business -o markdown. 브라우저가 뜨고 본문이 마크다운으로 떨어지는 걸 눈으로 확인한다. 첫 성공 경험용.
파이썬에서 PruningContentFilter를 단 DefaultMarkdownGenerator를 붙이고, result.markdown.raw_markdown과 fit_markdown의 글자 수를 찍어 본다. 노이즈가 얼마나 줄어드는지 체감하는 게 목표. CacheMode도 바꿔가며 속도 차이를 본다.
JsonCssExtractionStrategy에 CSS 선택자 스키마를 정의해, 쇼핑몰·목록 페이지에서 제목·가격·이미지를 JSON으로 뽑는다. LLM 호출 0회로 구조적 추출이 된다는 걸 직접 확인한다.
BFSDeepCrawlStrategy(max_depth=2, max_pages=30)로 문서 사이트 전체를 크롤하고, on_state_change로 상태를 파일에 저장한 뒤 중간에 끊고 resume_state로 이어서 돌려 본다. 긴 작업의 내결함성을 설계하는 감각을 익힌다.
docker run -p 11235:11235로 서버를 띄우고 /playground·/dashboard를 살펴본 뒤, MCP로 AI 코딩 도구에 "웹 읽기 도구"로 연결한다. 더 나아가 자신만의 ExtractionStrategy 서브클래스를 작성해 파이프라인을 확장한다.
| 주차 | 주제 | 핵심 키워드 |
|---|---|---|
| 1주 | 비동기 파이썬 + 브라우저 자동화 기초 | asyncio, await, Playwright 기본 |
| 2주 | Crawl4AI 기본 크롤 + 마크다운/필터 | AsyncWebCrawler, fit markdown, PruningContentFilter |
| 3주 | 구조적 추출 (CSS vs LLM) | JsonCssExtractionStrategy, pydantic, litellm |
| 4주 | 딥 크롤링 + 배치 + 캐시 | BFS/DFS/Best-First, MemoryAdaptiveDispatcher, CacheMode |
| 5주 | 안티봇 · 세션 · 프로필 | stealth, proxy, BrowserProfiler, 세션 재사용 |
| 6주 | 프로덕션 배포 | FastAPI, Docker, MCP, 모니터링 대시보드 |
| 용어 | 뜻 |
|---|---|
| LLM-ready 마크다운 | 모델이 바로 읽기 좋게 정제된 마크다운 출력. Crawl4AI의 기본 결과물 |
| fit markdown | 노이즈를 걸러낸 "본문만" 마크다운 (raw_markdown의 정제본) |
| PruningContentFilter | 휴리스틱으로 본문 블록만 남기고 잡동사니를 쳐내는 필터 |
| BM25ContentFilter | 질문 관련도(BM25 점수)로 본문을 거르는 필터 |
| AsyncWebCrawler | 메인 진입 클래스. arun()(단일) / arun_many()(배치) |
| BrowserConfig / CrawlerRunConfig | 브라우저 수준 설정 vs 요청 수준 설정 (2층 분리) |
| JsonCssExtractionStrategy | LLM 없이 CSS/XPath 스키마로 JSON 추출 |
| LLMExtractionStrategy | litellm 기반 LLM 추출 (비정형 데이터용) |
| AdaptiveCrawler | 신뢰도 임계값에 도달하면 자동으로 멈추는 학습형 크롤러 |
| AsyncUrlSeeder | sitemap + Common Crawl로 URL을 대량 발굴 |
| 딥 크롤링 (BFS/DFS/Best-First) | 링크를 따라 사이트를 탐색하는 세 가지 전략 |
| CacheMode | 캐시 동작 모드 (ENABLED / BYPASS / WRITE_ONLY) |
| C4A-Script | 브라우저 동작을 적는 자체 DSL (lark로 컴파일) |
| MCP | 에이전트가 도구를 쓰는 표준 규약. Crawl4AI는 MCP 서버 내장 |
| Shadow DOM 플래트닝 | 웹 컴포넌트 캡슐 속 텍스트까지 끄집어내는 처리 |
unclecode/crawl4ai:latest