본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 05. 17:37

정규표현식(Regex)을 쓰는 데 3일을 보냈습니다. 그 후 AI에게 부탁했더니 10분 만에 끝났습니다.

요약

복잡한 HTML 구조에서 데이터를 추출하기 위해 정규표현식이나 XPath 대신 LLM을 활용한 퓨샷 프롬프팅 방식을 제안합니다. GPT-4를 사용하여 비정형 데이터를 구조화된 JSON으로 변환함으로써 개발 시간을 획기적으로 단축한 사례를 다룹니다.

핵심 포인트

  • 정규표현식과 XPath의 한계: 동적 클래스명과 복잡한 구조에 취약함
  • LLM 기반 추출 방식: HTML을 텍스트로 입력하고 퓨샷 프롬프팅 활용
  • 안정적인 결과 도출: temperature=0 설정 및 Function Calling 권장
  • 비용 최적화: 단순 추출 작업에는 gpt-3.5-turbo 활용 가능

지난달, 저는 수십 개의 이커머스 사이트에서 제품 데이터를 스크레이핑(Scrape)해야 했습니다. 각 사이트는 저마다의 HTML 구조와 일관성 없는 CSS 클래스를 가지고 있었고, 가장 최악인 부분은 무엇이었을까요? 제품 설명이 수십 개의 서로 다른 컨테이너 안에 중첩되어 있었다는 점입니다. 저는 제정신인 개발자라면 누구나 할 법한 행동을 했습니다. 바로 정규표현식(Regex)을 사용한 것이죠.

3일 후, 저는 한 사이트에서는 작동하지만 다른 사이트에서는 실패하고, 페이지 레이아웃이 단 하나의 <div>만 바뀌어도 깨져버리는 취약한 패턴들의 더미를 갖게 되었습니다. 저는 포기하고 데이터를 복사해서 붙여넣어 줄 가상 비서(VA)를 고용하기 직전까지 갔습니다.

그때 문득 생각이 떠올랐습니다. 패턴을 명시적으로 설명하려고 애쓰는 대신, AI에게 몇 가지 예시를 보여주고 나머지는 AI가 알아서 하게 하면 어떨까?

시도했지만 실패했던 방법들

1. 순수 CSS 선택자 (Pure CSS selectors)

클래스명이 깔끔한 사이트의 경우 document.querySelectorAll('.price')가 작동합니다. 하지만 현실 세계는 .productPrice_3xK2f.css-1a2b3c처럼 배포할 때마다 바뀌는 자동 생성된 클래스명을 던져줍니다.

2. XPath

XPath는 더 유연하지만, //div[contains(@class, 'price')]//span[2]를 작성하는 것은 마치 추측을 하는 것처럼 느껴졌습니다. 그리고 제품 페이지마다 페이지 구조가 달라질 때마다 저의 XPath 표현식들은 무너졌습니다.

3. 정규표현식 지옥 (Regex hell)

<script> 태그에서 JSON을 추출하고, 인라인 스타일(Inline styles)을 파싱하며, 키워드로 분할하는 시도를 했습니다. 새로운 사이트가 나타날 때마다 맞춤형 정규표현식이 필요했습니다. 40개가 넘는 패턴이 담긴 파일을 가지고 있었음에도 여전히 데이터를 놓치고 있었습니다.

마침내 성공한 접근 방식: LLM을 이용한 퓨샷 텍스트 추출 (Few-shot text extraction with an LLM)

규칙을 작성하는 대신, 추출을 하나의 언어 작업(Language task)으로 다루기로 했습니다. 저는 AI(OpenAI의 GPT-4)에게 원본 HTML과 제가 원하는 정확한 필드의 예시를 몇 가지 제공하고, JSON으로 출력하도록 요청했습니다.

핵심 아이디어는 다음과 같습니다:

  • HTML을 구조적으로 파싱하지 마세요. 그냥 일반 텍스트로 입력하세요.
  • 원하는 출력 형식을 보여주기 위해 2~3개의 예시를 제공하세요 (퓨샷 프롬프팅 (Few-shot prompting)).
  • 결정론적인(Deterministic) 결과를 위해 temperature=0 설정과 함께 간단한 함수 호출(Function call)을 사용하세요.

코드

먼저, 원본 HTML을 입력받아 제품 리스트를 딕셔너리(Dictionary) 형태로 반환하는 Python 함수를 작성했습니다.

import openai
from typing import List, Dict, Any
import json
...
if content.startswith("```\n"):
    content = content.split("\n", 1)[1].rsplit("\n", 1)[0]
return json.loads(content)

중요: 이것은 최소한의 예시입니다. 실제 운영 환경(Production)에서는 다음과 같은 조치가 필요합니다:

  • 비용 절감을 위해 gpt-3.5-turbo를 사용합니다 (단순한 추출 작업에는 잘 작동합니다).
    ...
import requests

url = "https://example.com/products"
html = requests.get(url).text
products = extract_products(html)
for p in products:
    print(p["name"], p["price"])

저는 또한 폴백(Fallback) 메커니즘을 추가했습니다. 만약 AI 요청이 실패할 경우(예: 타임아웃), 기본적인 데이터를 얻기 위해 단순한 정규표현식(Regex)을 사용하도록 했습니다. 하지만 95%의 경우 AI가 성공적으로 작동했습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0