Crawl4AI로 RAG용 Markdown을 만들 때 먼저 확인할 것
Crawl4AI로 동적 웹페이지를 Markdown, JSON으로 수집할 때 렌더링 완료 조건, 추출 품질, 중복, 갱신, 출처 보존과 운영 비용을 점검합니다.
JavaScript로 렌더링되는 페이지를 RAG용 Markdown이나 구조화 JSON으로 바꾸려면 Crawl4AI가 후보가 될 수 있지만, 변환 결과가 곧 정확한 본문 데이터라는 뜻은 아닙니다. 정적 요청으로 충분한 페이지와 브라우저가 필요한 페이지를 먼저 나누고, 렌더링 완료, 본문 추출, 출처 보존을 서로 다른 성공 단계로 검사해야 합니다. 도입 판단은 수집 건수보다 사람이 정한 정답 문서에서 누락과 중복이 얼마나 남는지로 하는 편이 정확합니다.
HTML을 Markdown으로 바꾸면 무엇이 좋아지나
Crawl4AI는 Playwright 기반 브라우저 제어와 비동기 수집을 사용하고, 페이지 결과를 Markdown으로 제공하는 것으로 소개됩니다. 메뉴, 스크립트, 스타일이 섞인 raw HTML보다 제목과 목록 구조를 모델 입력에 남기기 쉽습니다. JsonCssExtractionStrategy를 이용하면 CSS 선택자를 기준으로 특정 필드를 JSON으로 구성할 수 있습니다.
Markdown이 짧아져도 중요한 표, 각주, 숨겨진 탭이 빠질 수 있습니다. 같은 페이지에서 원문 텍스트 수, 링크 수, 표 행 수를 비교하고 빈 필드를 실패로 처리해야 합니다.
원문의 최소 코드는 버전 없는 스냅샷이다
다음 코드는 원문에 포함된 비동기 수집 예시를 줄이지 않고 옮긴 것입니다.
1
2
3
4
5
6
7
8
9
import asyncio
from crawl4ai import AsyncWebCrawler
async def main():
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(url="https://www.example.com")
print(result.markdown)
asyncio.run(main())
패키지 버전, Python 버전, Playwright 브라우저 설치가 명시되지 않았고 예시 URL은 실제 수집 대상이 아닙니다. 특정 정보의 JSON 추출도 이 조각에는 구현되어 있지 않습니다. 현재 API와 설치법은 GitHub 저장소와 문서를 사용 시점에 대조해야 합니다.
동적 페이지는 기다림 조건이 핵심이다
SPA는 첫 응답에 본문이 없고 이후 JavaScript가 데이터를 채울 수 있습니다. 페이지 로드 완료만 기다리면 빈 Markdown을 얻을 수 있으므로 대상 요소의 등장, 페이지 이동, 더 보기 버튼처럼 완료 조건을 명시해야 합니다. 로그인과 세션이 필요한 페이지는 쿠키와 비밀값이 로그에 남지 않는지도 확인해야 합니다.
비동기 처리는 동시 요청을 늘릴 수 있지만 대상 서버와 로컬 브라우저 자원을 동시에 압박합니다. 동시성 제한, 재시도 간격, 시간 초과, 중복 URL 제거를 두고 CPU, 메모리와 실패율을 함께 측정해야 합니다.
RAG 품질은 크롤링 뒤에 결정된다
수집 성공 뒤에도 문서 날짜, canonical URL, 섹션 경계와 표를 보존해야 검색 결과를 원문에 연결할 수 있습니다. 메뉴 문구가 모든 페이지에 반복되면 임베딩 검색을 오염시키므로 문서 간 중복도 제거해야 합니다. 변경된 페이지를 다시 수집할 기준과 삭제된 문서 처리도 필요합니다.
브라우저 크롤링은 단순 HTTP 요청보다 자원을 많이 쓰고 사이트별 구조 차이를 없애지 못합니다. 대상 사이트의 허용 범위와 접근 정책을 확인하고, 소규모 정답 세트에서 누락, 중복, 잘못된 필드 비율을 측정한 뒤 규모를 늘리는 편이 안전합니다.
브라우저와 단순 HTTP 요청 중 무엇을 고를까
페이지 소스에 제목과 본문이 이미 들어 있다면 HTTP 응답을 파싱하는 경로가 더 단순합니다. 브라우저 시작 시간과 JavaScript 실행 비용이 없고 실패 지점도 적습니다. 반대로 첫 HTML에는 빈 껍데기만 있고 API 응답 뒤에 본문이 생기거나, 탭, 더 보기, 무한 스크롤을 눌러야 한다면 브라우저 자동화가 필요합니다.
선택은 사이트 단위보다 페이지 유형 단위로 할 수 있습니다. 같은 도메인에서도 기사 본문은 정적이고 검색 결과는 동적일 수 있습니다. 먼저 HTTP로 시도하고 필수 선택자가 없을 때만 브라우저 경로로 넘기면 모든 URL에 비싼 렌더링을 적용하는 일을 피할 수 있습니다.
로그인이 필요한 페이지는 기술적으로 열 수 있다는 사실보다 수집 권한과 자격 증명 관리가 먼저입니다. 쿠키를 재사용할 때는 수명과 접근 범위를 줄이고, 스크린샷, HTML, 오류 로그에 세션 값이 남지 않게 해야 합니다. 인증 실패를 빈 문서로 저장하면 이후 RAG가 그 빈 결과를 정상 문서처럼 취급할 수 있으므로 상태 코드를 분리해야 합니다.
추출 파이프라인은 어떤 단계로 나눌까
첫째, URL을 정규화하고 같은 canonical 문서의 중복 요청을 합칩니다. 둘째, 렌더링 성공과 필수 요소 등장을 확인합니다. 셋째, Markdown 또는 CSS 기반 JSON을 만들고, 넷째 원문과 비교하는 품질 검사를 거칩니다. 마지막으로 통과한 문서에만 출처, 수집 시각, 섹션 경계를 붙여 저장합니다.
기사 페이지라면 제목, 작성 시각, 본문 첫 문장, 본문 링크 수를 샘플 기준으로 삼을 수 있습니다. 상품 페이지라면 이름, 가격, 재고처럼 필수 필드를 정하고 하나라도 비면 재시도 또는 검토 대상으로 보냅니다. 필드가 비어도 HTTP 200이 반환되는 경우가 흔하므로 네트워크 성공과 데이터 성공을 구분해야 합니다.
Markdown은 최종 목적이 아니라 중간 표현입니다. 메뉴와 푸터가 반복되면 여러 문서의 임베딩에 같은 문구가 과도하게 들어가고, 표가 평문으로 무너지면 열 이름과 숫자가 잘못 연결될 수 있습니다. 청킹 전에 반복 블록을 식별하고, 표와 코드 블록은 행이나 함수 경계를 고려해 나누며, 각 청크가 원문 위치로 돌아갈 수 있는 정보를 남겨야 합니다.
실패를 어떻게 재현하고 진단할까
빈 문서가 생기면 먼저 페이지가 실제로 렌더링됐는지, 필수 선택자를 너무 일찍 찾았는지, 로그인이나 지역 제한 페이지를 받았는지 확인합니다. 본문은 있는데 일부가 누락됐다면 더 보기 버튼과 가상 스크롤, 숨겨진 탭이 있는지 봅니다. 내용이 중복됐다면 페이지 내부의 반복 메뉴와 URL 정규화 실패를 나눠 조사해야 합니다.
브라우저가 자주 종료되면 동시성을 줄이고 한 페이지의 메모리 사용량과 timeout을 기록합니다. 무조건 재시도하면 같은 무거운 페이지가 작업열을 점유할 수 있으므로, 일시적 네트워크 오류와 영구적인 선택자 실패를 다른 정책으로 처리해야 합니다. 재시도 뒤 저장이 두 번 일어나지 않도록 문서 키와 쓰기 작업의 멱등성도 필요합니다.
사이트 구조가 바뀌었을 때는 전체 수집량보다 품질 지표가 먼저 변할 수 있습니다. 제목 길이, 본문 문자 수, 표 행 수의 분포를 날짜별로 비교하면 “성공” 응답 속에서 추출기가 조용히 망가진 시점을 찾기 쉽습니다. 실패 HTML을 제한적으로 보관하되 개인정보와 인증 값은 제거해야 합니다.
작은 검증 세트는 어떻게 만들까
대상 사이트마다 쉬운 문서만 고르지 말고 짧은 글, 긴 글, 표가 있는 글, 이미지 중심 글, 로그인이 필요한 글을 포함합니다. 사람이 원문에서 필수 문장과 필드를 표시하고 Crawl4AI 출력에 남았는지 확인합니다. 이 결과를 회귀 테스트로 두면 선택자나 라이브러리 버전을 바꿀 때 무엇이 좋아지고 나빠졌는지 설명할 수 있습니다.
성능은 페이지당 평균 시간만 보지 않습니다. 첫 렌더링 지연, 실패 후 재시도 시간, peak 메모리, 성공 문서당 전체 비용을 함께 봅니다. 정적 경로와 브라우저 경로를 같은 문서에서 비교해 품질 차이가 없다면 더 단순한 경로를 선택합니다. 이렇게 수집, 검증, 저장을 나누면 Crawl4AI는 만능 파서가 아니라 관리 가능한 브라우저 수집 계층이 됩니다.
갱신 정책도 첫 수집과 분리합니다. 문서 내용이 바뀌지 않았으면 기존 청크와 임베딩을 재사용하고, 삭제된 페이지는 검색 결과에서 언제 빠질지 정해야 합니다. 수집 시각만 달라진 복제 문서가 계속 쌓이면 최신 답변과 출처 집계가 왜곡되므로 content hash와 canonical URL을 함께 이용해 변경 여부를 판정하는 것이 좋습니다.
수집기 버전을 바꿀 때도 같은 정답 URL을 다시 처리해 이전 결과와 비교합니다. 문서 수가 같아도 본문 길이와 표 구조가 달라질 수 있으므로 배포 전 diff 검토가 필요합니다.
원문과 버전 확인
함께 읽으면 이해가 이어지는 글
- GitNexus는 코드를 밖으로 보내지 않나: 브라우저 Graph RAG와 MCP 경계 — GitNexus가 브라우저에서 AST, 지식 그래프를 만드는 방식과 MCP로 외부 모델을 연결할 때 달라지는 데이터 경계, 규모, 정확도 검증법을 정리합니다.
- PageIndex는 벡터 DB 없이 긴 문서를 잘 찾을까: 트리 검색 검증법 — PageIndex가 문서의 목차와 섹션을 트리로 만들고 LLM으로 탐색하는 원리, 벡터 검색과의 비용, 정확도 비교 및 설치 예시를 정리합니다.
- Dify가 LLM 스파게티를 없앨까: DAG, Celery, DSL이 옮겨 놓은 복잡도 — Dify가 프롬프트, 검색, 분기 로직을 어떻게 시각적 DAG로 분리하는지, 그리고 배포 전에 확인할 버전 관리, 확장, 운영 비용을 짚습니다.
자주 묻는 질문
Crawl4AI가 만든 Markdown을 바로 임베딩해도 되나요?
먼저 제목, 표, 링크, 본문 순서와 반복 메뉴가 어떻게 변환됐는지 확인해야 합니다. 출처 메타데이터와 문서 경계를 붙이고 정답 샘플에서 누락과 중복을 측정한 뒤 임베딩하는 편이 안전합니다.
모든 사이트에 브라우저 크롤링이 필요한가요?
정적 HTML에 본문이 들어 있는 사이트는 단순 HTTP 수집이 더 빠르고 저렴할 수 있습니다. JavaScript 렌더링이나 사용자 상호작용이 필요한 페이지에만 브라우저 경로를 쓰는 것이 운영 비용을 줄입니다.
비동기 수집의 동시성은 높을수록 좋은가요?
아닙니다. 로컬 브라우저의 CPU, 메모리와 대상 사이트의 허용 요청량을 함께 고려해야 합니다. 실패율과 지연을 보면서 동시성, 재시도, 시간 초과를 정해야 합니다.