URL을 마크다운으로 추출하는 과정에서 쿠키 배너가 본문으로 반환된 경험
요약
URL을 마크다운으로 변환할 때, 단순 텍스트 밀도만으로는 쿠키 배너 같은 정형화된 콘텐츠를 본문으로 오인하기 쉽습니다. 이 문제를 해결하기 위해 링크 밀도와 시맨틱 태그(article/main) 존재 여부를 활용하는 휴리스틱을 적용했습니다.
핵심 포인트
- 단순 텍스트 밀도는 법적 고지 사항과 기사를 구분할 수 없습니다.
- 링크 밀도가 높은 블록은 쿠키 배너일 가능성이 높으므로 페널티를 부여해야 합니다.
- 시맨틱 태그(<article>, <main>)가 존재하면 가장 확실한 본문 식별자입니다.
- SPA 페이지의 경우, 단순 HTTP 요청으로는 콘텐츠 추출이 불가능합니다.
제가 사용하는 문서 변환기 대부분은 이미 가지고 있는 파일을 입력받습니다. 하지만 URL-to-Markdown 방식은 다릅니다. 이 방식은 페이지 자체를 가져와서, 무언가를 변환하기 전에 '어떤 것이 주요 콘텐츠인지' 결정해야 합니다. 그 결정 과정이 저에게 지금까지 가장 겸손한 교훈을 주었습니다.
처음에 제가 사용했던 추출 휴리스틱(extraction heuristic)은 순수한 텍스트 밀도였습니다. 모든 후보 블록을 포함된 텍스트 양으로 점수를 매기고, 최고점을 받은 것을 선택하여 변환하는 방식이었습니다. 이 방법은 블로그, 문서, 뉴스 페이지에서는 아주 잘 작동했습니다. 그러다가 실제 웹 URL들을 일괄적으로 돌려보았는데, 한 뉴스 사이트가 기사 본문 대신 600단어 분량의 GDPR 동의 대화 상자를 반환해 왔습니다. 실제 이야기는 폭이 좁은 컬럼에 약 300단어로 존재했고, 그 동의 배너는 기사 자체보다 더 많은 산문의 문구로 이루어진 정형적인 내용(boilerplate)이었습니다.
텍스트 밀도만으로는 충분하지 않았습니다. 그것은 법적 고지 사항의 벽과 기사를 구분할 수 없었기 때문입니다. 둘 다 그저 '큰 덩어리의 텍스트'였을 뿐입니다.
두 가지 신호가 이 문제를 해결했습니다. 첫째는 링크 밀도(link density)였습니다. 내비게이션 헤더, 푸터, 쿠키 배너 등은 앵커 태그로 가득 차 있는 반면, 실제 기사 본문 텍스트는 주로 산문으로 이루어져 있습니다. 앵커 텍스트가 전체 텍스트의 약 30%를 초과하는 블록에 페널티를 부여하자, 잘못 추출된 결과물(false wins) 대부분이 사라졌습니다. 둘째는 시맨틱 앵커(semantic anchors)였습니다. 단일 <article> 또는 <main> 요소가 존재한다면, 이는 어떤 휴리스틱 점수보다도 확실했습니다. 또한 저는 'consent', 'cookie', 'banner', 'paywall'과 같은 ID/클래스 문자열을 포함하는 작은 블랙리스트를 유지하여 해당 후보들을 아예 제외시킵니다.
그 밑에는 세 번째 교훈이 숨어 있습니다: 단일 페이지 애플리케이션(single-page apps). 클라이언트 측에서 렌더링되는 페이지에 대한 단순 HTTP 요청은 거의 비어 있는 div만 반환하며, 서버가 보내지 않은 텍스트를 어떤 점수 계산으로도 복구할 수 없습니다. 따라서 정적 HTML이 주로 스크립트 태그로 이루어진 페이지의 경우, 저는 빈 마크다운 문서를 반환하는 대신 명시적인
Agents가 임의 웹 페이지를 대상으로 RAG 파이프라인을 구축할 때 정확히 이러한 판단이 필요합니다. 그래서 저는 이 '데이터 가져오기 및 정리(fetch-and-clean)' 단계를 작은 API로 패키징했습니다: https://x402.freeq.one/tools/markdown.html — 하지만 위에 설명된 휴리스틱(heuristic) 세부 사항이 전이 가능한 부분입니다. 동일한 점수 매기기 트릭은 인덱싱 전에 정리하는 모든 HTML에 적용됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기