Durante i miei primi giorni come Data Engineer (risalenti al 2016), avevo la responsabilità di estrarre dati da diversi siti web. Web scraping consiste nell’utilizzo di strumenti automatizzati per ottenere grandi quantità di dati dai siti web, solitamente dal loro 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.
Un pensiero che mi è venuto in mente quando ho iniziato a leggere su Large Language Models (LLMs) è stato: “Posso evitare tutti quei problemi che ho incontrato utilizzando LLMs per strutturare dati da pagine web?”
Vediamo se posso.
Strumenti e Tecniche di Web Scraping
Al tempo, gli strumenti principali che stavo utilizzando erano Requests, BeautifulSoup, e Selenium. Ogni servizio ha uno scopo diverso e è rivolto a diversi tipi di ambienti web.
- Requests è una libreria Python che può essere utilizzata per facilmente effettuare richieste HTTP. Questa libreria esegue operazioni GET e POST contro gli URL forniti nelle richieste. È spesso usata per recuperare contenuto HTML che può essere analizzato da BeautifulSoup.
- BeautifulSoup è una libreria Python per la parsing di documenti HTML e XML, che costruisce un albero di parsing dal codice sorgente della pagina che consente di accedere facilmente ai vari elementi della pagina. Di solito, viene abbinato ad altre librerie come Requests o Selenium che forniscono il codice HTML sorgente.
- Selenium viene principalmente utilizzato per siti web che hanno una quantità significativa di JavaScript coinvolto. A differenza di BeautifulSoup, Selenium non analizza semplicemente il codice HTML: interagisce con i siti web simulando azioni utente come clic e scorrimento. Ciò facilita l’estrazione dei dati da siti web che creano contenuti in modo dinamico.
Questi strumenti erano indispensabili quando cercavo di estrarre dati da siti web. Tuttavia, hanno anche posto alcune sfide: il codice, le etichette e gli elementi strutturali dovevano essere aggiornati regolarmente per adattarsi ai cambiamenti nella disposizione del sito web, complicando la manutenzione a lungo termine.
Cosa sono i Large Language Models (LLM)?
I Large Language Models (LLM) sono programmi di computer di prossima generazione che possono imparare leggendo e analizzando grandi quantità di dati di testo. In questa epoca, sono dotati della straordinaria capacità di scrivere in modo narrativo simile all’uomo rendendoli agenti efficienti nel processare il linguaggio e comprendere il linguaggio umano. La capacità eccezionale si è manifestata in quel tipo di situazione, dove il contesto del testo era davvero importante.
Integrazione di LLM nello scraping web
Il processo di web scraping può essere ottimizzato in misura notevole quando si implementano modelli linguistici gerarchici (LLM) al suo interno. Dobbiamo prendere il codice HTML di una pagina web e inserirlo nell’LLM, il quale estrarrà gli oggetti a cui si riferisce. Pertanto, questa tattica facilita la manutenzione, poiché la struttura di markup può evolversi, ma il contenuto stesso di solito non cambia.
Ecco come apparirebbe l’architettura di un sistema integrato di questo tipo:
- Ottenere HTML: Utilizzare strumenti come Selenium o Requests per recuperare il contenuto HTML di una pagina web. Selenium può gestire contenuti dinamici caricati con JavaScript, mentre Requests è adatto per pagine statiche.
- Analisi dell’HTML: Utilizzando BeautifulSoup, possiamo analizzare questo HTML come testo, rimuovendo così il rumore dall’HTML (piè di pagina, intestazione, ecc.).
- Creazione di modelli Pydantic: Digitare il modello Pydantic in cui eseguiremo lo scraping. Ciò garantisce che i dati digitati e strutturati rispettino gli schemi predefiniti.
- Generazione di prompt per LLM: Progettare un prompt che informi l’LLM quale informazione deve essere estratta.
- Elaborazione da parte dell’LLM: Il modello legge l’HTML, lo comprende e applica le istruzioni per il trattamento e la strutturazione dei dati.
- Uscita di dati strutturati: L’LLM fornirà l’output sotto forma di oggetti strutturati definiti dal modello Pydantic.
Questo flusso di lavoro aiuta a trasformare l’HTML (dati non strutturati) in dati strutturati utilizzando LLM, risolvendo problemi come progettazione non standard o modifica dinamica del codice sorgente HTML del web.
Integrazione di LangChain con BeautifulSoup e Pydantic
Questa è la pagina web statica selezionata per l’esempio. L’idea è quella di estrarre tutte le attività elencate lì e presentarle in modo strutturato.
Questo metodo estrarrà l’HTML grezzo dalla pagina web statica e lo pulirà prima che l’LLM lo elabori.
from bs4 import BeautifulSoup
import requests
def extract_html_from_url(url):
try:
# Recupera il contenuto HTML dall'URL utilizzando requests
response = requests.get(url)
response.raise_for_status() # Raise an exception for bad responses (4xx and 5xx)
# Analizza il contenuto HTML utilizzando BeautifulSoup
soup = BeautifulSoup(response.content, "html.parser")
excluded_tagNames = ["footer", "nav"]
# Escludi elementi con nomi di tag 'footer' e 'nav'
for tag_name in excluded_tagNames:
for unwanted_tag in soup.find_all(tag_name):
unwanted_tag.extract()
# Processa la zuppa per mantenere href negli elementi di collegamento
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
Il passo successivo è definire gli oggetti Pydantic che estrarremo dalla pagina web. Due oggetti devono essere creati:
Attività
: Questo è un oggetto Pydantic che rappresenta tutta la metadati relativa all’attività, con i suoi attributi e tipi di dati specificati. Abbiamo contrassegnato alcuni campi comeOpzionale
nel caso in cui non siano disponibili per tutte le attività. Fornire una descrizione, esempi e qualsiasi metadato aiuterà l’LLM ad avere una definizione migliore dell’attributo.ActivityScraper
: Questo è il wrapper Pydantic intorno aActivity
. L’obiettivo di questo oggetto è assicurare che l’LLM comprenda che è necessario strappare diverse attività.
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")
Infine, abbiamo la configurazione dell’LLM. Utilizzeremo la libreria LangChain, che fornisce un eccellente toolkit per iniziare.
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.
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
Il passo finale è richiamare la catena e recuperare i risultati.
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
Ecco come appaiono i dati. Ci vogliono 46 secondi per strappare l’intera pagina web.
[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 e Full Repository
I have created a quick demo using Streamlit available here.
Nella prima parte, ti viene presentato il modello. Puoi aggiungere tutte le righe necessarie e specificare il nome, il tipo e la descrizione di ogni attributo. Questo genererà automaticamente un modello Pydantic da utilizzare nel componente di scraping web.
La parte successiva ti permette di inserire un URL e strappare tutti i dati cliccando il pulsante sulla pagina web. Un pulsante di download apparirà quando lo scraping sarà terminato, permettendoti di scaricare i dati in formato JSON.
Sentiti libero di giocarci!
Conclusione
LLM offre nuove possibilità per estrarre dati in modo efficiente da dati non strutturati come siti web, PDF, ecc. L’automatizzazione dello scraping web da parte di LLM non solo risparmierà tempo, ma garantirà anche la qualità dei dati recuperati.
Tuttavia, inviare HTML grezzo al LLM potrebbe aumentare il costo dei token e renderlo inefficiente. Poiché l’HTML spesso include vari tag, attributi e contenuti, il costo può rapidamente aumentare.
Pertanto, è cruciale preprocessare e pulire l’HTML, rimuovendo tutti i metadati inutili e le informazioni non utilizzate. Questo approccio aiuterà a utilizzare il LLM come estrae dati per siti web mantenendo un costo decente.
Il giusto strumento per il lavoro giusto!
Source:
https://dzone.com/articles/enhancing-web-scraping-with-large-language-models