Aprimorando Web Scraping com Grandes Modelos de Linguagem: Uma Abordagem Moderna

Durante os primeiros dias como Engenheiro de Dados (que remontam a 2016), tive a responsabilidade de coletar dados de diferentes websites. Web scraping envolve o uso de ferramentas automatizadas para obter grandes quantidades de dados dos sites, geralmente a partir de seu 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.

Uma ideia que me ocorreu quando comecei a ler sobre Large Language Models (LLMs) foi: “Posso evitar todos esses problemas que enfrentei usando LLMs para estruturar dados de páginas da web?”

Vamos ver se consigo.

Ferramentas e Técnicas de Web Scraping

Naquela época, as principais ferramentas que eu estava usando eram Requests, BeautifulSoup, e Selenium. Cada serviço tem um propósito diferente e é direcionado a diferentes tipos de ambientes da web.

  • Requests é uma biblioteca Python que pode ser usada para facilmente fazer requisições HTTP. Essa biblioteca realiza operações GET e POST contra URLs fornecidas nas requisições. É frequentemente usada para buscar conteúdo HTML que pode ser analisado por BeautifulSoup.
  • BeautifulSoup é uma biblioteca Python para a análise de documentos HTML e XML, construindo uma árvore de análise a partir do código-fonte da página que permite acessar facilmente os diversos elementos na página. Geralmente, é usada em conjunto com outras bibliotecas como Requests ou Selenium que fornecem o código HTML de origem.
  • Selenium é principalmente empregado para sites que envolvem muito JavaScript. Ao contrário de BeautifulSoup, Selenium não analisa simplesmente o HTML do código: interage com os sites simulando ações do usuário como cliques e rolagem. Isso facilita a extração de dados de sites que criam conteúdo dinamicamente.

Essas ferramentas eram indispensáveis quando eu tentava extrair dados de sites. No entanto, também apresentavam alguns desafios: o código, tags e elementos estruturais tinham que ser atualizados regularmente para acomodar mudanças na disposição do site, complicando a manutenção a longo prazo.

O que são Modelos de Linguagem Grande (LLMs)?

Modelos de Linguagem Grande (LLMs) são programas de computador de próxima geração que podem aprender lendo e analisando vastas quantidades de dados de texto. Nesta época, eles têm a incrível capacidade de escrever em uma narrativa semelhante a humana, tornando-os agentes eficientes para processar linguagem e compreender a linguagem humana. A habilidade excepcional se destacou nesse tipo de situação, onde o contexto do texto era realmente importante.

Integrando LLMs em Web Scraping

O processo de raspagem de dados pode ser otimizado em grande medida ao implementar LLMs (Modelos de Linguagem de Grande Escala) nele. Precisamos pegar o código HTML de uma página da web e alimentá-lo no LLM, que extrairá os objetos a que se refere. Portanto, essa tática ajuda a facilitar a manutenção, pois a estrutura de marcação pode evoluir, mas o conteúdo em si geralmente não muda.

Veja como seria a arquitetura de um sistema integrado assim:

  1. Obtendo HTML: Use ferramentas como Selenium ou Requests para buscar o conteúdo HTML de uma página da web. O Selenium pode lidar com conteúdo dinâmico carregado com JavaScript, enquanto o Requests é adequado para páginas estáticas.
  2. Analisando HTML: Usando BeautifulSoup, podemos analisar esse HTML como texto, removendo o ruído do HTML (rodapé, cabeçalho, etc.).
  3. Criando modelos Pydantic: Digite o modelo Pydantic no qual vamos fazer a raspagem. Isso garante que os dados digitados e estruturados sigam os esquemas pré-definidos.
  4. Gerando prompts para LLMs: Crie um prompt que informará ao LLM que informações precisam ser extraídas.
  5. Processamento pelo LLM: O modelo lê o HTML, o entende e usa as instruções para processar e estruturar os dados.
  6. Saída de dados estruturados: O LLM fornecerá a saída na forma de objetos estruturados definidos pelo modelo Pydantic.

Este fluxo de trabalho ajuda a transformar HTML (dados não estruturados) em dados estruturados usando LLMs, resolvendo problemas como design não padronizado ou modificação dinâmica da fonte HTML da web.

Integração de LangChain com BeautifulSoup e Pydantic

Esta é a página da web estática selecionada para o exemplo. A ideia é raspar todas as atividades listadas lá e apresentá-las de maneira estruturada.

Este método extrairá o HTML bruto da página da web estática e o limpará antes de o LLM processá-lo.

Python

 

from bs4 import BeautifulSoup
import requests


def extract_html_from_url(url):
    try:
        # Buscar o conteúdo HTML da URL usando requests

        response = requests.get(url)
        response.raise_for_status()  # Raise an exception for bad responses (4xx and 5xx)

        # Analisar o conteúdo HTML usando BeautifulSoup

        soup = BeautifulSoup(response.content, "html.parser")
        excluded_tagNames = ["footer", "nav"]
        # Excluir elementos com nomes de tags 'footer' e 'nav'

        for tag_name in excluded_tagNames:
            for unwanted_tag in soup.find_all(tag_name):
                unwanted_tag.extract()

        # Processar a sopa para manter hrefs nos tags de âncora

        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

O próximo passo é definir os objetos Pydantic que vamos raspar da página da web. Dois objetos precisam ser criados:

  • Atividade: Este é um objeto Pydantic que representa todos os metadados relacionados à atividade, com seus atributos e tipos de dados especificados. Marcamos alguns campos como Opcional  caso eles não estejam disponíveis para todas as atividades. Fornecer uma descrição, exemplos e quaisquer metadados ajudará o LLM a ter uma definição melhor do atributo.
  • ActivityScraper: Este é o wrapper Pydantic em torno do Activity. O objetivo deste objeto é garantir que o LLM compreenda que é necessário raspar várias atividades.
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, temos a configuração do LLM. Utilizaremos a biblioteca LangChain, que fornece uma excelente ferramenta para começar.

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

O passo final é invocar a cadeia e recuperar os 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

Aqui está como os dados se parecem. Leva 46 segundos para raspar toda a página da 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 e Repositório Completo

I have created a quick demo using Streamlit available here.

Na primeira parte, você é apresentado ao modelo. Você pode adicionar quantas linhas precisar e especificar o nome, tipo e descrição de cada atributo. Isso automaticamente gerará um modelo Pydantic a ser usado no componente de raspagem de dados da web.

A próxima parte permite que você insira uma URL e raspe todos os dados clicando no botão na página da web. Um botão de download aparecerá quando a raspagem terminar, permitindo que você baixe os dados em formato JSON.

Sinta-se à vontade para brincar com isso!

Conclusão

O LLM proporciona novas possibilidades para extrair dados de forma eficiente de dados não estruturados, como sites, PDFs, etc. A automatização da raspagem de dados pelo LLM não apenas economizará tempo, mas também garantirá a qualidade dos dados recuperados.

No entanto, enviar HTML bruto para o LLM pode aumentar o custo de tokens e torná-lo ineficiente. Como o HTML frequentemente inclui vários tags, atributos e conteúdo, o custo pode aumentar rapidamente. 

Portanto, é crucial pré-processar e limpar o HTML, removendo todo o metadado desnecessário e informação não utilizada. Essa abordagem ajudará a usar o LLM como extraidor de dados para sites, mantendo um custo decente.

A ferramenta certa para o trabalho certo!

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