AI 웹 스크래퍼 환경 구축과 필수 패키지 설정

개발자가 웹페이지 전체 HTML을 LLM에 그대로 전달하는 대신 클리닝 후 마크다운으로 변환하는 파이프라인을 구축해 토큰 사용량을 최적화한다. 웹페이지의 내비게이션 링크, 버튼, 스크립트, 푸터 등 불필요한 요소가 포함된 지저분한 페이지를 그대로 전송하면 토큰 낭비가 심하고 모델의 응답 품질이 저하되기 때문이다. 정제된 마크다운 형식은 LLM이 콘텐츠를 더 쉽게 이해하게 만들며, 결과적으로 더 깨끗하고 읽기 쉬운 답변을 도출하는 워크플로를 가능하게 한다.

실무자는 Jupyter Notebook을 개발 환경으로 선택해 수집, 정제, 변환의 각 단계를 개별적으로 테스트하고 API나 애플리케이션으로 전환하기 전 검증 과정을 거친다. 파이프라인 구현을 위해 웹 서버 요청을 담당하는 `requests`, HTML 파싱 및 정제를 수행하는 `beautifulsoup4`, HTML을 마크다운으로 변환하는 `markdownify`, 환경 변수를 관리하는 `python-dotenv`, 그리고 LLM 통신을 위한 `openai` 라이브러리를 설치한다.

bash
pip install requests beautifulsoup4 markdownify python-dotenv openai

사용자는 OpenAI API 키를 소스 코드에 직접 노출하지 않고 `.env` 파일에 저장한 뒤 `python-dotenv` 라이브러리를 통해 불러오는 방식으로 보안을 강화한다. 또한 OpenAI 플랫폼 계정의 빌링 설정을 확인하고 필요한 경우 선불 크레딧을 충전하여 API 호출 시 인증 오류로 인해 워크플로가 중단되는 상황을 방지한다.

python
from dotenv import load_dotenv
load_dotenv()

HTML 수집 및 노이즈 제거를 위한 클리닝 공정

개발자가 `requests` 패키지를 사용하여 웹페이지의 raw HTML을 가져오는 `fetch_page` 함수를 구현한다. 이때 웹사이트의 요청 차단을 방지하기 위해 `User-Agent` 헤더를 추가하고, 서버 응답 지연에 대비해 `timeout` 설정을 적용하며, `raise_for_status()`를 호출해 404나 500 에러 발생 시 코드를 즉시 중단시켜 데이터 무결성을 확보한다.

python
def fetch_page(url):
    headers = {"User-Agent": "Mozilla/5.0"}
    response = requests.get(url, headers=headers, timeout=10)
    response.raise_for_status()
    return response.text

BeautifulSoup 라이브러리는 수집된 HTML에서 텍스트 정보 가치가 낮은 `script`, `style`, `nav`, `header`, `footer`, `form`, `button` 태그를 일괄 제거하여 노이즈를 줄인다. 태그 제거 후에는 HTML 요소의 클래스(class)나 ID 이름에 `popup`, `cookie`, `navbar`, `newsletter`, `modal`과 같은 특정 키워드가 포함된 요소를 찾아 추가로 삭제함으로써 LLM이 분석해야 할 데이터의 밀도를 높인다.

이러한 전처리 과정은 LLM에 전달되는 입력 토큰의 양을 직접적으로 줄여 비용을 절감하고, 모델이 페이지의 레이아웃 요소가 아닌 실제 본문 콘텐츠에만 집중하게 만들어 답변의 정확도를 향상시키는 핵심 단계가 된다.

마크다운 변환을 통한 토큰 최적화 및 구조화

개발자가 `markdownify` 라이브러리를 도입해 정제된 HTML을 ATX 스타일의 마크다운으로 변환함으로써 LLM이 문서의 계층 구조를 더 명확하게 파악하도록 설계한다. ATX 스타일은 제목에 `#`, `##`, `###` 기호를 사용하는 표준 문법으로, raw HTML보다 읽기 쉽고 저장 및 관리가 용이하며 LLM의 이해도를 높이는 특성이 있다.

