LLM이 HTML을 읽게 하면서 나의 웹 스크래핑 악몽이 끝났다
요약
기존 CSS 셀렉터 방식의 한계를 극복하기 위해 LLM을 활용한 웹 스크래핑 최적화 전략을 소개합니다. HTML 전처리, 캐싱, 모델 폴백 체인 등을 통해 비용과 효율성을 동시에 잡는 실무적인 가이드를 제공합니다.
핵심 포인트
- HTML 전처리를 통해 토큰 사용량을 30~50% 절감 가능
- 저렴한 모델(GPT-4o-mini) 우선 사용 후 필요시 상위 모델로 폴백
- URL 해시 기반 캐싱으로 중복 호출 및 비용 방지
- 가변적인 레이아웃 대응에는 유리하나 대규모 스크래핑에는 비효율적
저는 수년 동안 스크래퍼(scrapers)를 만들어 왔습니다. 보통은 간단한 스크립트로 해결됩니다: requests.get, BeautifulSoup, 몇 개의 CSS 셀렉터(selectors)만 있으면 끝이죠. 하지만 지난달, 제가 알고 있던 모든 것에 의문을 갖게 만드는 벽에 부딪혔습니다.
저는 수십 개의 서로 다른 이커머스 사이트에서 제품 정보를 추출해야 했습니다. 각 사이트마다 레이아웃이 조금씩 달랐습니다: 어떤 곳은 <div class="price">를 사용했고, 다른 곳은 <span itemprop="price">를 사용했으며, 특히 악랄한 한 사이트는 무작위로 생성된 클래스 이름(class names)을 가진 깊게 중첩된 React 트리 안에 가격을 렌더링하고 있었습니다. 셀렉터 기반의 제 접근 방식은 폴백 패턴(fallback patterns), try/except 블록이 뒤섞인 취약한 난장판이 되었고, 결국 300줄짜리 함수가 되었지만 여전히 네 페이지마다 한 번씩 실패했습니다.
헤드리스 브라우저(headless browsers)도 시도해 보았습니다. 규모를 키워야 하기 전까지는 효과가 있었습니다. 20개의 브라우저를 동시에 실행하니 메모리를 잡아먹었고
위의 단순한 코드 스니펫(snippet)은 비용, 지연 시간(latency), 그리고 토큰 제한(token limits)이라는 문제점을 가지고 있습니다. 제가 개선한 사항은 다음과 같습니다:
- 캐싱 (Caching): URL 해시(hash)별로 결과를 저장하여 매 실행 시마다 다시 추출하지 않도록 합니다.
- HTML 전처리 (HTML preprocessing):
<script>,<style>,<svg>태그를 제거합니다. 과도한 공백을 제거합니다. 이를 통해 토큰을 30~50% 절감할 수 있습니다. - 재시도 및 검증 (Retry & validation): 출력이 유효한 JSON인지 확인하고, 예상되는 필드가 누락된 경우 더 구체적인 프롬프트(prompt)로 재시도합니다.
- 배치 처리 (Batch processing): 전체 HTML이 컨텍스트(context) 내에 들어온다면 한 번의 호출로 여러 URL을 보냅니다 (목록 페이지에 유용합니다).
- 폴백 체인 (Fallback chain): 먼저 저렴한 모델(GPT-4o-mini)을 시도하고, 신뢰도가 낮으면 더 강력한 모델로 다시 실행합니다.
import json
import hashlib
...
저는 또한 간단한 프롬프트 캐시(prompt cache)를 구축했습니다. 동일한 URL을 다시 쿼리하면 캐시된 결과를 제공합니다. 이는 개발 과정에서 매우 중요합니다.
이 접근 방식이 빛을 발하는 경우
- 가변적인 HTML 구조: 레이아웃이 자주 바뀌는 이커머스 사이트 (블랙 프라이데이 기간의 디자인 변경? 문제없습니다.)
- 소규모 스크래핑: 하루 100~1,000페이지 정도. 대규모로 갈 경우 LLM 비용이 누적됩니다 (GPT-4o-mini의 경우 100만 토큰당 $0.15이므로, 페이지당 약 $0.01).
- 빠른 프로토타이핑 (Rapid prototyping): 아무것도 없는 상태에서 작동하는 추출기를 만드는 데 10분이면 충분합니다.
사용하지 말아야 할 경우
- 고정되어 있고 문서화가 잘 된 API 또는 구조화된 HTML: 사이트에 일관된 셀렉터(selector)가 있다면, 직접 만든 CSS 경로(path)가 더 빠르고 저렴합니다.
- 방대한 양: 수백만 페이지를 스크래핑하시나요? LLM 비용이 컴퓨팅 비용을 압도할 것입니다. 전통적인 방식을 고수하세요.
- 실시간 요구 사항: 각 호출에는 1~3초가 소요됩니다. 1초 미만의 추출이 필요하다면 정규표현식(regex)과 휴리스틱(heuristics)을 사용하세요.
- 민감한 데이터: 전체 HTML을 제3자 API로 전송하는 것은 이용 약관이나 개인정보 보호 정책을 위반할 수 있습니다. Ollama를 통한 로컬 모델(Llama 3, Mistral) 사용을 고려하세요.
트레이드오프 (Trade-offs) 및 학습한 교훈
- 모델 크기보다 프롬프트 엔지니어링 (Prompt engineering)이 더 중요합니다. 저는 프롬프트를 튜닝하는 데 몇 시간을 소비했고, 그 결과 GPT-4로 교체하는 것보다 더 나은 결과를 얻었습니다.
- 토큰 제한 (Token limits)은 가장 큰 적입니다. 단일 제품 페이지의 HTML이 쉽게 50KB에 달할 수 있습니다. 지능적으로 절단(Truncate)하세요.
<body>태그는 유지하고<h1>위쪽의 모든 것은 제거하십시오. - 환각 (Hallucinations)은 실재합니다. 모델이 존재하지 않는 "할인" 필드를 만들어내는 것을 경험했습니다. 항상 알려진 정답(Ground truth)과 대조하여 검증하십시오.
- 비용 대 정확도 (Cost vs. accuracy) 트레이드오프: 100개 페이지의 테스트 세트에서 GPT-4o-mini는 82%의 정확도(정확한 필드 일치)를 달성했습니다. GPT-4는 93%를 달성했습니다. 제 사용 사례에서는 더 저렴한 모델로도 충분했지만, 상황에 따라 결과는 다를 수 있습니다.
결국 저는 두 가지 방식을 결합한 작은 내부 도구를 구축했습니다. 알려진 패턴에는 빠른 CSS 선택자 (CSS selectors)를 사용하고, 선택자가 null을 반환할 때는 LLM으로 전환하는 방식입니다. 이러한 하이브리드 방식이 두 방식의 장점을 모두 제공했습니다.
이 과정을 더 추상화해 주는 서비스들도 있습니다. 저는 캐싱과 모델 선택을 처리해 주는 https://ai.interwestinfo.com/의 서비스를 시도해 보았지만, 솔직히 DIY(직접 구축) 방식이 프롬프트 설계와 비용 관리에 대해 더 많은 것을 가르쳐 주었습니다. 여러분의 선택은 스택을 직접 소유하고 싶은지, 아니면 복잡성을 외주로 처리하고 싶은지에 달려 있습니다.
앞으로 나아갈 방향
이 기술에 관심이 있다면, 채용 공고 스크래핑, 뉴스 헤드라인, 또는 PDF 텍스트 추출과 같이 여러분이 겪고 있는 문제에 직접 적용해 보세요. 원리는 동일합니다. 규칙을 작성하는 대신, 데이터를 설명하고 모델이 구조를 파악하게 만드는 것입니다.
작은 배치(Batch)로 시작하여 정확도를 측정하고, 프롬프트에 만족할 때만 규모를 키우십시오. 그리고 항상 백업 스크래퍼를 유지하세요. 저는 API 속도 제한 (Rate limit)이 걸렸을 때 그 교훈을 뼈아프게 배웠습니다.
여러분의 설정은 어떤 모습인가요? 취약한 선택자를 대체하기 위해 LLM을 사용해 보셨나요, 아니면 전통적인 스크래핑 방식을 고수하시나요? 여러분의 경험담을 듣고 싶습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기