대규모 언어 모델을 활용한 웹 스크래핑 강화: 현대적인 접근 방식

2016년 데이터 엔지니어로서의 초기 시절부터 저는 다양한 웹사이트에서 데이터를 스크래핑하는 책임을 지게 되었습니다. 웹 스크래핑은 웹사이트에서 많은 양의 데이터를 얻기 위해 자동화된 도구를 사용하는 것을 의미하며, 보통 웹사이트의 HTML에서 이루어집니다.

I remember building around the application, digging into the HTML code, and trying to figure out the best solutions for scraping all the data. One of my main challenges was dealing with frequent changes to the websites: for example, the Amazon pages I was scraping changed every one to two weeks.

제가 대규모 언어 모델(LLMs)에 대해 읽기 시작했을 때 든 생각은 “LLMs를 사용하여 웹페이지의 데이터를 구조화함으로써 그런 함정들을 피할 수 있을까?”였습니다.

한 번 보죠.

웹 스크래핑 도구 및 기술

당시 제가 사용하던 주요 도구는 Requests, BeautifulSoup, 그리고 Selenium이었습니다. 각 서비스는 다른 목적과 다양한 유형의 웹 환경을 대상으로 합니다.

  • RequestsPython 라이브러리로, HTTP 요청을 쉽게 만들 수 있습니다. 이 라이브러리는 요청에 제공된 URL에 대해 GET 및 POST 작업을 수행합니다. 이 라이브러리는 종종 BeautifulSoup에 의해 구문 분석될 수 있는 HTML 콘텐츠를 가져오는 데 사용됩니다.
  • BeautifulSoup은 HTML 및 XML 문서를 구문 분석하기 위한 Python 라이브러리로, 페이지 소스에서 파서 트리를 구성하여 페이지의 다양한 요소에 쉽게 접근할 수 있습니다. 보통 RequestsSelenium과 같은 다른 라이브러리와 함께 사용되며, 이들은 HTML 소스 코드를 제공합니다.
  • Selenium은 많은 JavaScript가 포함된 웹사이트를 위해 주로 사용됩니다. BeautifulSoup과 달리, SeleniumHTML 코드를 단순히 분석하지 않고 클릭이나 스크롤과 같은 사용자 동작을 에뮬레이션하여 웹사이트와 상호 작용합니다. 이는 동적으로 콘텐츠를 생성하는 웹사이트에서 데이터 추출을 용이하게 합니다.

이러한 도구들은 웹사이트에서 데이터를 추출하려고 할 때 필수적이었습니다. 그러나 그들은 또한 몇 가지 과제를 제기했습니다: 코드, 태그 및 구조적 요소는 웹사이트 레이아웃의 변경을 수용하기 위해 정기적으로 업데이트되어야 했으며, 장기적인 유지 보수를 복잡하게 만들었습니다.

대규모 언어 모델 (LLMs)은 많은 양의 텍스트 데이터를 읽고 분석하여 학습할 수 있는 차세대 컴퓨터 프로그램입니다. 이 시대에 그들은 인간처럼 서술하는 능력을 가진 놀라운 능력을 갖추고 있어 언어를 처리하고 인간의 언어를 이해하는 효율적인 에이전트가 될 수 있습니다. 텍스트 맥락이 정말 중요한 상황에서 뛰어난 능력이 발휘되었습니다.

LLMs을 웹 스크래핑에 통합

웹 스크레이핑 과정은 LLM을 통합함으로써 상당히 최적화될 수 있습니다. 웹페이지의 HTML 코드를 가져와 LLM에 입력하면, 이를 통해 해당 객체를 추출할 수 있습니다. 따라서 이 전략은 마크업 구조가 진화할 수 있음에도 불구하고 콘텐츠 자체는 보통 변경되지 않기 때문에 유지보수를 쉽게 만들어 줍니다.

