Um guia para seletores HTML para Web Scraping

Guias, Raspagem, Python, 08/11/20245 minutos de leitura

Os selectores HTML são fundamentais para a recolha de dados da Web, permitindo aos programadores visar elementos específicos de uma página Web. Ao utilizar estes selectores, os programadores podem extrair dados com precisão.

O Web scraping envolve a obtenção de dados de sítios Web através da navegação na sua estrutura HTML. Os selectores HTML são cruciais, permitindo-lhe identificar etiquetas, atributos ou conteúdos específicos. Quer se trate de extrair preços de produtos ou cabeçalhos, os selectores são o seu guia.

A utilização de selectores HTML simplifica eficazmente a extração de dados e reduz os erros. Ajudam-no a concentrar-se em elementos importantes, poupando tempo e esforço na recolha de informações de fontes online.

Neste blogue, vamos explorar a forma de utilizar os selectores abaixo com Python e a biblioteca"Beautifulsoup":

  • Seletores de Id
  • Seletores de classe
  • Selectores de atributos
  • Selectores hierárquicos
  • Combinação destes selectores

Selectores de ID

Em HTML, os IDs são identificadores únicos atribuídos a elementos específicos, assegurando que não há dois elementos que partilhem o mesmo ID. Esta exclusividade faz com que os selectores de ID sejam ideais para visar elementos singulares numa página Web. Por exemplo, se estiver a recolher uma página Web com várias secções, cada secção pode ter o seu próprio ID, permitindo-lhe extrair dados de uma secção específica sem interferência.

Vejamos, por exemplo este sítio Web, especialmente o elemento abaixo <div id="pages"> ...</div>

Este elemento contém outros elementos HTML aninhados, mas o mais importante é que este elemento é único neste sítio Web e podemos tirar partido deste cenário, por exemplo, quando quisermos extrair secções específicas do sítio Web. Neste caso, este elemento inclui alguns outros artigos que explicaremos com os outros selectores abaixo. Eis o aspeto desta secção da página:

Vamos explorar um exemplo simples utilizando as bibliotecas "requests" e "bs4" do Python:

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find the div with id="pages"
   pages_div = soup.find("div", id="pages")
  
   # Step 4: Display the content or handle it as needed
   if pages_div:
       print("Content of the div with id='pages':")
       print(pages_div.text.strip())
   else:
       print("No div with id='pages' found.")
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Explicação:

  • Enviar um pedido: A biblioteca de pedidos envia um pedido GET para obter o conteúdo HTML do URL de destino.
  • Analisar HTML: BeautifulSoup analisa o HTML, permitindo-nos pesquisar a estrutura do documento.
  • Find Specific <div>: Utilizamos soup.find("div", id="pages") para localizar o <div> elemento com id="páginas".
  • Conteúdo do ecrã: Se o <div> for encontrado, imprimimos o seu conteúdo. Se não for, uma mensagem indica que está em falta.

Limitações dos selectores de ID:

Os selectores de ID são poderosos, mas têm limitações. As IDs dinâmicas que mudam a cada carregamento de página podem dificultar a extração de dados consistentes. Nestas situações, pode ser necessário utilizar selectores alternativos para obter resultados fiáveis.

Seletores de classe

Os selectores de classe são flexíveis porque permitem direcionar grupos de elementos que partilham a mesma classe. Isto torna-os essenciais para páginas Web com elementos recorrentes. Por exemplo, um sítio Web que apresente uma lista de produtos pode atribuir a mesma classe a cada item do produto.

Vamos dar novamente um exemplo utilizando este sítio Web. Acima identificámos um <div id="pages"> utilizando o Seletor de ID e, neste elemento div, existem alguns artigos que têm a mesma classe.

Como se pode ver, temos quatro elementos com a mesma classe <div class="page">

Eis o seu aspeto no sítio Web:

