Web Scraping com BeautifulSoup: Guia
Aprenda web scraping com Python e BeautifulSoup. Extraia dados de sites, parse HTML, trate erros e siga boas práticas de scraping
Introdução
Web scraping é a técnica de extrair dados de páginas web automaticamente. Com Python e a biblioteca BeautifulSoup, você pode coletar informações de sites que não oferecem APIs, como preços de produtos, notícias, dados de pesquisa e muito mais.
Neste guia, vamos aprender a usar BeautifulSoup para extrair dados de páginas HTML, tratar erros e seguir boas práticas de scraping responsável.
Instalação
Instale BeautifulSoup e Requests:
pip install beautifulsoup4 requests
O beautifulsoup4 faz o parsing do HTML e o requests faz as requisições HTTP para baixar as páginas.
Primeiro scraping
Vamos extrair dados de uma página HTML simples:
import requests
from bs4 import BeautifulSoup
# Baixar a pagina
url = "https://books.toscrape.com/"
resposta = requests.get(url)
resposta.raise_for_status() # Levanta erro se a requisicao falhar
# Parsear o HTML
soup = BeautifulSoup(resposta.text, "html.parser")
# Extrair o titulo da pagina
titulo = soup.title.string
print(f"Titulo: {titulo}")
O site books.toscrape.com é um site de prática para web scraping, feito especificamente para aprendizado.
Navegando o HTML
Encontrando elementos
O BeautifulSoup oferece vários métodos para encontrar elementos:
# Encontrar o primeiro elemento por tag
primeiro_h1 = soup.find("h1")
# Encontrar por classe CSS
produtos = soup.find_all("article", class_="product_pod")
# Encontrar por ID
elemento = soup.find(id="meu-id")
# Encontrar por atributo
links = soup.find_all("a", attrs={"data-tipo": "externo"})
Usando seletores CSS
O método select() aceita seletores CSS, que são frequentemente mais práticos:
# Seletor de classe
produtos = soup.select("article.product_pod")
# Seletor de descendente
titulos = soup.select("article.product_pod h3 a")
# Seletor de atributo
links_externos = soup.select("a[href^='http']")
# Primeiro resultado apenas
primeiro = soup.select_one("h1")
Exemplo prático: extraindo livros
Vamos extrair informações de livros do site de prática:
import requests
from bs4 import BeautifulSoup
def extrair_livros(url):
resposta = requests.get(url)
resposta.raise_for_status()
soup = BeautifulSoup(resposta.text, "html.parser")
livros = []
for artigo in soup.select("article.product_pod"):
titulo = artigo.select_one("h3 a")["title"]
preco = artigo.select_one(".price_color").text
disponivel = artigo.select_one(".availability").text.strip()
estrelas = artigo.select_one("p.star-rating")["class"][1]
livros.append({
"titulo": titulo,
"preco": preco,
"disponivel": disponivel,
"estrelas": estrelas,
})
return livros
livros = extrair_livros("https://books.toscrape.com/")
for livro in livros[:5]:
print(f"{livro['titulo']} - {livro['preco']}")
Navegando entre páginas
Muitos sites dividem conteúdo em múltiplas páginas. Para coletar tudo, siga os links de paginação:
def extrair_todas_paginas(url_base):
todos_livros = []
pagina = 1
while True:
if pagina == 1:
url = url_base
else:
url = f"{url_base}catalogue/page-{pagina}.html"
resposta = requests.get(url)
if resposta.status_code != 200:
break
soup = BeautifulSoup(resposta.text, "html.parser")
livros = soup.select("article.product_pod")
if not livros:
break
for artigo in livros:
titulo = artigo.select_one("h3 a")["title"]
todos_livros.append(titulo)
# Verificar se existe proxima pagina
proxima = soup.select_one("li.next a")
if not proxima:
break
pagina += 1
return todos_livros
Extraindo texto e atributos
# Texto de um elemento
paragrafo = soup.find("p")
texto = paragrafo.text # Texto sem tags HTML
texto = paragrafo.get_text() # Equivalente
texto = paragrafo.get_text(strip=True) # Remove espacos extras
# Atributos de um elemento
link = soup.find("a")
href = link["href"] # Atributo href
href = link.get("href", "") # Com valor padrao se nao existir
# Todos os atributos
atributos = link.attrs # Dicionario com todos os atributos
Tratamento de erros
Scraping envolve muitas situações imprevisíveis. Trate erros adequadamente:
import requests
from bs4 import BeautifulSoup
import time
def scraping_seguro(url, tentativas=3):
headers = {
"User-Agent": "Mozilla/5.0 (compatible; MeuBot/1.0)"
}
for tentativa in range(tentativas):
try:
resposta = requests.get(url, headers=headers, timeout=10)
resposta.raise_for_status()
return BeautifulSoup(resposta.text, "html.parser")
except requests.exceptions.HTTPError as e:
print(f"Erro HTTP: {e}")
if resposta.status_code == 429: # Too Many Requests
print("Rate limit atingido, aguardando...")
time.sleep(60)
else:
break
except requests.exceptions.ConnectionError:
print(f"Erro de conexao. Tentativa {tentativa + 1}/{tentativas}")
time.sleep(5)
except requests.exceptions.Timeout:
print("Timeout. Tentando novamente...")
time.sleep(5)
return None
Salvando dados extraídos
Salvando em CSV
import csv
def salvar_csv(livros, arquivo):
with open(arquivo, "w", newline="", encoding="utf-8") as f:
escritor = csv.DictWriter(f, fieldnames=livros[0].keys())
escritor.writeheader()
escritor.writerows(livros)
salvar_csv(livros, "livros.csv")
Salvando em JSON
import json
def salvar_json(dados, arquivo):
with open(arquivo, "w", encoding="utf-8") as f:
json.dump(dados, f, ensure_ascii=False, indent=2)
salvar_json(livros, "livros.json")
Salvando com Pandas
import pandas as pd
df = pd.DataFrame(livros)
df.to_csv("livros.csv", index=False)
df.to_excel("livros.xlsx", index=False)
Lidando com HTML dinâmico
BeautifulSoup funciona apenas com HTML estático. Se o site carrega conteúdo via JavaScript, você precisará de ferramentas adicionais:
pip install requests-html
from requests_html import HTMLSession
session = HTMLSession()
resposta = session.get("https://exemplo.com")
resposta.html.render() # Renderiza JavaScript
soup = BeautifulSoup(resposta.html.html, "html.parser")
Para sites mais complexos, considere usar Selenium ou Playwright.
Boas práticas e ética
Web scraping deve ser feito de forma responsável:
- Respeite o robots.txt: verifique
https://site.com/robots.txtantes de fazer scraping - Limite a frequência: adicione delays entre requisições com
time.sleep() - Identifique-se: use um User-Agent que identifique seu bot
- Não sobrecarregue o servidor: faça requisições em intervalos razoáveis
- Verifique os termos de uso: alguns sites proíbem scraping explicitamente
- Prefira APIs: se o site oferece uma API, use-a em vez de scraping
- Cache: salve páginas baixadas para evitar requisições repetidas durante o desenvolvimento
import time
for url in urls:
dados = scraping_seguro(url)
processar(dados)
time.sleep(2) # Espere 2 segundos entre requisicoes
Conclusão
Web scraping com BeautifulSoup e Python é uma habilidade valiosa para coletar dados que não estão disponíveis via APIs. A combinação de Requests para baixar páginas e BeautifulSoup para parsear HTML é simples e poderosa para a maioria dos casos. Lembre-se sempre de praticar scraping responsável, respeitando os limites dos servidores e os termos de uso dos sites que você acessa.