이러한 통합 시스템의 아키텍처는 다음과 같습니다:

  1. HTML 가져오기: Selenium이나 Requests와 같은 도구를 사용하여 웹페이지의 HTML 콘텐츠를 가져옵니다. Selenium은 JavaScript로 로드된 동적 콘텐츠를 처리할 수 있고, Requests는 정적 페이지에 적합합니다.
  2. HTML 파싱: BeautifulSoup을 사용하여 이 HTML을 텍스트로 파싱하여 마크업에서 노이즈(푸터, 헤더 등)를 제거합니다.
  3. Pydantic 모델 생성: 스크레이핑할 Pydantic 모델을 작성합니다. 이는 데이터가 미리 정의된 스키마에 따라 타이핑되고 구조화되도록 보장합니다.
  4. LLM용 프롬프트 생성: LLM이 어떤 정보를 추출해야 하는지 알리는 프롬프트를 설계합니다.
  5. LLM 처리: 모델은 HTML을 읽고 이해한 후 데이터 처리 및 구조화를 위한 지침을 사용합니다.
  6. 구조화된 데이터 출력: LLM은 Pydantic 모델에 의해 정의된 구조화된 객체 형태로 출력을 제공합니다.

이 워크플로는 HTML(구조화되지 않은 데이터)를 LLM을 사용하여 구조화된 데이터로 변환하는 데 도움을 주며, 비표준 디자인이나 웹 소스 HTML의 동적 변경과 같은 문제를 해결합니다.

LangChain과 BeautifulSoup 및 Pydantic 통합

이 정적 웹페이지는 예시에 선택되었습니다. 여기서 나열된 모든 활동을 스크래핑하여 구조적인 방식으로 표시하는 것이 목표입니다.

이 방법은 정적 웹페이지에서 원시 HTML을 추출하고 LLM이 처리하기 전에 정리합니다.

Python

 

from bs4 import BeautifulSoup
import requests


def extract_html_from_url(url):
    try:
        # requests를 사용하여 URL에서 HTML 콘텐츠 가져오기
        response = requests.get(url)
        response.raise_for_status()  # Raise an exception for bad responses (4xx and 5xx)

        # BeautifulSoup를 사용하여 HTML 콘텐츠 구문 분석
        soup = BeautifulSoup(response.content, "html.parser")
        excluded_tagNames = ["footer", "nav"]
        # 'footer' 및 'nav' 태그 이름을 가진 요소 제외
        for tag_name in excluded_tagNames:
            for unwanted_tag in soup.find_all(tag_name):
                unwanted_tag.extract()

        # 앵커 태그에서 hrefs를 유지하도록 수프 처리
        for a_tag in soup.find_all("a"):
            href = a_tag.get("href")
            if href:
                a_tag.string = f"{a_tag.get_text()} ({href})"

        return ' '.join(soup.stripped_strings)  # Return text content with preserved hrefs

    except requests.exceptions.RequestException as e:
        print(f"Error fetching data from {url}: {e}")
        return None

다음 단계는 웹페이지에서 스크래핑할 Pydantic 객체를 정의하는 것입니다. 두 개의 객체를 생성해야 합니다:

  • Activity: 이는 활동과 관련된 모든 메타데이터를 나타내는 Pydantic 객체로, 속성과 데이터 유형이 지정되어 있습니다. 일부 필드에 Optional 표시를 하여 모든 활동에 대해 사용 가능하지 않을 수 있음을 나타냅니다. 설명, 예제 및 메타데이터를 제공하면 LLM이 속성에 대한 더 나은 정의를 갖게 됩니다.
  • ActivityScraper: 이것은 Activity를 감싸는 Pydantic 래퍼입니다. 이 객체의 목적은 LLM이 여러 활동을 스크래핑해야 한다는 것을 이해하도록 보장하는 것입니다.
Python

 

from pydantic import BaseModel, Field
from typing import Optional

class Activity(BaseModel):
    title: str = Field(description="The title of the activity.")
    rating: float = Field(description="The average user rating out of 10.")
    reviews_count: int = Field(description="The total number of reviews received.")
    travelers_count: Optional[int] = Field(description="The number of travelers who have participated.")
    cancellation_policy: Optional[str] = Field(description="The cancellation policy for the activity.")
    description: str = Field(description="A detailed description of what the activity entails.")
    duration: str = Field(description="The duration of the activity, usually given in hours or days.")
    language: Optional[str] = Field(description="The primary language in which the activity is conducted.")
    category: str = Field(description="The category of the activity, such as 'Boat Trip', 'City Tours', etc.")
    price: float = Field(description="The price of the activity.")
    currency: str = Field(description="The currency in which the price is denominated, such as USD, EUR, GBP, etc.")

    
