웹 크롤링 및 LLM

Python 웹 크롤링 및 LLM 데이터 추출 완벽 가이드 (2026)

핵심 요약: 2026년 LLM 연동 python web scraping projects는 고병렬 비동기 헤드리스 브라우저(Playwright 또는 Crawl4AI)와 알고리즘 기반 DOM 노이즈 정제(SVG, 스크립트, 내비게이션 제거)를 결합한 2단계 파이프라인이 필수입니다. 구조화된 데이터 추출 시 Pydantic schemas와 Instructor를 적용하여 토큰 비용을 75~88% 절감할 수 있습니다.


1. 서론: 프론티어 LLM과 자율형 AI 에이전트 시대의 웹 크롤링

Claude 3.7 Sonnet, DeepSeek V3/R1, GPT-4o 등 최신 프론티어 모델의 컨텍스트 창이 최대 200만 토큰에 달하지만, 가공되지 않은 원시 HTML을 그대로 모델에 입력하는 것은 심각한 비용 낭비입니다.

과거 scrape website python 작업은 requestsBeautifulSoup, Scrapy가 표준이었으나, 현재 웹은 React/Next.js 기반 SPA와 Cloudflare WAF 방어막으로 둘러싸여 있습니다.

이에 따라 웹 크롤링의 목적은 단순한 DB 저장을 넘어, DOM 노이즈 제거, 마크다운 변환, Pydantic schemas 기반의 엄격한 JSON 추출로 진화했습니다.


2. 프레임워크 비교: BeautifulSoup vs Scrapy vs Playwright vs Crawl4AI

평가 항목 BeautifulSoup4 + Requests Scrapy (Twisted/AsyncIO) Raw Playwright (Async Python) Crawl4AI (v0.9.x+)
주요 용도 간단한 스크립트 및 정적 HTML 대규모 분산 크롤링 동적 SPA 및 복잡한 JS 상호작용 AI 에이전트 및 RAG 데이터 추출
JS 렌더링 미지원 미지원 (Scrapy-Playwright 필요) 완벽 지원 (Chromium, WebKit) LLM 최적화 Chromium
처리량 ~15-25 req/s /워커 ~150-300 req/s /스파이더 ~5-12 pages/s /16GB RAM ~25-45 pages/s (컨텍스트 재사용)
메모리 사용량 최소 (~40MB) 낮음 (~120MB) 높음 (150-350MB/컨텍스트) 중간 (~80-140MB/탭)
마크다운 변환 외부 라이브러리 필요 파이프라인 수동 구축 수동 연동 내장 LLM 최적화 마크다운
DOM 노이즈 정제 수동 태그 제거 코드 수동 XPath/CSS 규칙 CDP 기반 수동 평가 내장 PruningContentFilter
봇 차단 우회 취약 (UA 헤더만) 미들웨어 프록시 연동 우수 (playwright-stealth) 내장 스텔스 및 TLS 핑거프린트
Pydantic 연동 미지원 ItemLoaders 미지원 네이티브 Pydantic 추출 지원

3. LLM 크롤링 경제학: DOM 노이즈 정제 및 토큰 절감

웹 페이지의 85% 이상은 CSS 클래스, Base64 이미지, 추적 스크립트로 구성되어 있습니다.

일 50,000개 페이지 처리 비용 분석 (GPT-4o $2.50/1M 토큰 기준)

  • 원시 HTML 일일 토큰: 50,000 × 55,000 = 27.5억 토큰
  • 정제된 마크다운 토큰: 50,000 × 4,200 = 2.1억 토큰
  • 일일 비용 절감액: (2,750 - 210) × $2.50 = $6,350.00 /일
  • 월간 비용 절감액: $190,500.00 /월

4. 프로덕션 구현: Async Playwright + Selectolax

# clean_scraper.py
import asyncio
from playwright.async_api import async_playwright
from selectolax.parser import HTMLParser
import markdownify

async def scrape_clean_markdown(url: str) -> str:
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True, args=["--no-sandbox"])
        page = await browser.new_page()
        await page.goto(url, wait_until="networkidle", timeout=30000)
        html = await page.content()
        await browser.close()

    parser = HTMLParser(html)
    for tag in ["script", "style", "svg", "nav", "footer", "header", "noscript"]:
        for node in parser.css(tag):
            node.decompose()

    main = parser.css_first("main, article, #content") or parser.css_first("body")
    return markdownify.markdownify(main.html if main else parser.html, heading_style="ATX")

5. Crawl4AI를 통한 고성능 파이프라인

# crawl4ai_pipeline.py
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
from crawl4ai.content_filter_strategy import PruningContentFilter

async def run_crawl4ai(url: str) -> str:
    async with AsyncWebCrawler(config=BrowserConfig(headless=True)) as crawler:
        config = CrawlerRunConfig(
            cache_mode=CacheMode.BYPASS,
            content_filter=PruningContentFilter(threshold=0.48),
            wait_until="networkidle"
        )
        res = await crawler.arun(url=url, config=config)
        return res.markdown

6. Pydantic 및 Instructor 구조화 JSON 추출

# pydantic_extractor.py
import os
from typing import List, Optional
from pydantic import BaseModel, Field
import instructor
from openai import OpenAI

class Specification(BaseModel):
    feature: str = Field(description="기능 명칭")
    supported: bool = Field(description="지원 여부")

class ExtractedProduct(BaseModel):
    name: str
    price_usd: Optional[float] = None
    specs: List[Specification]

def extract_structured(clean_md: str) -> ExtractedProduct:
    client = instructor.from_openai(OpenAI(api_key=os.environ["OPENAI_API_KEY"]))
    return client.chat.completions.create(
        model="gpt-4o-mini",
        response_model=ExtractedProduct,
        messages=[{"role": "user", "content": clean_md}],
        temperature=0.0
    )

7. WAF 방어 및 프록시 회전 전략

curl_cffi를 사용하여 Chrome 124 TLS 핸드셰이크를 모방하면 브라우저 없이도 WAF를 우회할 수 있습니다:

# stealth_requester.py
from curl_cffi import requests

def fetch_stealth(url: str, proxy: str = None) -> str:
    proxies = {"http": proxy, "https": proxy} if proxy else None
    return requests.get(url, impersonate="chrome124", proxies=proxies, timeout=15).text

8. 100,000 페이지 처리 비용 종합 비교

비용 항목 순수 Playwright (HTML) Playwright + Selectolax Crawl4AI 비동기 엔진 Firecrawl 클라우드
인프라 비용 $48.00 $22.00 $16.00 $0.00
주거용 프록시 비용 $120.00 $32.00 $30.00 포함
LLM 추론 비용 $13,750.00 $1,050.00 $975.00 $825.00
총 비용 $13,918.00 $1,104.00 $1,021.00 $1,024.00

9. 결론 및 엔지니어링 권고사항

  1. 계층적 접근: 가벼운 정적 페이지는 curl_cffi, 동적 SPA는 Crawl4AI를 선택합니다.
  2. DOM 정제 필수: 원시 HTML 입력은 지양하고 최소 80% 이상의 토큰 압축률을 유지합니다.
  3. Pydantic 스키마 검증: Instructor를 통해 데이터 무결성을 보장합니다.
  4. 크롤링과 추론의 분리: 비동기 태스크 큐(Celery/ARQ)를 두어 안정성을 극대화합니다.
← 전체 아티클
0 / 4