Apidog

올인원 협업 API 개발 플랫폼

API 설계

API 문서

API 디버깅

API 모킹

API 자동화 테스트

Crawl4AI 튜토리얼: 초보자 가이드

Mark Ponomarev

Mark Ponomarev

Updated on April 30, 2025

AI 시대에는 웹 데이터에 효율적으로 접근하고 처리하는 것이 중요합니다. Crawl4AI는 대규모 언어 모델(LLM), AI 에이전트 및 최신 데이터 파이프라인을 사용하는 개발자를 위해 세심하게 설계된 강력한 오픈 소스 웹 크롤러 및 스크래퍼로 등장했습니다. 이 튜토리얼은 설치부터 고급 크롤링 기술까지 Crawl4AI에 대한 심층적인 내용을 다룹니다.

💡
아름다운 API 문서를 생성하는 훌륭한 API 테스트 도구를 원하십니까?

최대한의 생산성으로 개발자 팀이 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?

Apidog는 귀하의 모든 요구를 충족하며 Postman을 훨씬 더 저렴한 가격으로 대체합니다!
버튼

프로젝트에 Crawl4AI를 선택해야 하는 이유

Crawl4AI는 단순한 표준 웹 스크래퍼 이상입니다. LLM 친화적으로 처음부터 설계되었습니다. 이는 다음 사항에 중점을 둡니다.

  • 깔끔한 마크다운 생성: 상용구 및 노이즈를 제거하여 검색 증강 생성(RAG) 시스템 및 모델 미세 조정에 최적화된 구조가 잘 잡히고 간결한 마크다운을 생성합니다.
  • 구조화된 데이터 추출: 전통적인 방법(CSS 선택자, XPath)을 사용하거나 LLM을 활용하여 더 복잡하고 의미론적인 추출 작업을 수행하여 특정 데이터 포인트를 JSON과 같은 형식으로 추출할 수 있습니다.
  • 고성능: Python의 asyncio 라이브러리와 강력한 Playwright 브라우저 자동화 프레임워크를 활용하여 빠르고 비동기적인 크롤링을 수행합니다.
  • 고급 브라우저 제어: JavaScript 실행, 동적 콘텐츠 처리, 세션 관리(쿠키, 로컬 스토리지), 프록시 사용, 다양한 사용자 환경 시뮬레이션(사용자 에이전트, 지리적 위치)을 포함하여 브라우저 인스턴스에 대한 세부적인 제어를 제공합니다.
  • 오픈 소스 및 유연성: 외부 API 키 또는 유료 서비스에 의존하지 않는 완전한 오픈 소스(Apache 2.0, 출처 표기)입니다. Docker 또는 직접적인 pip 설치를 통해 배포 유연성을 제공합니다.

Crawl4AI는 데이터 접근성을 민주화하여 개발자가 웹 데이터를 빠르고 효율적으로 수집하고 형성할 수 있도록 지원하는 것을 목표로 합니다.


Crawl4AI 설치 및 설정

Crawl4AI를 실행하는 것은 간단하며, pipDocker 옵션을 모두 제공합니다.

방법 1: Pip 설치 (라이브러리 사용에 권장)

패키지 설치: 터미널을 열고 다음을 실행합니다.

# 최신 안정 버전 설치
pip install -U crawl4ai

# 또는, 최신 프리릴리스 설치 (최첨단 기능용)
# pip install crawl4ai --pre

설치 후 설정 실행: 이 중요한 단계는 필요한 Playwright 브라우저 바이너리(기본값은 Chromium)를 설치합니다.

crawl4ai-setup

확인: 진단 도구를 사용하여 설정을 확인합니다.

crawl4ai-doctor

문제 해결: crawl4ai-setup에서 문제가 발생하는 경우, 브라우저 종속성을 수동으로 설치합니다.

python -m playwright install --with-deps chromium

방법 2: Docker 배포 (API 서비스에 적합)

