Webscraping verbeteren met grote taalmodellen: Een moderne aanpak

Tijdens mijn vroege dagen als Data Engineer (die teruggaan tot 2016) had ik de verantwoordelijkheid om gegevens van verschillende websites te schrapen. Web scraping gaat over het gebruik van geautomatiseerde tools om grote hoeveelheden gegevens van websites te verkrijgen, meestal uit hun 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.

Een gedachte die bij mij opkwam toen ik begon te lezen over Large Language Models (LLMs) was: “Kan ik al die valkuilen die ik tegengekomen ben met LLMs vermijden om gegevens van webpagina’s te structureren?”

Laten we eens kijken of ik dat kan.

Web Scraping Tools en Technieken

Op dat moment gebruikte ik voornamelijk Requests, BeautifulSoup, en Selenium. Elke dienst heeft een andere functie en is gericht op verschillende soorten webomgevingen.

  • Requests is een Python bibliotheek die kan worden gebruikt om HTTP-verzoeken gemakkelijk te doen. Deze bibliotheek voert GET en POST-operaties uit tegen de URLs die zijn opgegeven in de verzoeken. Het wordt vaak gebruikt om HTML-inhoud te halen die vervolgens door BeautifulSoup kan worden geparseerd.
  • BeautifulSoup is een Python bibliotheek voor het parseren van HTML en XML documenten, het construeert een parseboom van pagina-bron die toelaat om gemakkelijk toegang te krijgen tot de verschillende elementen op de pagina. Meestal wordt het gebruikt in combinatie met andere bibliotheken zoals Requests of Selenium die de HTML-broncode leveren.
  • Selenium wordt voornamelijk gebruikt voor websites waar veel JavaScript bij betrokken is. In tegenstelling tot BeautifulSoup, Selenium analyseert niet alleen HTML code: het interacteert met websites door gebruikersacties te emuleren zoals klikken en scrollen. Dit faciliteert het extraheren van gegevens van websites die inhoud dynamisch creëren.

Deze tools waren onmisbaar toen ik gegevens probeerde te extraheren van websites. Ze boden echter ook enkele uitdagingen: code, tags en structurele elementen moesten regelmatig worden bijgewerkt om wijzigingen in het ontwerp van de website te accommoderen, wat de langetermijnonderhoud compliceerde.

Wat zijn Grote Taalmodellen (LLMs)?

Grote Taalmodellen (LLMs) zijn volgende generatie computerprogramma’s die kunnen leren door het lezen en analyseren van enorme hoeveelheden tekstgegevens. Op dit moment zijn ze uitgerust met de verbazingwekkende mogelijkheid om op een menselijke manier te schrijven, waardoor ze efficiënte agenten zijn om taal te verwerken en de menselijke taal te begrijpen. De uitstekende vaardigheid kwam naar voren in dit soort situaties, waar de tekstcontext echt belangrijk was.

Integratie van LLMs in Web Scraping

Het proces van web scraping kan aanzienlijk worden geoptimaliseerd door LLMs in te zetten. We moeten de HTML-code van een webpagina opnemen in de LLM, die vervolgens de objecten haalt waarnaar wordt verwezen. Daardoor wordt onderhoud gemakkelijker, omdat de markupstructuur zich kan ontwikkelen, maar de inhoud zelf verandert meestal niet.

Hier is hoe de architectuur van zo’n geïntegreerd systeem eruit zou zien:

  1. HTML ophalen: Gebruik tools zoals Selenium of Requests om de HTML-inhoud van een webpagina op te halen. Selenium kan dynamische inhoud die met JavaScript wordt geladen aan, terwijl Requests geschikt is voor statische pagina’s.
  2. HTML parseren: Met BeautifulSoup kunnen we deze HTML parseren als tekst, waardoor de storingen uit de HTML (voettekst, koptekst, enz.) worden verwijderd.
  3. Pydantic-modellen maken: Typ het Pydantic model waarin we gaan scrapen. Dit zorgt ervoor dat de getypte en gestructureerde gegevens aan de vooraf gedefinieerde schema’s voldoen.
  4. Prompts genereren voor LLMs: Ontwerp een prompt die de LLM informeert over welke informatie moet worden geëxtraheerd.
  5. Verwerking door LLM: Het model leest de HTML, begrijpt deze en past de instructies voor gegevensverwerking en -structuur toe.
  6. Uitvoer van gestructureerde gegevens: De LLM zal de uitvoer leveren in de vorm van gestructureerde objecten die zijn gedefinieerd door het Pydantic-model.