class ActivityScrapper(BaseModel):
    Activities: list[Activity] = Field("List of all the activities listed in the text")

마지막으로, LLM의 구성에 대해 설명합니다. 시작하기에 훌륭한 도구 키트를 제공하는 LangChain 라이브러리를 사용할 것입니다.

A key component here is the PydanticOutputParser. Essentially, this will translate our object into instructions, as illustrated in the Prompt, and also parse the output of the LLM to retrieve the corresponding list of objects.

Python

 

from langchain.prompts import PromptTemplate
from langchain.output_parsers import PydanticOutputParser
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()

llm = ChatOpenAI(temperature=0)
output_parser = PydanticOutputParser(pydantic_object = ActivityScrapper)

prompt_template = """
You are an expert making web scrapping and analyzing HTML raw code.
If there is no explicit information don't make any assumption.
Extract all objects that matched the instructions from the following html
{html_text}
Provide them in a list, also if there is a next page link remember to add it to the object.
Please, follow carefulling the following instructions
{format_instructions}
"""

prompt = PromptTemplate(
    template=prompt_template,
    input_variables=["html_text"],
    partial_variables={"format_instructions": output_parser.get_format_instructions}
)

chain = prompt | llm | output_parser

마지막 단계는 체인을 호출하고 결과를 검색하는 것입니다.

Python

 

url = "https://www.civitatis.com/es/budapest/"
html_text_parsed = extract_html_from_url(url)
activites = chain.invoke(input={
    "html_text": html_text_parsed
})
activites.Activities

데이터의 모습은 다음과 같습니다. 전체 웹 페이지를 스크래핑하는 데 46초가 소요됩니다.

Python

 

[Activity(title='Paseo en barco al anochecer', rating=8.4, reviews_count=9439, travelers_count=118389, cancellation_policy='Cancelación gratuita', description='En este crucero disfrutaréis de las mejores vistas de Budapest cuando se viste de gala, al anochecer. El barco es panorámico y tiene partes descubiertas.', duration='1 hora', language='Español', category='Paseos en barco', price=21.0, currency='€'),
 Activity(title='Visita guiada por el Parlamento de Budapest', rating=8.8, reviews_count=2647, travelers_count=34872, cancellation_policy='Cancelación gratuita', description='El Parlamento de Budapest es uno de los edificios más bonitos de la capital húngara. Comprobadlo vosotros mismos en este tour en español que incluye la entrada.', duration='2 horas', language='Español', category='Visitas guiadas y free tours', price=27.0, currency='€')
 ...
]

데모 및 전체 저장소

I have created a quick demo using Streamlit available here.

첫 번째 부분에서는 모델에 대해 소개됩니다. 필요한 만큼 많은 행을 추가하고 각 속성의 이름, 유형 및 설명을 지정할 수 있습니다. 이렇게 하면 웹 스크래핑 구성 요소에서 사용할 수 있는 Pydantic 모델이 자동으로 생성됩니다.

다음 부분에서는 URL을 입력하고 웹 페이지의 버튼을 클릭하여 모든 데이터를 스크래핑할 수 있습니다. 스크래핑이 완료되면 다운로드 버튼이 나타나 데이터를 JSON 형식으로 다운로드할 수 있습니다.

자유롭게 사용해보세요!

결론

LLM은 웹사이트, PDF 등과 같은 비정형 데이터에서 데이터를 효율적으로 추출하는 새로운 가능성을 제공합니다. LLM에 의한 웹 스크래핑의 자동화는 시간을 절약할 뿐만 아니라 검색된 데이터의 품질을 보장합니다.

그러나 원시 HTML을 LLM에 보내는 것은 토큰 비용을 증가시키고 비효율적일 수 있습니다. HTML은 종종 다양한 태그, 속성 및 내용을 포함하므로 비용이 빠르게 상승할 수 있습니다.

따라서 HTML을 사전 처리하고 정리하여 불필요한 메타데이터와 사용되지 않는 정보를 모두 제거하는 것이 중요합니다. 이러한 접근 방식은 LLM을 웹에 대한 데이터 추출기로 사용하면서 적절한 비용을 유지하는 데 도움이 됩니다.

적절한 작업에 적합한 도구!

Source:
https://dzone.com/articles/enhancing-web-scraping-with-large-language-models