웹 사이트 스크래핑에 3일을 썼는데, AI는 10분 만에 해냈다
요약
전통적인 웹 스크래핑 방식(BeautifulSoup, Selenium 등)이 동적 HTML과 안티 봇 로직으로 인해 실패했을 때, AI 비전 모델을 활용해 문제를 해결한 사례를 다룹니다. 스크린샷을 비전 모델에 전달하여 구조화된 JSON 데이터를 추출하는 방식의 효율성을 강조합니다.
핵심 포인트
- 동적 클래스명과 Cloudflare 차단 등 전통적 스크래핑의 한계
- 비전 모델을 활용한 스크린샷 기반 데이터 추출 방식의 유효성
- 복잡한 HTML 파싱 대신 시각적 정보를 통한 구조화된 JSON 생성
- AI를 활용한 데이터 추출 프로세스의 시간 단축 효과
저는 수년 동안 웹 스크래퍼 (web scrapers)를 만들어 왔습니다. BeautifulSoup, Selenium, Playwright — 저는 제가 모든 것을 다 겪어봤다고 생각했습니다. 하지만 지난달, 저는 프로젝트 전체를 거의 포기할 뻔할 정도로 매우 완고한 벽에 부딪혔습니다.
전통적인 스크래핑 (scraping) 방식이 왜 저를 실망시켰는지, 그리고 왜 제가 이제 AI를 데이터 추출 (data extraction) 도구 상자에서 정당한 도구로 취급하는지에 대한 이야기입니다.
문제: 스크래퍼를 싫어하는 사이트
한 고객이 패션 소매업체로부터 제품 목록을 추출해 달라고 요청했습니다. 그리 대단한 기술이 필요한 일은 아니죠, 그렇지 않나요? 페이지를 열어보니 평소 보던 것들이 보였습니다: div.product-card, price, title, image와 같은 CSS 클래스들 말이죠. 저는 빠르게 BeautifulSoup 스크립트를 작성하여 실행했지만... 아무것도 나오지 않았습니다.
HTML이 완전히 동적 (completely dynamic) 이었습니다. 모든 제품 카드는 JavaScript에 의해 렌더링되었고, 페이지를 새로고침할 때마다 CSS 클래스 이름이 바뀌었습니다 (아마도 CSS modules나 Tailwind의 purge를 사용하는 React 앱일 것입니다). 설상가상으로, 몇 번의 요청 후에 헤드리스 브라우저 (headless browsers)를 차단하는 Cloudflare 챌린지까지 추가되어 있었습니다.
제가 시도했던 것들 (그리고 실패한 것들)
- requests + BeautifulSoup를 이용한 정적 파싱 (Static parsing) — 빈 div만 반환되었습니다. 전형적인 사례죠.
- Chrome을 이용한 Selenium — 5~10페이지 정도는 작동했지만, 그 후 Cloudflare가 제 IP를 차단했습니다. 스텔스 (stealth) 설정과 프록시 (proxies)를 사용했지만 여전히 차단되었습니다.
- stealth 플러그인을 사용한 Playwright — 결과는 같았습니다. 사이트의 안티 봇 (anti-bot) 로직이 매우 공격적이었습니다.
- 스크린샷에 대한 OCR — 렌더링된 페이지를 읽기 위해 Tesseract를 시도했습니다. 정확도가 형편없었습니다 (화려한 폰트, 겹쳐진 요소들).
- 제3자 스크래핑 API (Third-party scraping APIs) — 몇 가지를 시도해 보았지만, 비용이 너무 많이 들거나 불완전한 데이터를 반환했습니다.
3일 동안 디버깅을 한 끝에, 저는 고객에게 불가능하다고 말하려던 참이었습니다.
우연한 발견
친구에게 하소연을 하던 중, 그는 PDF 인보이스 (invoices)에서 데이터를 추출하기 위해 AI를 사용하고 있다고 언급했습니다. “웹 페이지에도 시도해 보는 게 어때?” 그가 말했습니다. “스크린샷을 찍어서 비전 모델 (vision model)에 보내고, JSON을 반환하라고 요청해 봐.”
저는 회의적이었습니다. 텍스트 요약 (text summarization)을 위해 GPT-4를 사용해 본 적은 있지만, 구조화된 데이터 (structured data)를 위해서라고요? 게다가 느리고 비싸지 않을까요?
하지만 저는 절박했습니다. 그래서 간단한 스크립트를 작성했습니다:
import base64
from openai import OpenAI
from playwright.sync_api import sync_playwright
...
한 번 실행해 보았습니다. 10초 후, 제품명, "$49.99" 형식으로 포맷팅된 가격, 재고 상태(심지어 "장바구니에 담기" 버튼을 읽고 "재고 있음"이라고 추론했습니다)가 포함된 완벽한 JSON 배열을 얻었습니다. 믿기지 않았습니다.
이것이 작동하는 이유 (그리고 마법이 아닌 이유)
핵심 통찰은 다음과 같습니다: 현대의 비전 모델 (vision models)은 렌더링된 텍스트를 읽고 레이아웃 (layout)을 이해할 수 있으며, 이는 거의 인간과 비슷한 수준입니다. 이 모델들은 클래스 이름 (class names), 동적 ID (dynamic IDs), 또는 안티 봇 (anti-bot) 스크립트에 신경 쓰지 않습니다. 이들은 사용자가 보는 것과 정확히 똑같은 것을 봅니다.
제 경우, 해당 사이트는 JavaScript 비중이 높았지만 최종적으로 렌더링된 페이지는 깔끔했습니다. 모델은 제가 "제품 정보를 추출하라"는 프롬프트 (prompt)를 준 것만으로 내비게이션 바, 광고, 푸터를 쉽게 무시했습니다.
트레이드오프 (솔직하게 말하자면)
이 접근 방식이 만능 해결책 (silver bullet)은 아닙니다. 제가 배운 점은 다음과 같습니다:
- 비용 (Cost): GPT-4o를 사용할 경우 스크린샷 하나와 프롬프트 하나당 약 $0.01–$0.03이 듭니다. 제품 1,000개 기준으로는 $10-30입니다. 수동 추출보다는 저렴하지만, (제대로 작동한다는 가정하에) 전통적인 스크래퍼 (scraper)보다는 비쌉니다.
- 지연 시간 (Latency): 페이지당 5~15초가 소요됩니다. 실시간 스크래핑을 하기에는 너무 느리지만, 배치 작업 (batch jobs)에는 적합합니다.
- 정확도 (Accuracy): 완벽하지는 않습니다. 가끔 모델이 가격을 환각 (hallucinate) 합니다 (실제로는 $19.87인데 "$19.99"라고 출력하는 경우). 명백한 오류를 확인하기 위해 사후 처리 검증 (post-processing validation) 단계를 추가해야 했습니다.
- 개인정보 보호 (Privacy): 스크린샷을 OpenAI 서버로 전송하는 것은 일부 고객사가 허용하지 않을 수 있습니다. 대안도 존재합니다 (LLaVA나 Qwen-VL 같은 로컬 모델이 있지만, 정확도는 더 낮습니다).
- 속도 제한 (Rate limits): OpenAI에는 제한이 있습니다. 저는 데이터를 배치로 나누고 지연 시간을 추가해야 했습니다.
언제 이 방식을 사용해야 할까요?
저는 이제 다음과 같은 경우에만 이 기술을 사용합니다:
- 전통적인 파싱 (parsing)이 불가능할 때 (동적 CSS, 무거운 JS, 스크린샷은 허용하지만 DOM 접근은 차단하는 안티 봇 장벽 등).
- 데이터가 부분적으로 이미지에 포함되어 있을 때 (예: 사이즈 차트, 별점 형태의 평점).
- 빠른 프로토타입 (prototype)이 필요하고 비용은 상관없을 때.
단순한 사이트의 경우에는 여전히 BeautifulSoup + requests를 사용합니다. 그것이 더 빠르고, 저렴하며, 더 신뢰할 수 있기 때문입니다. 하지만 정말 까다로운 사이트들에 대해서는, AI가 저의 새로운 망치(hammer)가 되었습니다.
다음에 제가 다르게 시도할 것들
- 먼저 로컬 비전 모델 (local vision model)을 시도하기. 민감한 데이터의 경우, GPU에서 LLaVA 13B를 실행할 것입니다. 속도는 느리지만 데이터가 제 서버를 벗어나지 않습니다.
- 더 나은 프롬프트 (prompt) 사용하기. 원하는 출력 형식의 예시와 함께 특정 필드를 요청하는 법을 배웠습니다. 퓨샷 프롬프팅 (Few-shot prompting)은 정확도를 크게 향상시켰습니다.
- 캐싱 레이어 (caching layer) 추가하기. 동일한 페이지가 다시 나타나면 API 호출을 건너뜁니다.
- 먼저 작은 배치 (batch)로 테스트하기. 모델이 "사이즈"를 "가격"과 혼동한다는 사실을 뒤늦게 깨닫기 위해 1,000개의 스크린샷을 한꺼번에 보내지는 마세요.
참고로, ai.interwestinfo.com에 있는 도구는 유사한 서비스를 제공하지만, 중요한 것은 기술입니다. 비전 기능이 있는 어떤 API를 사용하더라도 직접 구현할 수 있습니다.
여러분의 의견은 어떠신가요?
저는 여전히 파싱 (parsing)을 "AI에게 물어보기"로 대체하는 것이 완전히 편안하지는 않습니다. 하지만 이번 경험을 통해 우리의 기존 방식에는 한계가 있으며, 때로는 가장 좋은 도구가 그저 페이지를 "보는" 도구라는 것을 깨달았습니다.
친절하지 않은 웹사이트에서 데이터를 추출할 때 여러분이 선호하는 방법은 무엇인가요? 비전 모델을 사용해 보셨나요, 아니면 여전히 XPath와 정규표현식 (regex) 전쟁에 의존하고 계신가요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기