scraper는 첫 실행에서는 잘 동작합니다. 세 번째 실행쯤에는 403, 빈 response, CAPTCHA loop가 나옵니다. 코드는 그대로입니다. 사이트도 그대로입니다. anti-bot 시스템이 session profile을 만들고 차단하기 시작한 것입니다.
TL;DR: 대부분의 차단은 network, browser identity, behavior, session state 네 계층에서 발생합니다. fingerprints와 proxy routing을 engine 수준에서 관리하는 anti-detect browser로 시작하고, 코드는 recon, extraction, pagination, scale에 집중하게 합니다.
네 계층 모델 전체는 다음 글에서 다룹니다: 차단 없는 browser automation: 4계층 방어 스택.
코드 전에 사전 조사
바로 scraper를 쓰면 다시 만들 가능성이 큽니다. 10분만 조사해도 올바른 stack을 고를 수 있습니다.
anti-bot 시스템 확인
대상 사이트에서 DevTools를 열고 response headers를 확인합니다.
| Header | anti-bot 시스템 |
|---|---|
cf-ray, server: cloudflare |
Cloudflare Bot Management |
x-akamai-transformed |
Akamai Bot Manager |
x-datadome |
DataDome |
x-px-* headers |
PerimeterX (now HUMAN) |
| 해당 없음 | 상용 anti-bot이 없거나 자체 솔루션일 가능성 |
보호가 약한 사이트는 curl_cffi로 충분합니다. Cloudflare 사이트는 managed fingerprints가 있는 실제 browser가 필요합니다.
API가 있는지 확인
browser scraper를 만들기 전에 Network에서 XHR/Fetch를 봅니다. 많은 사이트가 JSON endpoint로 데이터를 로드합니다.
# If the site loads product data from an API endpoint
from curl_cffi import requests
response = requests.get(
"https://target-site.com/api/v2/products?category=electronics&page=1",endpoint는 빠르지만, 보호된 사이트는 실제 browser session 이후의 API call을 기대할 수 있습니다. 그때는 page를 browser로 로드하고 response를 intercept합니다.
rendering model 평가
JavaScript를 끕니다. content가 남아 있으면 HTTP로 충분합니다. 빈 페이지면 browser engine이 필요합니다.
| JS 없이 content가 보이나요? | 도구 |
|---|---|
| 예, 모두 렌더링됨 | curl_cffi or requests with TLS impersonation |
| 일부만 | curl_cffi for static parts, browser for dynamic |
| 아니요, 빈 페이지 | Full browser (Clawbrowser + Playwright/Puppeteer) |
scraping stack 선택
도구는 보호 수준과 rendering model에 따라 달라집니다. HTTP면 충분한데 full browser를 쓰면 리소스 낭비이고, 보호된 SPA에 HTTP만 쓰면 시간이 낭비됩니다.
의사결정 트리
anti-bot 없음 + server-rendered HTML: curl_cffi와 TLS impersonation을 사용합니다.
from curl_cffi import requests
response = requests.get(
"https://unprotected-site.com/products",
impersonate="chrome136"anti-bot 없음 + JavaScript-rendered: 일반 headless browser를 사용합니다.
anti-bot + server-rendered HTML: curl_cffi와 residential proxy를 사용합니다.
anti-bot + JavaScript-rendered: managed fingerprints와 residential proxy가 있는 Clawbrowser를 사용합니다.
from playwright.async_api import async_playwright
async def scrape_protected_site():
async with async_playwright() as p:
# Clawbrowser handles fingerprints, TLS and proxy at the engine levelClawbrowser는 local, free, Chromium 기반 anti-detect browser이며 managed fingerprints, proxy routing, native CDP, built-in MCP server를 제공합니다.
데이터 추출 패턴
anti-bot 계층을 지나면 안정적으로 structured data를 추출하는 일이 남습니다.
Pagination
pagination은 보통 세 가지 형태입니다.
URL 기반 pagination
async def scrape_paginated(page, base_url, max_pages=50):
all_items = []
for page_num in range(1, max_pages + 1):
await page.goto(f"{base_url}?page={page_num}")
await human_delay(2000, 4000)Infinite scroll (scroll 시 content 로드):
async def scrape_infinite_scroll(page, max_scrolls=30):
all_items = []
previous_count = 0
for _ in range(max_scrolls):"Load more" button:
async def scrape_load_more(page):
while True:
load_more = await page.query_selector('[data-testid="load-more"]')
if not load_more:
break동적 content 처리
일부 데이터는 click, accordion, hover 뒤에만 나타납니다.
async def extract_product_details(page, product_url):
await page.goto(product_url)
await human_delay(1000, 2000)
# Click "Specifications" tab to reveal hidden datashadow DOM에서 추출
shadow DOM 안의 component는 shadow root를 통해 읽어야 합니다.
# Pierce through shadow DOM to extract data
data = await page.evaluate("""
() => {
const host = document.querySelector('product-card');
const shadow = host.shadowRoot;scraping session 관리
scraper는 사람보다 훨씬 많은 page를 봅니다. session이 일관되게 보여야 합니다.
Session warming
target page로 바로 가지 말고 home, category, cookie banner를 거친 뒤 scrape합니다. behavior 계층은 차단 없는 browser automation: 4계층 방어 스택.
async def warm_session(page, site_url):
await page.goto(site_url)
await human_delay(2000, 4000)
# Accept cookies if banner appearsscale에서 profile rotation
대량 작업은 여러 Clawbrowser profiles에 나눕니다. 각 profile은 fingerprint, cookies, storage, proxy를 따로 가집니다.
import asyncio
from playwright.async_api import async_playwright
async def scrape_batch(profile_name, urls):
async with async_playwright() as p:| 규모 | 권장 방식 |
|---|---|
| < 100 pages/day | Single profile, residential proxy, 3-5s delays |
| 100-1,000 pages/day | 3-5 rotating profiles, sticky residential sessions |
| 1,000-10,000 pages/day | 10+ profiles, proxy pool, session warming |
| 10,000+ pages/day | Distributed setup, multiple Clawbrowser instances, backoff logic |
차단 진단
증상은 대개 실패한 계층을 알려줍니다.
| 증상 | 가능한 원인 | 해결 |
|---|---|---|
| 첫 request에서 차단 | IP reputation 또는 browser fingerprint | residential proxy와 anti-detect browser 사용 |
| 5-10 page 후 차단 | behavior detection 또는 session limit | 속도 낮추기, delay 추가, session warming |
| CAPTCHA on every page | Fingerprint leak | Browser is leaking automation signals, switch to managed fingerprints |
| 403 after proxy rotation | Browser fingerprint unchanged | New IP but same broken fingerprint, fix the browser layer |
| local은 성공, production은 실패 | Datacenter IP | production에 residential proxy 추가 |
| 빈 페이지 / 무한 spinner | JavaScript challenge failed | Browser can't pass Cloudflare/Akamai JS check, needs real engine |
| 수동 방문과 데이터가 다름 | Geo or locale mismatch | Proxy location doesn't match fingerprint timezone/language |
빠른 진단 script
import asyncio
from playwright.async_api import async_playwright
async def diagnose_blocking(target_url):
async with async_playwright() as p:Cloudflare 보호 사이트 scraping
Cloudflare는 TLS, JavaScript, behavior, IP reputation을 동시에 봅니다.
Cloudflare가 확인하는 것
- TLS fingerprint (JA3/JA4): ClientHello가 맞지 않으면 HTML 전에 challenge가 나옵니다.
- JavaScript execution: Turnstile은 실제 rendering engine을 요구합니다.
- IP reputation: IP reputation은 수많은 사이트에서 평가됩니다.
- Request patterns: 같은 session의 반복 request pattern은 빠르게 flag됩니다.
workflow
모든 계층을 동시에 정리합니다. TLS/JS는 anti-detect browser, IP는 residential proxy, timing은 code에서 담당합니다.
async def scrape_cloudflare_site(target_url, profile="cf-scraper"):
async with async_playwright() as p:
browser = await p.chromium.connect_over_cdp(
f"http://127.0.0.1:9222?profile={profile}"
)Cloudflare 상세 내용은 Playwright scripts가 Cloudflare에 계속 막히는 이유.
AI agent scraping
Clawbrowser MCP server를 쓰면 AI agent가 CDP로 실제 browser session을 제어합니다. fingerprints와 proxy routing은 코드에서 실행할 때와 같습니다.
전체 통합 가이드는 AI agent용 CDP browser: 개발자 가이드.
FAQ
왜 scraper가 local에서는 되는데 production에서는 실패하나요?
local은 보통 residential IP이고 production은 datacenter IP입니다. residential proxy를 추가하고 managed fingerprints를 확인합니다.
HTTP client와 browser 중 무엇을 써야 하나요?
server-rendered HTML이고 anti-bot이 없으면 HTTP면 됩니다. JavaScript rendering이나 challenge가 있으면 full browser를 씁니다.
Cloudflare 사용 여부는 어떻게 알 수 있나요?
DevTools response headers에서 cf-ray 또는 server: cloudflare를 찾습니다.
proxies 없이 scrape할 수 있나요?
보호 없는 사이트는 가능합니다. Cloudflare/Akamai 뒤나 scale 작업에서는 보통 residential proxies가 필요합니다.
탐지 없이 web scraping 시작하기
안정적인 scraping은 사전 조사, 맞는 도구, 깨끗한 browser infrastructure에서 시작합니다.
Install Clawbrowser 로 browser identity와 network 계층을 처리합니다. 설치 prompt를 clawbrowser.ai 에서 복사해 AI agent에 붙여넣으면 됩니다. setup은 2분 이내입니다.
detection model은 차단 없는 browser automation: 4계층 방어 스택. fingerprinting 상세는 Browser fingerprinting: anti-bot 시스템이 보는 20개 이상의 신호.
Continue exploring
Ask AI how Clawbrowser helps
계속 읽기
관련 글

CDP vs MCP: AI 브라우저 제어에서 어떤 것을 써야 할까
CDP는 브라우저를 제어하고 MCP는 AI를 연결합니다. AI 에이전트 브라우저 자동화에서 Chrome DevTools Protocol과 Model Context Protocol을 어떻게 구분해 쓰는지 알아봅니다.
글 읽기 →
Cursor를 CDP로 실제 브라우저에 연결하는 방법
Cursor 내장 브라우저는 격리된 webview입니다. Clawbrowser에 CDP로 연결하면 persistent profile, managed fingerprint, proxy routing을 사용할 수 있습니다.
글 읽기 →