No código abaixo, seleccionaremos todos os elementos com a classe "page", que devolverá uma lista que pode ser utilizada para análise posterior.

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all elements with class="page"
   page_elements = soup.find_all("div", class_="page")
  
   # Step 4: Save each element's text content in a list
   pages_list = [page.text.strip() for page in page_elements]
  
   print("Content of elements with class 'page':")
   for i, page in enumerate(pages_list, start=1):
       print(f"Page {i}:")
       print(page)
       print("-" * 20)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Explicação:

  • Enviar um pedido: Utilizamos pedidos para enviar um pedido GET para o URL, recuperando o conteúdo HTML da página Web.
  • Analisar HTML com BeautifulSoup: Se o pedido for bem sucedido, a BeautifulSoup analisa o HTML, permitindo-nos pesquisar e interagir com elementos.
  • Procurar elementos por classe: Utilizamos soup.find_all("div", class_="page") para localizar todos os <div> elementos com a classe "page", devolvendo-os como uma lista.
  • Guardar na lista: Extraímos e limpamos o conteúdo de texto de cada elemento, guardando-o numa lista chamada pages_list.

Limitações dos selectores de classes

Ao utilizar selectores de classe, tenha em atenção potenciais problemas, como a seleção de elementos não pretendidos. Múltiplas classes num único elemento podem exigir uma filtragem adicional para obter uma seleção precisa.

Selectores de atributos

Os selectores de atributos permitem-lhe direcionar elementos com base na presença, valor ou valor parcial de atributos específicos em etiquetas HTML. Isto é particularmente útil quando as classes ou IDs não são únicas ou quando é necessário filtrar elementos com atributos dinâmicos, tais como dados-* ou href valores nas ligações.

No exemplo seguinte, seleccionaremos todas as imagens neste página web e extrair os seus URLs de origem ou src atributos. Este é o aspeto do elemento na estrutura html e na visualização da página web:

No código a seguir, utilizamos o BeautifulSoup para analisar todos os <img> elementos, extraindo os seus src e armazenando-os numa lista.

import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/frames/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all <img> elements with a 'src' attribute
   image_elements = soup.find_all("img", src=True)
  
   # Step 4: Save the 'src' attributes in a list
   images_list = [img['src'] for img in image_elements]
  
   print("Image sources found on the page:")
   for i, src in enumerate(images_list, start=1):
       print(f"Image {i}: {src}")
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Limitações dos selectores de classes

Os selectores de atributos só podem selecionar elementos com atributos estáticos, o que os torna menos eficazes para conteúdos dinâmicos, como elementos carregados através de JavaScript. Dependem de estruturas HTML estáveis, pelo que alterações frequentes da disposição do sítio Web podem perturbá-los. Além disso, não podem gerir filtros complexos ou condições múltiplas, o que limita a sua precisão. Podem também detetar elementos não pretendidos se atributos como classe ou nome forem partilhados por vários elementos.

Selectores hierárquicos

Os selectores hierárquicos permitem-lhe selecionar elementos HTML com base na sua posição e relação com outros elementos na estrutura HTML. Esta abordagem é particularmente útil quando se trabalha com tabelas ou listas aninhadas, em que os dados são organizados num formato pai-filho.

Neste exemplo, estamos a utilizar selectores hierárquicos para extrair dados de uma tabela de estatísticas de equipas de hóquei encontrada em esta página web.
A tabela contém linhas <tr> representando cada equipa, e cada linha contém células <td> com informações como o nome da equipa, o ano, as vitórias e as derrotas. Cada linha tem o class="equipa"identificando-o como uma entrada relevante nos nossos dados. Ao navegar a partir do <table> to each <tr> and then to each <td>Se o utilizador tiver uma visão geral dos dados, pode capturá-los de forma eficiente e estruturada.

Abaixo, encontrará duas imagens para o ajudar a visualizar onde esta tabela está localizada na estrutura HTML e como aparece na página Web real.

Agora, vejamos o código abaixo para ver como os selectores hierárquicos podem ser utilizados para extrair estes dados:

import requests
from bs4 import BeautifulSoup

url = "https://www.scrapethissite.com/pages/forms/"

# Step 1: Send a GET request to the website
response = requests.get(url)

if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Step 3: Find all rows in the table with class="team"
   teams_data = []
   team_rows = soup.find_all("tr", class_="team")
  
   # Step 4: Extract and store each team's data
   for row in team_rows:
       team = {
           "name": row.find("td", class_="name").text.strip(),
           "year": row.find("td", class_="year").text.strip(),
           "wins": row.find("td", class_="wins").text.strip(),
           "losses": row.find("td", class_="losses").text.strip(),
           "ot_losses": row.find("td", class_="ot-losses").text.strip(),
           "win_pct": row.find("td", class_="pct").text.strip(),
           "goals_for": row.find("td", class_="gf").text.strip(),
           "goals_against": row.find("td", class_="ga").text.strip(),
           "goal_diff": row.find("td", class_="diff").text.strip(),
       }
       teams_data.append(team)
  
   # Step 5: Display the extracted data
   for team in teams_data:
       print(team)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Limitações dos selectores hierárquicos

