Mejorando el Web Scraping con Grandes Modelos de Lenguaje: Un Enfoque Moderno

Durante mis primeros días como Ingeniero de Datos (que datan de 2016), tuve la responsabilidad de extraer datos de diferentes sitios web. Web scraping consiste en utilizar herramientas automatizadas para obtener grandes cantidades de datos de los sitios web, generalmente desde su 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.

Una idea que se me ocurrió cuando comencé a leer sobre Modelos de Lenguaje Grande (LLMs) fue: “¿Puedo evitar todos esos problemas que enfrenté usando LLMs para estructurar datos de páginas web?”

Veamos si puedo.

Herramientas y Técnicas de Web Scraping

En ese momento, las principales herramientas que estaba utilizando eran Requests, BeautifulSoup, y Selenium. Cada servicio tiene un propósito diferente y está dirigido a diferentes tipos de entornos web.

  • Requests es una biblioteca Python que se puede utilizar para realizar fácilmente solicitudes HTTP. Esta biblioteca realiza operaciones GET y POST contra las URL proporcionadas en las solicitudes. Se utiliza con frecuencia para recuperar contenido HTML que puede ser analizado por BeautifulSoup.
  • BeautifulSoup es una biblioteca de Python para analizar documentos HTML y XML, construye un árbol de análisis a partir del código fuente de la página que permite acceder fácilmente a los diversos elementos de la página. Por lo general, se asocia con otras bibliotecas como Requests o Selenium que proporcionan el código fuente HTML.
  • Selenium se emplea principalmente para sitios web que involucran mucho JavaScript. A diferencia de BeautifulSoup, Selenium no analiza simplemente el código HTML: interactúa con los sitios web simulando acciones de usuarios como clics y desplazamientos. Esto facilita la extracción de datos de sitios web que crean contenido dinámicamente.

Estas herramientas fueron imprescindibles cuando intentaba extraer datos de sitios web. Sin embargo, también plantearon algunos desafíos: el código, las etiquetas y los elementos estructurales debían actualizarse regularmente para adaptarse a los cambios en el diseño del sitio web, lo que complicaba el mantenimiento a largo plazo.

¿Qué son los Modelos de Lenguaje Grande (LLMs)?

Modelos de Lenguaje Grande (LLMs) son programas informáticos de próxima generación que pueden aprender leyendo y analizando grandes cantidades de datos de texto. En esta era, tienen la asombrosa capacidad de escribir de manera narrativa similar a la humana, lo que los convierte en agentes eficientes para procesar el lenguaje y comprender el lenguaje humano. La habilidad excepcional se destacó en ese tipo de situación, donde el contexto del texto era realmente importante.

Integrando LLMs en el Web Scraping

El proceso de web scraping puede optimizarse en gran medida al implementar LLMs en él. Necesitamos tomar el código HTML de una página web y alimentarlo al LLM, que extraerá los objetos a los que se refiere. Por lo tanto, esta táctica ayuda a facilitar el mantenimiento, ya que la estructura de marcado puede evolucionar, pero el contenido en sí no suele cambiar.

Aquí está cómo se vería la arquitectura de un sistema integrado de este tipo:

  1. Obtener HTML : Utilice herramientas como Selenium o Requests para obtener el contenido HTML de una página web. Selenium puede manejar contenido dinámico cargado con JavaScript, mientras que Requests es adecuado para páginas estáticas.
  2. Analizar HTML : Usando BeautifulSoup, podemos analizar este HTML como texto, eliminando así el ruido del HTML (pie de página, encabezado, etc.).
  3. Crear modelos Pydantic : Escriba el modelo Pydantic en el que vamos a raspar. Esto garantiza que los datos escritos y estructurados se ajusten a los esquemas predefinidos.
  4. Generar prompts para LLMs : Diseñe un aviso que informará al LLM de qué información debe extraerse.
  5. Procesamiento por LLM : El modelo lee el HTML, lo entiende y emplea las instrucciones para el procesamiento y estructuración de datos.
  6. Salida de datos estructurados : El LLM proporcionará la salida en forma de objetos estructurados definidos por el modelo Pydantic.

Este flujo de trabajo ayuda a transformar HTML (datos no estructurados) en datos estructurados utilizando modelos de lenguaje masivo (LLMs), resolviendo problemas como diseño no estándar o modificación dinámica del HTML fuente de la web.

Integración de LangChain con BeautifulSoup y Pydantic

Esta es la página web estática seleccionada para el ejemplo. La idea es raspar todas las actividades listadas allí y presentarlas de manera estructurada.

Este método extraerá el HTML crudo de la página web estática y lo limpiará antes de que el LLM lo procese.

Python

 

from bs4 import BeautifulSoup
import requests


def extract_html_from_url(url):
    try:
        # Obtener el contenido HTML de la URL usando requests
        response = requests.get(url)
        response.raise_for_status()  # Raise an exception for bad responses (4xx and 5xx)

        # Analizar el contenido HTML usando BeautifulSoup
        soup = BeautifulSoup(response.content, "html.parser")
        excluded_tagNames = ["footer", "nav"]
        # Excluir elementos con nombres de etiquetas 'footer' y 'nav'
        for tag_name in excluded_tagNames:
            for unwanted_tag in soup.find_all(tag_name):
                unwanted_tag.extract()

        # Procesar la sopa para mantener los hrefs en las etiquetas de anclaje
        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

El siguiente paso es definir los objetos Pydantic que vamos a raspar de la página web. Se necesitan crear dos objetos:

  • Actividad: Este es un objeto Pydantic que representa todos los metadatos relacionados con la actividad, con sus atributos y tipos de datos especificados. Hemos marcado algunos campos como Opcional en caso de que no estén disponibles para todas las actividades. Proporcionar una descripción, ejemplos y cualquier metadato ayudará al LLM a tener una mejor definición del atributo.
  • ActivityScraper: Este es el envoltorio de Pydantic alrededor de Activity. El objetivo de este objeto es garantizar que el LLM entienda que necesita raspar varias actividades.
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")

Finalmente, tenemos la configuración del LLM. Utilizaremos la biblioteca LangChain, que proporciona un excelente kit de herramientas para comenzar.

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

El paso final es invocar la cadena y recuperar los resultados.

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

Así es como se ve los datos. Toma 46 segundos raspar toda la página web.

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 y Repositorio Completo

I have created a quick demo using Streamlit available here.

En la primera parte, se te presenta el modelo. Puedes agregar tantas filas como necesites y especificar el nombre, tipo y descripción de cada atributo. Esto generará automáticamente un modelo Pydantic para ser utilizado en el componente de raspado web.

La siguiente parte te permite ingresar una URL y raspar todos los datos haciendo clic en el botón en la página web. Aparecerá un botón de descarga cuando haya terminado el raspado, permitiéndote descargar los datos en formato JSON.

¡Siéntete libre de jugar con ello!

Conclusión

LLM proporciona nuevas posibilidades para extraer datos de manera eficiente de datos no estructurados como páginas web, PDFs, etc. La automatización del raspado web por parte de LLM no solo ahorrará tiempo sino que también asegurará la calidad de los datos recuperados.

Sin embargo, enviar HTML sin procesar al LLM podría aumentar el costo de los tokens y hacerlo ineficiente. Dado que el HTML a menudo incluye varios tags, atributos y contenido, el costo puede aumentar rápidamente.

Por lo tanto, es crucial preprocesar y limpiar el HTML, eliminando todo el metadato innecesario y la información no utilizada. Este enfoque ayudará a usar el LLM como extractor de datos para webs manteniendo un costo decente.

¡La herramienta adecuada para el trabajo adecuado!

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