이미지 가져오기: 공식 Docker 이미지를 가져옵니다 (최신 태그는 GitHub에서 확인하세요).

# 예시 태그, 필요한 경우 교체
docker pull unclecode/crawl4ai:latest

컨테이너 실행: Crawl4AI 서비스를 시작하고 API를 노출합니다 (기본 포트 11235).

docker run -d -p 11235:11235 --name crawl4ai --shm-size=1g unclecode/crawl4ai:latest

이는 FastAPI 백엔드로 Crawl4AI를 실행하며, HTTP를 통해 크롤링 요청을 받을 준비가 됩니다. http://localhost:11235/playground에서 대화형 API 플레이그라운드에 접근할 수 있습니다.


Crawl4AI로 첫 번째 크롤링을 실행하는 방법

Crawl4AI는 AsyncWebCrawler를 사용하여 기본적인 크롤링을 매우 간단하게 만듭니다.

import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode

async def run_basic_crawl():
    # --- 기본 예제 ---
    print("--- 기본 크롤링 실행 중 ---")
    # 'async with'를 사용하여 자동 브라우저 시작 및 종료
    async with AsyncWebCrawler() as crawler:
        # arun() 메서드는 단일 URL에 대한 크롤링을 수행합니다.
        # CrawlResult 객체를 반환합니다.
        result = await crawler.arun(url="https://example.com")

        if result and result.success:
            # 생성된 마크다운 접근 (일반적으로 'fit_markdown')
            print("크롤링 성공!")
            # result.markdown은 원본 및 필터링된 마크다운을 모두 제공합니다.
            print(f"적합 마크다운 (처음 300자): {result.markdown.fit_markdown[:300]}...")
        else:
            print(f"크롤링 실패: {result.error_message}")

    # --- 기본 구성 예제 ---
    print("\n--- 기본 구성으로 크롤링 실행 중 ---")
    # 브라우저 동작 구성 (예: 디버깅을 위해 headful로 실행)
    browser_conf = BrowserConfig(headless=True) # 브라우저 창을 보려면 False로 설정

    # 실행별 설정 구성 (예: 캐시 우회)
    # CacheMode.ENABLED (기본값), CacheMode.DISABLED, CacheMode.BYPASS
    run_conf = CrawlerRunConfig(cache_mode=CacheMode.BYPASS)

    async with AsyncWebCrawler(config=browser_conf) as crawler:
        result = await crawler.arun(
            url="https://crawl4ai.com/", # 공식 사이트 크롤링
            config=run_conf # 실행 구성 적용
        )
        if result and result.success:
            print("크롤링 성공!")
            print(f"적합 마크다운 단어 수: {result.markdown.word_count}")
            print(f"크롤링된 URL: {result.url}")
        else:
            print(f"크롤링 실패: {result.error_message}")

if __name__ == "__main__":
    asyncio.run(run_basic_crawl())

주요 Crawl4AI 개념:

  • AsyncWebCrawler: 크롤링을 시작하는 메인 클래스입니다. async with를 사용하면 브라우저가 제대로 관리됩니다.
  • arun(url, config=None): 단일 URL을 크롤링하는 핵심 비동기 메서드입니다.
  • BrowserConfig: 브라우저 수준 설정(headless, 사용자 에이전트, 프록시)을 제어합니다. AsyncWebCrawler 초기화 중에 전달됩니다.
  • CrawlerRunConfig: 특정 크롤링 작업에 대한 설정(캐싱, 추출 전략, 타임아웃, JavaScript 실행)을 제어합니다. arun 메서드에 전달됩니다.
  • CacheMode: Crawl4AI가 캐시와 상호 작용하는 방식을 결정합니다(ENABLED, DISABLED, BYPASS). BYPASS는 개발 중 최신 데이터를 확보하는 데 유용합니다.

Crawl4AI CrawlResult 객체는 어떻게 작동하나요?