Deze workflow helpt om HTML (ongestructureerde gegevens) om te zetten in gestructureerde gegevens met behulp van LLMs, waardoor problemen zoals niet-standaard ontwerp of dynamische aanpassing van de webbron HTML worden opgelost.

Integratie van LangChain met BeautifulSoup en Pydantic

Dit is de statische webpagina die voor het voorbeeld is geselecteerd. Het idee is om alle activiteiten die daar worden vermeld op te graven en ze op een gestructureerde manier te presenteren.

Deze methode zal de ruwe HTML van de statische webpagina extraheren en schoonmaken voordat de LLM ermee werkt.

Python

 

from bs4 import BeautifulSoup
import requests


def extract_html_from_url(url):
    try:
        # HTML-inhoud vanuit de URL ophalen met requests
        response = requests.get(url)
        response.raise_for_status()  # Raise an exception for bad responses (4xx and 5xx)

        # HTML-inhoud parseren met BeautifulSoup
        soup = BeautifulSoup(response.content, "html.parser")
        excluded_tagNames = ["footer", "nav"]
        # Elementen met tagnamen 'footer' en 'nav' uitsluiten
        for tag_name in excluded_tagNames:
            for unwanted_tag in soup.find_all(tag_name):
                unwanted_tag.extract()

        # Het soepje verwerken om hrefs in anker tags te behouden
        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

Het volgende stap is om de Pydantic objecten te definiëren die we van de webpagina gaan opgraven. Twee objecten moeten worden gemaakt:

  • Activiteit: Dit is een Pydantic object dat alle metadata vertegenwoordigt die verband houden met de activiteit, met zijn attributen en gegevenstypen gespecificeerd. We hebben sommige velden gemarkeerd als Optioneel voor het geval ze niet beschikbaar zijn voor alle activiteiten. Het verstrekken van een beschrijving, voorbeelden en eventuele metadata zal de LLM helpen om een beter beeld te krijgen van het attribuut.
  • ActivityScraper: Dit is de Pydantic wrapper rondom de Activity. Het doel van dit object is om ervoor te zorgen dat de LLM begrijpt dat het nodig is om verschillende activiteiten te schrapen.
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")

Tenslotte hebben we de configuratie van de LLM. We zullen de LangChain-bibliotheek gebruiken, die een uitstekend hulpmiddel biedt om aan de slag te gaan.

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

Het laatste stapje is om de ketting aan te roepen en de resultaten op te halen.

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

Hier is hoe de gegevens eruitzien. Het kost 46 seconden om de hele webpagina te schrapen.

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='€')
 ...
]

Demo en Volledige Repository

I have created a quick demo using Streamlit available here.

In het eerste deel word je geïntroduceerd bij het model. Je kunt zoveel rijen toevoegen als je nodig hebt en de naam, type en beschrijving van elk attribuut aangeven. Dit zal automatisch een Pydantic-model genereren om te worden gebruikt in het webscraping-onderdeel.

Het volgende deel stelt je in staat om een URL in te voeren en al het gegevens te schrapen door op de knop op de webpagina te klikken. Een downloadknop zal verschijnen wanneer het schrapen is afgerond, waardoor je de gegevens in JSON-formaat kunt downloaden.

Speel gerust wat mee!

Conclusie

LLM biedt nieuwe mogelijkheden voor het efficiënt verkrijgen van gegevens uit niet-gestructureerde gegevens zoals websites, PDFs, enz. De geautomatiseerde webscraping door LLM zal niet alleen tijd besparen, maar ook de kwaliteit van de opgehaalde gegevens garanderen.

Echter, het verzenden van onbewerkte HTML naar de LLM kan de tokenkosten verhogen en inefficiënt zijn. Aangezien HTML vaak verschillende tags, attributen en inhoud bevat, kan de kost snel oplopen. 

Daarom is het van cruciaal belang om de HTML voor te verwerken en schoon te maken, waarbij alle overbodige metadata en niet-gebruikte informatie wordt verwijderd. Deze aanpak zal helpen de LLM te gebruiken als gegevensextractie voor websites, terwijl een behoorlijke kost wordt onderhouden.

Het juiste gereedschap voor het juiste werk!

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