Os selectores hierárquicos dependem da estrutura HTML, pelo que as alterações na disposição podem facilmente interromper o script de exploração. Estão também limitados a conteúdo estático e não podem aceder a elementos carregados dinamicamente por JavaScript. Estes selectores requerem frequentemente uma navegação precisa através de relações pai-filho, o que pode ser um desafio em estruturas profundamente aninhadas. Além disso, podem ser ineficientes na extração de dados dispersos, uma vez que têm de atravessar vários níveis para chegar a elementos específicos.

Utilizar selectores combinados para uma melhor segmentação

Cada tipo de seletor tem uma finalidade única, e a sua combinação permite-nos navegar e capturar dados com precisão a partir de conteúdo aninhado ou estruturado. Por exemplo, a utilização de um seletor de ID pode ajudar a localizar a área de conteúdo principal, os selectores de classe podem isolar elementos repetidos, os selectores de atributo podem extrair ligações ou imagens específicas e os selectores hierárquicos podem alcançar elementos aninhados em secções específicas. Em conjunto, estas técnicas proporcionam uma abordagem poderosa para a recolha de dados estruturados.

import requests
from bs4 import BeautifulSoup
# Target URL
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
   # Step 2: Parse the HTML content with BeautifulSoup
   soup = BeautifulSoup(response.text, 'html.parser')
  
   # Use ID selector to find the main content
   main_content = soup.find(id="pages")
  
   # Use class selector to find each "page" section
   pages = main_content.find_all("div", class_="page") if main_content else []
  
   # Extract details from each "page" section using hierarchical selectors
   for page in pages:
       # Use hierarchical selector to find title link and URL within each "page"
       title_tag = page.find("h3", class_="page-title")
       title = title_tag.text.strip() if title_tag else "No Title"
       link = title_tag.find("a")["href"] if title_tag and title_tag.find("a") else "No Link"
      
       # Use class selector to find the description
       description = page.find("p", class_="lead session-desc").text.strip() if page.find("p", class_="lead session-desc") else "No Description"
      
       print(f"Title: {title}")
       print(f"Link: {link}")
       print(f"Description: {description}")
       print("-" * 40)
else:
   print(f"Failed to retrieve the webpage. Status code: {response.status_code}")

Explicação do Código

  • Seletor de ID: Começamos por localizar a área de conteúdo principal com id="pages", que contém as secções de que precisamos.
  • Seletor de classes: Dentro desta área principal, utilizamos class="página" para encontrar cada bloco de conteúdo individual que representa uma secção de interesse.
  • Seletores hierárquicos: Em cada bloco de "página", utilizamos:
    • page.find("h3", class_="page-title") para encontrar o título.
    • title_tag.find("a")["href"] para obter o URL da ligação a partir da etiqueta de âncora no título.
  • Seletor de atributos: Acedemos ao atributo href de cada ligação para captar os URLs exactos associados a cada secção.
  • Saída: O script imprime o título, o link e a descrição de cada secção, dando uma visão estruturada dos dados extraídos da página.

Conclusão

Na recolha de dados da Web, saber como utilizar selectores HTML pode melhorar significativamente as suas capacidades de extração de dados, permitindo-lhe recolher informações importantes com precisão. Seletores como ID, classe, atributo e seletores hierárquicos têm utilizações específicas para diferentes tarefas de recolha de dados. Ao utilizar estas ferramentas em conjunto, pode lidar com uma vasta gama de desafios de recolha de dados da Web com confiança.

Para praticar, sites como Scrape This Site e Books to Scrape oferecem excelentes exemplos para o ajudar a aperfeiçoar as suas capacidades. E se precisar de ajuda ou quiser se conectar com outras pessoas interessadas em raspagem da Web, sinta-se à vontade para participar do nosso canal do Discord em https://discord.com/invite/scrape.

Boa raspagem!