모든 성공적인 arun 또는 arun_many 호출은 하나 이상의 CrawlResult 객체를 반환하며, 이는 크롤링 중에 수집된 모든 정보를 캡슐화합니다.

CrawlResult 객체는 다음과 같은 다양한 속성을 포함합니다.

  • url: 크롤링된 최종 URL (리다이렉트 후).
  • success: 크롤링 성공 여부를 나타내는 부울 값.
  • error_message: successFalse인 경우 오류 세부 정보 포함.
  • status_code: 응답의 HTTP 상태 코드.
  • markdown: 마크다운 버전(raw_markdown, fit_markdown, word_count)을 포함하는 객체.
  • html: 페이지의 원본 HTML 콘텐츠.
  • text: 페이지에서 추출된 일반 텍스트 콘텐츠.
  • extracted_content: 구성된 추출 전략의 결과(예: JSON 문자열)를 저장합니다.
  • links: 페이지에서 발견된 링크 목록(internal, external).
  • media: 추출된 미디어(이미지, 테이블 등)에 대한 정보.
  • metadata: 페이지 메타데이터(제목, 설명 등).
  • cookies: 크롤링 후 브라우저 쿠키.
  • screenshot_path: 스크린샷이 찍힌 경우 경로.
  • network_log_path: 네트워크 HAR 파일이 캡처된 경우 경로.
  • console_log_path: 콘솔 로그 파일이 캡처된 경우 경로.

이 객체를 검사하는 것은 Crawl4AI 크롤링에서 필요한 특정 데이터에 접근하는 핵심입니다.


Crawl4AI로 AI 지원 마크다운을 생성하는 방법

Crawl4AI의 핵심 강점은 LLM에 적합한 깔끔한 마크다운을 생성하는 능력입니다.

result.markdown 속성은 다음을 포함합니다.

  • result.markdown.raw_markdown: 페이지의 주요 콘텐츠 영역을 마크다운으로 직접, 필터링되지 않은 변환 결과.
  • result.markdown.fit_markdown: 마크다운의 필터링된 버전. Crawl4AI가 일반적인 웹 클러터(메뉴, 광고, 푸터, 사이드바)를 제거하기 위해 휴리스틱 필터(예: PruningContentFilter 또는 BM25ContentFilter)를 적용하므로 LLM에 가장 유용한 경우가 많습니다.
  • result.markdown.word_count: fit_markdown의 단어 수.

Crawl4AI에서 필터링 프로세스를 사용자 정의할 수 있습니다.

import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode
# 사용자 정의를 위한 특정 전략 가져오기
from crawl4ai.content_filter_strategy import PruningContentFilter
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator

async def run_custom_markdown_crawl():
    print("\n--- 사용자 정의 마크다운 필터링으로 크롤링 실행 중 ---")

    # 특정 콘텐츠 필터로 마크다운 생성기 구성
    # PruningContentFilter는 단어 수 임계값을 기반으로 요소를 제거합니다.
    markdown_generator_with_filter = DefaultMarkdownGenerator(
        content_filter=PruningContentFilter(
            threshold=0.48, # 엄격성을 위해 임계값 조정 (0 ~ 1)
            threshold_type="fixed" # 'fixed' 또는 'relative'
            )
    )

    # 실행 구성에 이 생성기 적용
    run_conf = CrawlerRunConfig(
        cache_mode=CacheMode.BYPASS,
        markdown_generator=markdown_generator_with_filter
    )

    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(
            url="https://www.nbcnews.com/business", # 뉴스 사이트는 종종 클러터가 많습니다.
            config=run_conf
        )
        if result and result.success:
            print("크롤링 성공!")
            print(f"원본 마크다운 길이: {len(result.markdown.raw_markdown)}")
            print(f"적합 마크다운 길이: {len(result.markdown.fit_markdown)}") # 보통 더 짧습니다.
            # raw_markdown과 fit_markdown을 비교하여 필터의 효과를 확인하세요.
        else:
            print(f"크롤링 실패: {result.error_message}")

