52.2k 스타·5k 포크의 Python 웹 스크래핑 신예. CSS 셀렉터가 어제 잘 되다가 오늘 깨졌을 때, adaptive=True 한 줄로 유사도 알고리즘이 변경된 요소를 자동으로 다시 찾아준다. Cloudflare Turnstile/Interstitial을 그냥 통과하고, BS4보다 ~1679배 빠른 lxml 기반 파서, Scrapy 스타일 Spider, 내장 MCP 서버까지 한 라이브러리에 묶었다.
Scrapling은 한 줄 요청에서 풀스케일 크롤링까지 다루는 적응형(adaptive) 웹 스크래핑 프레임워크다. BS4·Scrapy·Playwright가 각자 하던 일을 하나의 일관된 API로 통합하고, 거기에 "요소 추적(Smart Element Tracking)"이라는 새 레이어를 얹었다.
핵심 아이디어는 단순하다 — 처음 셀렉터로 요소를 찾았을 때 그 요소의 "지문(서명)"을 저장해두고, 나중에 사이트 구조가 바뀌어 셀렉터가 깨지면 저장된 지문과 가장 비슷한 요소를 자동으로 다시 찾는다.
친구네 집에 자주 갔는데 어느 날 가구 배치가 바뀌었다. 일반 스크래퍼는 "내가 알던 그 자리에 소파가 없네? 못 찾겠다" 하고 멈춘다. Scrapling은 "소파는 가죽이고 3인용이었지" 하고 기억해서, 바뀐 자리에서도 소파를 알아본다. "위치"가 아니라 "특징"으로 요소를 추적하는 게 핵심.
3가지 Fetcher(HTTP / Stealthy / Dynamic)와 Scrapy 스타일 Spider 프레임워크, 그리고 내장 MCP 서버까지 갖춰서 한 라이브러리로 단발 스크래퍼부터 풀스케일 크롤러, AI 에이전트 도구까지 커버한다. Karim Shoair가 2024년부터 단독 메인테이너로 끌어왔고, 2026년 6월 기준 v0.4.9까지 47번 릴리즈했다.
.product에서 .product-card로 바뀌어도 동작한다. Scrapling은 첫 매칭 때 요소의 부모/자식/형제·속성·텍스트를 저장해 "프로파일"을 만든 뒤, 다음 실행에서 유사도가 가장 높은 후보를 고른다.웹 스크래퍼를 운영해본 사람이라면 알고 있다 — 사이트가 디자인을 한번 바꾸면 그날부터 셀렉터가 우수수 깨진다. CSS 클래스명만 바뀌어도 다 다시 짜야 한다.
Scrapling은 첫 매칭 때 auto_save=True로 요소 정보를 저장하고, 다음 실행 때 adaptive=True를 켜면 알아서 비슷한 요소를 다시 찾는다. 유지보수 비용을 거의 0으로 만드는 발상이다.
products = p.css('.product', auto_save=True) # 1차 실행: 요소 지문 저장
# ... 며칠 후 사이트 구조 변경 ...
products = p.css('.product', adaptive=True) # 2차 실행: 자동 재탐색
대부분의 상업 사이트는 Cloudflare·DataDome·PerimeterX 같은 봇 차단 시스템 뒤에 있다. requests나 일반 Playwright로는 첫 페이지부터 막힌다.
Scrapling의 StealthyFetcher는 Patchright(스텔스 Playwright 포크) + browserforge(브라우저 지문 위조) + Apify 지문 데이터셋을 결합해서 Cloudflare Turnstile을 solve_cloudflare=True 한 줄로 통과한다.
벤치마크 결과(5000개 중첩 요소 텍스트 추출, 100회 평균):
| 라이브러리 | 시간 (ms) | Scrapling 대비 |
|---|---|---|
| Scrapling | 2.02 | 1.0× |
| Parsel/Scrapy | 2.04 | 1.01× |
| Raw lxml | 2.54 | 1.26× |
| PyQuery | 24.17 | ~12× |
| Selectolax | 82.63 | ~41× |
| MechanicalSoup | 1549.71 | ~767× |
| BS4 (lxml) | 1584.31 | ~784× |
| BS4 (html5lib) | 3391.91 | ~1679× |
JSON 직렬화도 orjson 사용으로 표준 라이브러리 대비 10배 빠르다.
pip install "scrapling[ai]" 한 줄이면 Model Context Protocol(MCP) 서버가 함께 설치된다. Claude/Cursor 같은 AI 코딩 도구에 등록하면, AI가 직접 사이트를 긁어와서 파싱한 결과만 받는다.
핵심 가치: AI에게 HTML 1MB를 통째로 보내는 게 아니라, Scrapling이 먼저 셀렉터로 잘라낸 깔끔한 데이터만 전달해서 토큰 비용을 대폭 줄인다. Anthropic 공식 에이전트 스킬(agent-skill/ 폴더), OpenClaw Skill도 번들로 제공.
Scrapy는 강력하지만 프로젝트 구조·미들웨어·파이프라인·설정 파일이 복잡하다. Scrapling Spider는 한 파일에 Spider 클래스 하나만 정의하면 끝. 동시성·throttling·robots.txt 준수·pause/resume·스트리밍을 다 내장.
이전: 셀렉터 깨질 때마다 사람이 수동 패치 → 운영 인력 비용 ↑ / 봇 차단 우회 노하우는 회사 비밀 / 풀크롤링은 Scrapy 학습 필수.
Scrapling: adaptive=True 한 줄 + StealthyFetcher 기본 옵션 + Spider 한 파일. 1인 개발자가 운영 가능한 스크래핑 인프라를 만든다.
| 패키지 | 버전 | 역할 |
|---|---|---|
lxml | ≥6.1.1 | C 기반 XML/HTML 파서. Scrapling 속도의 90%를 책임진다. |
cssselect | ≥1.4.0 | CSS 셀렉터를 XPath로 변환. .product::text 같은 pseudo-element도 처리. |
orjson | ≥3.11.8 | Rust 기반 JSON 직렬화. 표준 json 대비 10배 빠름. |
tld | ≥0.13.2 | Top-Level Domain 파싱. 도메인/서브도메인 차단에 사용. |
w3lib | ≥2.4.1 | Scrapy 팀의 URL/HTML 헬퍼. |
typing_extensions | — | Python 3.10에서도 최신 타입 힌트 사용. |
pip install "scrapling[fetchers]")| 패키지 | 역할 |
|---|---|
curl_cffi ≥0.15.0 | curl-impersonate 바인딩. Chrome/Firefox의 TLS 지문(JA3/JA4)을 그대로 흉내내서 HTTP 레벨에서 봇 탐지 우회. HTTP/3도 지원. |
playwright 1.60.0 | Microsoft의 브라우저 자동화 표준. Chromium·Firefox·WebKit 제어. |
patchright 1.60.1 | Playwright의 스텔스 패치 포크. navigator.webdriver 같은 탐지 시그널 제거. |
browserforge ≥1.2.4 | 실제 사용자 통계에서 추출한 헤더/지문 데이터로 위장된 브라우저 핑거프린트 생성. |
apify-fingerprint-datapoints ≥0.13.0 | Apify 회사가 수집한 실 브라우저 지문 데이터셋. |
msgspec ≥0.21.1 | 초고속 직렬화 라이브러리(Rust 기반). Pydantic 대안. |
anyio ≥4.13.0 | asyncio/trio 추상화. Scrapling이 둘 다 지원하기 위해 사용. |
protego ≥0.6.0 | Scrapy 팀의 robots.txt 파서. Disallow/Crawl-delay 준수. |
click ≥8.3.0 | CLI 프레임워크. scrapling shell 등 명령어. |
| 패키지 | 역할 |
|---|---|
mcp ≥1.27.0 | Model Context Protocol 공식 SDK. AI 에이전트가 Scrapling을 도구로 호출할 수 있게. |
markdownify ≥1.2.0 | HTML → Markdown 변환. scrapling extract get url out.md가 이걸 쓴다. |
IPython ≥8.37 | 대화형 셸. scrapling shell로 즉석에서 사이트 탐색. |
python:3.12-slim-trixie 베이스 + Playwright Chromium + 모든 extras 자동 빌드. GHCR과 DockerHub 동시 배포..readthedocs.yaml). Zensical 문서 빌더(zensical.toml).server.json에 PyPI(uvx)와 OCI(Docker) 양쪽 배포 방식 명세 → MCP 레지스트리에서 자동 인덱싱.requests(Python urllib3)와 진짜 Chrome은 지문이 다르게 나와서 봇 차단 시스템이 이를 보고 거른다. curl_cffi는 커널 레벨에서 Chrome의 TLS 스택을 복제해서 JA3 검사를 통과시킨다.Scrapling을 다른 스크래퍼와 결정적으로 차별화하는 부분이다. 셀렉터를 처음 실행할 때 auto_save=True를 주면, 매칭된 요소의 "프로파일"이 디스크에 저장된다.
저장되는 정보:
div, a 등)다음 실행에서 adaptive=True를 주면, Scrapling은 이렇게 동작한다:
"AI가 매번 추론"하는 게 아니라, 결정적 셀렉터를 1차로 시도하고 실패할 때만 유사도 검색으로 폴백한다. 정상 상황에서는 일반 lxml과 같은 속도를 유지하고, 사이트가 바뀐 날에만 비싼 연산을 수행하는 "비용을 사건과 결합한 설계".
같은 인터페이스로 점점 강한 위장을 선택할 수 있다.
| Fetcher | 엔진 | 속도 | 스텔스 | JS 실행 | 적합 케이스 |
|---|---|---|---|---|---|
Fetcher | curl_cffi | ★★★★★ | ★★★ | × | API/정적 HTML, 대량 요청 |
DynamicFetcher | playwright | ★★ | ★★★ | ○ | JS 렌더링 필요한 SPA |
StealthyFetcher | patchright + browserforge | ★★ | ★★★★★ | ○ | Cloudflare/DataDome 보호 사이트 |
같은 fetch() API로 3종을 바꿔낄 수 있어서, "먼저 빠른 Fetcher로 시도하다 차단되면 StealthyFetcher로 폴백" 같은 전략이 한 파일에 깔끔하게 들어간다.
Scrapy에는 없는 Scrapling만의 패턴. 한 Spider 안에서 URL 유형에 따라 다른 세션으로 라우팅한다.
class MultiSessionSpider(Spider):
def configure_sessions(self, manager):
manager.add("fast", FetcherSession(impersonate="chrome"))
manager.add("stealth", AsyncStealthySession(headless=True), lazy=True)
async def parse(self, response):
for link in response.css('a::attr(href)').getall():
if "protected" in link:
yield Request(link, sid="stealth") # 보호 페이지 → 스텔스
else:
yield Request(link, sid="fast") # 일반 페이지 → 빠른 HTTP
lazy=True: 무거운 브라우저 세션은 처음 요청이 들어왔을 때만 spin-up. 보호 페이지가 없는 도메인이면 브라우저는 아예 안 뜬다.
Scrapy의 JOBDIR과 비슷하지만 더 단순한 API. crawldir="./crawl_data"를 주면:
crawldir로 재시작하면 멈춘 시점부터 재개장시간 크롤(수일~수주)에 필수. 서버 재부팅·네트워크 단절·디버깅 중단에 강하다.
parse() 로직을 고치면서 매번 실제 서버에 요청 보내면 차단 위험 + 느림. Dev 모드는 첫 실행 응답을 디스크에 캐시했다가 이후 실행에선 캐시를 사용. Scrapy의 HTTPCACHE_ENABLED를 기본 워크플로로 승격한 것.
async for item in spider.stream():
# 결과가 도착하는 순서대로 즉시 받음 (전체 크롤 끝나기 전에)
await pipeline.send(item)
UI/대시보드/실시간 인덱싱 파이프라인에 결과를 흘려보낼 때 사용. 일반 모드는 크롤 끝나야 결과 모음을 반환하지만, 스트리밍 모드는 도착하는 대로 yield.
scrapling/__init__.py — 공개 API 한 페이지로 보기 (가장 먼저 읽을 것)scrapling/parser.py — 적응형 매칭 알고리즘. 58KB 단일 파일에 핵심 로직이 다 들어있다. 코드 리딩에서 가장 보람 있는 부분.scrapling/fetchers/ + engines/ — 3종 Fetcher가 어떻게 동일 인터페이스를 유지하는지scrapling/spiders/ — Spider/SessionManager/Checkpoint 구현benchmarks.py — "왜 빠른가"를 수치로 보기Dockerfile — uv 캐시 마운트 패턴 학습 (실무에 바로 적용 가능한 베스트 프랙티스)코드베이스가 마치 "스크래퍼 한 채를 통째로 지은 단독주택" 같다. parser.py 한 파일이 거실이고(여기서 다 일어남), fetchers/는 주방·욕실 같은 기능 공간, spiders/는 마당. Scrapy처럼 마이크로커널·미들웨어·확장 시스템 같은 게 없어서 "메서드 정의 찾으려면 IDE 점프 한 번이면 끝"이다.
lxml은 빠르지만 API가 투박하다. Scrapling은 lxml을 베이스로 깔고 BS4 스타일·Parsel 스타일·CSS pseudo-element까지 같이 노출한다. parser.py를 읽으면:
etree·HTMLParser·XPath를 어떻게 래핑하는지cssselect 활용법::text, ::attr(href) 같은 pseudo-element를 어떻게 직접 구현했는지실습: lxml로 직접 작은 셀렉터를 짜본 뒤, Scrapling이 어떻게 그 위에 추상화를 얹는지 비교.
일반 requests로 막히던 사이트가 curl_cffi.get(url, impersonate="chrome") 한 줄로 통과되는 마법. 이게 어떻게 가능한지 추적해보면 네트워크 보안 지식이 풍부해진다.
실습: 같은 사이트에 requests·httpx·curl_cffi로 각각 요청 보내고 응답 차이 관찰.
Playwright는 강력하지만 navigator.webdriver=true 같은 자동화 시그널이 그대로 남는다. patchright는 어떤 시그널을 어떻게 패치하는지 코드로 학습할 수 있다.
Scrapy를 다 공부하기엔 부담이지만, Spider/Request/Response/Pipeline의 본질은 scrapling/spiders/를 읽으면 1~2시간이면 잡힌다. 동시성 제어·throttling·재시도 로직이 어떻게 구현되는지가 그대로 노출.
비동기 컨텍스트 매니저(async with), 세션 풀, 타임아웃 처리, asyncio.gather 사용 패턴. "비동기 코드를 동기 컨텍스트에서도 쓸 수 있게 만드는" FetcherSession의 듀얼 인터페이스 구현이 특히 볼만하다.
scrapling[ai]의 MCP 서버 코드는 "기존 Python 라이브러리에 MCP 인터페이스 얹는 법"의 표준 예제. 도구 명세·파라미터·반환 타입을 어떻게 정의하는지, stdio transport와 HTTP transport(EXPOSE 8000) 양쪽을 어떻게 지원하는지 학습.
Dockerfile의 캐시 마운트 패턴은 그대로 가져다 다른 Python 프로젝트에 적용 가능:
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --no-install-project --all-extras --compile-bytecode
COPY . .
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --all-extras --compile-bytecode
의존성을 먼저 설치하고(레이어 캐시), 그 다음에 소스 복사. 코드만 바뀌면 의존성 설치 단계는 캐시 hit.
pyproject.toml에 optional-dependencies 트리(fetchers → ai/shell → all)를 어떻게 구성했는지, classifiers·MyPy·Pyright 설정·zip-safe 플래그까지 — 그대로 베껴서 자기 프로젝트에 적용 가능한 템플릿이다.
scrapling install로 Chromium까지 받으면 ~500MB# 1) 코어만 (파서만 필요할 때)
pip install scrapling
# 2) Fetcher까지 (HTTP 요청·브라우저 자동화 포함)
pip install "scrapling[fetchers]"
scrapling install # Playwright 브라우저 + 시스템 의존성
# 3) 전부 (AI/MCP + 인터랙티브 셸 + Fetcher)
pip install "scrapling[all]"
scrapling install
# 4) Docker
docker pull pyd4vinci/scrapling
# 또는
docker pull ghcr.io/d4vinci/scrapling:latest
저자가 README에 명시: "교육·연구 목적용. 사용자는 현지 데이터 수집·개인정보 법규를 준수할 책임이 있고, 항상 대상 사이트의 ToS와 robots.txt를 존중하라." Cloudflare 우회 기능이 강력한 만큼, 운영 환경에서 쓸 때는 (1) 대상 사이트의 ToS 확인, (2) robots.txt 준수, (3) 합리적인 throttling, (4) 개인정보 수집 시 GDPR/PIPA 적합성을 반드시 점검할 것.
1) pip install "scrapling[fetchers]" + scrapling install
2) Fetcher.get()로 첫 페이지 가져오기
3) .css('.quote')로 인용구 추출, 각 인용구에서 .text::text·.author::text·.tag::text 뽑기
4) 다음 페이지 링크 따라가서 10페이지까지 반복
5) orjson으로 결과를 quotes.json으로 저장
학습 목표: 기본 fetch + CSS 셀렉터 + 페이지네이션 패턴 익히기.
1) 간단한 HTML 파일 2개 만들기 — v1.html(<div class="product">), v2.html(<div class="product-card">)
2) v1에 auto_save=True로 셀렉터 매칭 → 지문 저장
3) v2에 동일 셀렉터 + adaptive=True로 매칭 → 자동 재탐색 동작 확인
4) 클래스명 외에 텍스트·구조·속성이 점점 더 달라지는 케이스(v3, v4...)를 만들고 어느 지점에서 매칭이 실패하는지 측정
5) 결과를 표로 정리
학습 목표: 유사도 매칭의 강점·한계를 손으로 확인. Scrapling 마법이 어디까지 가능한지 직감 잡기.
1) 먼저 일반 Fetcher.get()으로 시도 → 차단 확인
2) DynamicFetcher로 시도 → 여전히 차단
3) StealthyFetcher.fetch(url, solve_cloudflare=True)로 통과
4) DevTools/네트워크 탭에서 일반 Playwright vs Patchright의 헤더 차이 비교
5) 결과를 블로그 글이나 노트로 정리
학습 목표: 봇 차단 시스템의 동작 원리 + 우회 방법 + 윤리적 경계 이해.
1) Spider 클래스 정의 (start_urls = HN top stories API)
2) concurrent_requests=20, download_delay=0.5로 thro+ttling
3) crawldir="./hn_crawl" 옵션으로 시작
4) 1000개쯤 진행됐을 때 Ctrl+C → 상태 저장 확인
5) 같은 명령으로 재시작 → 멈춘 시점부터 이어지는지 검증
6) 결과를 JSONL로 export하고 분석
학습 목표: 장시간 크롤링 운영 패턴, 체크포인트 시스템 이해.
1) pip install "scrapling[ai]"
2) Claude Desktop/Cursor의 MCP 설정에 Scrapling 서버 추가 (uvx scrapling mcp 또는 docker run ... scrapling mcp)
3) AI에게 자연어로 요청: "trendshift.io 메인의 상위 10개 트렌딩 레포 이름과 별 개수를 표로 정리해줘"
4) 어떤 도구를 어떤 인자로 호출했는지 로그 확인
5) 동일 요청을 직접 Scrapling 코드로 짜보고 토큰 비용/속도 비교
6) Claude Code Agent Skill(agent-skill/SKILL.md) 형식으로 자기만의 워크플로 작성
학습 목표: MCP 도구 등록·호출 패턴, "토큰 효율적인" AI 에이전트 설계.
etree.HTML()·XPath·iterparse까지. Scrapling을 빼고 lxml만으로 같은 작업 짜보기.::text·::attr·contains()·following-sibling 익히기.find·find_all·CSS 셀렉터 지원, 그리고 왜 BS4가 1000배 느린지.requests → httpx → curl_cffi 단계별 차이impersonate="chrome"이 뒤에서 뭘 하는지page.goto·page.waitForSelector·page.evaluatenavigator.webdriver·플러그인·언어·시간대·WebGL·캔버스 지문scrapling/spiders/)와 비교 → "Scrapy의 본질을 어떻게 80% 코드로 잡아냈나"agent-skill/) — SKILL.md로 자기 도메인의 스크래핑 노하우를 캡슐화with 블록으로 자원 자동 정리. FetcherSession은 동기/비동기 양쪽에서 동작.scrapling.parser.Selector. 파싱된 HTML 트리의 노드를 감싸는 객체. .css()·.xpath()·.find_all()·.find_similar()·.next_sibling·.parent 등 풍부한 API. lxml 노드를 직접 다룰 필요 없게 해주는 추상화.auto_save는 매칭 결과를 디스크에 지문으로 저장. adaptive는 다음 실행 때 셀렉터가 깨졌으면 저장된 지문으로 유사한 요소 자동 검색. 한 쌍으로 사용.StealthyFetcher 옵션. Cloudflare Turnstile/Interstitial 페이지를 자동 감지하고 통과. JS 챌린지 완료 + 쿠키 저장까지 한 번에.name·start_urls·concurrent_requests·async parse()로 정의. yield Request(url)로 추가 요청, yield dict로 결과 항목 산출.result.items로 끝난 후 한꺼번에.parse() 로직 디버깅을 빠르게.uvx scrapling mcp로 stdio 기반 MCP 서버 실행..title::text는 매칭된 요소의 직접 텍스트, a::attr(href)는 href 속성값. Scrapling이 이걸 지원./robots.txt에 명시된 크롤러 정책. Disallow·Crawl-delay·Request-rate. Spider 옵션 robots_txt_obey=True로 자동 준수, Protego 라이브러리가 파싱.block_resources) 또는 알려진 광고/추적 도메인 ~3500개 자동 차단. 속도와 대역폭 절감.py.typed가 패키지에 있으면 IDE/타입 체커가 "이 패키지는 타입 힌트 완비"로 인식. Scrapling은 Pyright + MyPy 양쪽으로 매 변경마다 자동 검사.scrapling extract get URL out.md로 코드 없이 URL→마크다운/텍스트/HTML 추출. scrapling shell은 IPython 기반 인터랙티브 환경 (curl 명령을 Scrapling 코드로 변환하는 단축키 등).uv sync로 락 파일 기반 설치.json보다 ~10배 빠름. Scrapling 내부의 result.items.to_json/to_jsonl 모두 orjson.navigator.webdriver 제거, 자동화 시그널 차단, 인간형 마우스 패턴 등. 표준 Playwright API와 호환되면서 봇 탐지를 회피.impersonate="chrome" 한 인자로 JA3 우회.asyncio.gather로 수십~수백 요청 동시 실행. 풀크롤러에선 필수.docker pull pyd4vinci/scraplingdocker pull ghcr.io/d4vinci/scrapling:latest