변환 과정에서 텍스트 기반 질의응답에 불필요한 이미지 마크다운 링크를 제거하고, 불필요한 공백과 빈 줄을 삭제해 최종 콘텐츠를 콤팩트하게 만든다. 또한 `skip_lines` 리스트를 정의해 폼 메시지, 내비게이션 레이블, 작은 콜투액션(CTA) 텍스트 등 반복되는 웹사이트 문구를 필터링하여 토큰 소모를 최소화한다.

최종적으로 생성된 마크다운 텍스트는 헤딩, 단락, 불릿 포인트가 포함된 구조화된 형태로 변환된다. 이는 LLM이 입력 데이터를 처리하는 효율을 극대화하며, 사용자가 웹페이지의 전체 내용을 덤프 받는 대신 정밀하게 정제된 정보만을 모델에 제공하는 기반이 된다.

LLM 프롬프트 전략과 효율적인 모델 선택

시스템이 정제된 마크다운 콘텐츠와 사용자 쿼리를 입력받아 정답을 도출하는 `get_llm_answer` 함수를 실행한다. 이때 복잡한 논리 추론보다 정제된 텍스트 내 정보 추출이 주 목적이므로, 대규모 추론 모델 대신 비용 효율적인 소형 모델인 `gpt-5.4-nano`를 선택해 응답 속도를 높이고 운영 비용을 낮춘다.

프롬프트 설계 시 모델에게 부여할 역할과 사용할 수 있는 콘텐츠 범위를 명확히 지정하여, 제공된 마크다운 내용만을 근거로 답변하도록 제약 조건을 설정한다. 이는 모델이 학습 데이터에 의존해 존재하지 않는 정보를 생성하는 환각(Hallucination) 현상을 방지하고, 오직 주어진 웹페이지 문맥 안에서만 정답을 찾게 만드는 핵심 장치다.

또한 모델이 전체 페이지를 요약하거나 무분별하게 출력하지 않고, 사용자의 질문에 최적화된 깨끗한 마크다운 형식으로만 답변을 반환하도록 지시한다. 이러한 제약 조건은 출력된 결과물을 다른 AI 워크플로에 전달하거나 파일로 저장할 때 후처리가 용이하게 만든다.

통합 파이프라인 구현 및 실무 활용 기준

개발자가 `fetch_page`, `clean_html`, `convert_to_markdown`, `get_llm_answer` 함수를 하나로 묶은 `ai_web_scraper` 통합 함수를 구현해 데이터 수집부터 정답 도출까지의 전 과정을 자동화한다. 이 구조를 통해 사용자는 URL과 쿼리만 입력하면 단 한 번의 함수 호출로 정제된 마크다운 답변을 얻을 수 있으며, 코드의 재사용성을 높여 API, 챗봇, AI 에이전트 워크플로에 즉시 이식할 수 있다.

python
def ai_web_scraper(url, query):
    html = fetch_page(url)
    cleaned_html = clean_html(html)
    markdown_content = convert_to_markdown(cleaned_html)
    answer = get_llm_answer(markdown_content, query)
    return answer

최종 산출물인 마크다운 답변은 `.md` 파일로 저장하여 지식을 구조화된 형태로 자산화하고, 동일한 질문에 대해 반복적으로 API를 호출하는 토큰 낭비를 방지한다.

python
with open('result.md', 'w') as f:
    f.write(answer)

실무자는 웹 스크래핑 시 `requests` $\rightarrow$ `BeautifulSoup` $\rightarrow$ `markdownify` $\rightarrow$ `gpt-5.4-nano`로 이어지는 전처리 파이프라인을 구축함으로써 입력 토큰 비용을 최적화하고 정제된 답변을 얻는 기준을 확보한다. 특히 제거 대상 태그(`script`, `style`, `nav`, `header`, `footer`, `form`, `button`)와 필터링 키워드(`popup`, `cookie`, `navbar`, `newsletter`, `modal`) 리스트를 사이트 특성에 맞게 업데이트하며 최적의 정보 밀도를 유지하는 것이 중요하다.