if __name__ == "__main__":
    asyncio.run(run_custom_markdown_crawl())

markdown_generator 내에서 content_filter를 조정함으로써 Crawl4AI가 fit_markdown을 생성하기 전에 콘텐츠를 얼마나 적극적으로 정리할지 제어할 수 있습니다.


Crawl4AI 딥 크롤링 사용 방법

Crawl4AI는 단일 페이지에만 국한되지 않습니다. 링크를 따라 웹사이트를 탐색하는 딥 크롤링을 수행할 수 있습니다.

adeep_crawl 메서드 (또는 crwl CLI의 --deep-crawl 플래그)를 사용합니다.

import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode

async def run_deep_crawl():
    print("\n--- 딥 크롤링 실행 중 ---")
    # 구성은 평소와 같이 전역적으로 또는 실행별로 적용할 수 있습니다.
    run_conf = CrawlerRunConfig(cache_mode=CacheMode.ENABLED)

    async with AsyncWebCrawler() as crawler:
        # adeep_crawl은 비동기 제너레이터를 반환하며, 페이지가 완료될 때마다 결과를 생성합니다.
        crawl_generator = await crawler.adeep_crawl(
            start_url="https://docs.crawl4ai.com/", # 시작 지점
            strategy="bfs", # 'bfs' (너비 우선), 'dfs' (깊이 우선), 'bestfirst'
            max_depth=2,    # 따라갈 링크 깊이 제한
            max_pages=10,   # 크롤링할 총 페이지 수 제한
            config=run_conf
        )

        # 결과가 들어오는 대로 처리
        pages_crawled = 0
        async for result in crawl_generator:
            if result.success:
                print(f"[OK] 크롤링됨: {result.url} (깊이: {result.depth}, 적합 마크다운 길이: {len(result.markdown.fit_markdown)})")
                pages_crawled += 1
            else:
                print(f"[FAIL] URL: {result.url}, 오류: {result.error_message}")

        print(f"\n딥 크롤링 완료. 성공적으로 크롤링된 총 페이지 수: {pages_crawled}")

if __name__ == "__main__":
    asyncio.run(run_deep_crawl())

Crawl4AI 딥 크롤링 매개변수:

  • start_url: 크롤링을 시작할 초기 URL.
  • strategy: 링크를 발견하고 우선 순위를 지정하는 방법(bfs, dfs, bestfirst).
  • max_depth: start_url로부터의 최대 링크 거리.
  • max_pages: 이 작업에서 크롤링할 최대 총 페이지 수.
  • include_patterns, exclude_patterns: 따라갈 URL을 필터링하는 데 정규식 패턴을 사용합니다.

Crawl4AI로 동적 콘텐츠 및 상호 작용을 처리하는 방법

최신 웹사이트는 콘텐츠를 로드하기 위해 JavaScript에 크게 의존합니다. Crawl4AI는 Playwright의 기능을 통해 이를 처리합니다.

CrawlerRunConfig를 사용하여 임의의 JavaScript를 실행하거나 특정 조건을 기다릴 수 있습니다.

import asyncio
import json
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
from crawl4ai.extraction_strategy import JsonCssExtractionStrategy # 예시

async def crawl_dynamic_page():
    print("\n--- JS 상호 작용으로 동적 페이지 크롤링 중 ---")

    # CSS 추출을 위한 예시 스키마 (대상 사이트에 맞게 조정)
    schema = { "items": { "selector": "div.product-item", "type": "list", "fields": { "title": "h2", "price": ".price" } } }
    css_extractor = JsonCssExtractionStrategy(schema)

    # 페이지에서 실행할 JavaScript (예: '더 보기' 버튼 클릭)
    # 참고: 선택자는 대상 웹사이트와 일치해야 합니다.
    js_to_run = """
    (async () => {
        const loadMoreButton = document.querySelector('button#load-more');
        if (loadMoreButton) {
            console.log('더 보기 버튼 클릭 중...');
            loadMoreButton.click();
            // 클릭 후 콘텐츠 로드를 위해 잠시 대기
            await new Promise(resolve => setTimeout(resolve, 2000));
            console.log('클릭 후 대기 완료.');
        } else {
            console.log('더 보기 버튼을 찾을 수 없습니다.');
        }
    })();
    """

    run_conf = CrawlerRunConfig(
        cache_mode=CacheMode.BYPASS,
        js_code=[js_to_run], # 실행할 JS 스니펫 목록
        wait_for_timeout=3000, # 초기 로드 및 JS 실행 후 3초 대기
        # wait_for_selector="div.newly-loaded-content", # 또는 특정 요소 대기
        extraction_strategy=css_extractor, # JS 실행 후 데이터 추출
        output_formats=['markdown', 'extracted_content']
    )

    # BrowserConfig에서 JS가 활성화되어 있는지 확인합니다 (기본적으로 활성화됨).
    browser_conf = BrowserConfig(headless=True, java_script_enabled=True)

    async with AsyncWebCrawler(config=browser_conf) as crawler:
        result = await crawler.arun(
            url="URL_OF_DYNAMIC_PAGE_HERE", # 실제 URL로 교체하세요
            config=run_conf
        )

        if result and result.success:
            print("동적 페이지 크롤링 성공!")
            print(f"적합 마크다운 길이: {len(result.markdown.fit_markdown)}")
            if result.extracted_content:
                try:
                    extracted_data = json.loads(result.extracted_content)
                    print(f"추출된 콘텐츠 미리보기: {json.dumps(extracted_data, indent=2)[:500]}...")
                except json.JSONDecodeError:
                    print(f"추출된 콘텐츠 (JSON 아님): {result.extracted_content[:500]}...")
        else:
            print(f"크롤링 실패: {result.error_message}")


if __name__ == "__main__":
    # 테스트를 위해 동적으로 콘텐츠를 로드하는 실제 URL로 교체하고 위 줄의 주석을 해제하세요.
    # asyncio.run(crawl_dynamic_page())
    print("'URL_OF_DYNAMIC_PAGE_HERE'를 실제 URL로 교체하고 위 줄의 주석을 해제하여 동적 예제를 실행하세요.")

CrawlerRunConfig의 주요 Crawl4AI 상호 작용 매개변수:

  • js_code: 페이지 컨텍스트에서 실행할 JavaScript 문자열 목록.
  • wait_for_timeout: 페이지 로드 후 및 JS 실행 후 대기할 밀리초.
  • wait_for_selector: 페이지 로드/상호 작용 완료로 간주하기 전에 기다릴 CSS 선택자.
  • page_interaction_hooks: 복잡한 상호 작용을 위한 더 고급 훅.

Crawl4AI 결론

Crawl4AI는 웹 크롤링 및 스크래핑을 위한 포괄적이고 Pythonic하며 AI 중심적인 솔루션을 제공합니다. 깔끔한 마크다운 생성, 유연한 구조화된 데이터 추출(CSS 및 LLM 기반), 동적 콘텐츠의 강력한 처리, 효율적인 비동기 작업에 중점을 두어 RAG, LLM 미세 조정 또는 웹에서 구조화된 정보가 필요한 모든 프로젝트에 탁월한 선택입니다. 명확한 API, 구성 옵션(BrowserConfig, CrawlerRunConfig), 상세한 CrawlResult 객체를 활용하여 개발자는 정교하고 효율적인 데이터 수집 워크플로우를 구축할 수 있습니다.

💡
아름다운 API 문서를 생성하는 훌륭한 API 테스트 도구를 원하십니까?

최대한의 생산성으로 개발자 팀이 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?

Apidog는 귀하의 모든 요구를 충족하며 Postman을 훨씬 더 저렴한 가격으로 대체합니다!
버튼