beautifulsoup4 & lxml
BeautifulSoup analisa HTML/XML bagunçado em uma árvore navegável - busca por tags, atributos, texto. Combine-o com lxml como backend do parser para velocidade e XPath quando os documentos crescem ou ficam malformados.
Busque em todas as páginas da documentação
BeautifulSoup analisa HTML/XML bagunçado em uma árvore navegável - busca por tags, atributos, texto. Combine-o com lxml como backend do parser para velocidade e XPath quando os documentos crescem ou ficam malformados.
from bs4 import BeautifulSoup
html = '<div class="item"><a href="/p/1">Widget</a><span class="price">$9</span></div>'
soup = BeautifulSoup(html, "lxml")
for item in soup.select(".item"):
name = item.find("a").get_text(strip=True)
price = item.find(class_="price").get_text(strip=True)
print(name, price)Quando usar isso:
from __future__ import annotations
from dataclasses import dataclass
import httpx
from bs4 import BeautifulSoup
@dataclass
class Product:
sku: str
title: str
price: str
def parse_catalog(html: str) -> list[Product]:
soup = BeautifulSoup(html, "lxml")
products: list[Product] = []
for card in soup.select("article.product"):
sku = card.get("data-sku")
title_el = card.select_one("h2.title")
price_el = card.select_one("span.price")
if not sku or not title_el or not price_el:
continue
products.append(
Product(
sku=sku,
title=title_el.get_text(strip=True),
price=price_el.get_text(strip=True),
)
)
return products
def fetch_catalog(url: str) -> list[Product]:
with httpx.Client(timeout=10.0, headers={"User-Agent": "catalog-bot/1.0"}) as client:
response = client.get(url)
response.raise_for_status()
return parse_catalog(response.text)
if __name__ == "__main__":
sample = """
<article class="product" data-sku="W1">
<h2 class="title">Widget</h2><span class="price">$9.00</span>
</article>
"""
print(parse_catalog(sample))O que isso demonstra:
select / select_oneget_text(strip=True) para texto normalizadohtml.parser (stdlib), lxml (C rápido), html5lib (mais flexível)..parent, .next_sibling, .find, .find_all, .select (CSS).tree.xpath("//div[@class='item']") quando CSS é complicado.from_encoding quando estiver incorreta.| Parser | Velocidade | Flexível | Dependência |
|---|---|---|---|
| lxml | Rápido | Moderado | libxml2 |
| html.parser | Lento | Moderado | nenhum |
| html5lib | Mais Lento | Muito | html5lib |
# Analisa XML com lxml diretamente para esquemas rigorosos
from lxml import etree
root = etree.fromstring(xml_bytes)
for node in root.xpath("//item[@id]"):
print(node.get("id"), node.text)data-*; testes de contrato em fixtures HTML.rel=next ou cursor da API.lxml iterparse.| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| API JSON Oficial | O provedor oferece API estável | HTML sem API e com baixa frequência de alteração |
selectolax | Velocidade máxima de análise | Precisa de exemplos do ecossistema BeautifulSoup |
| Playwright/Selenium | SPAs renderizados com JavaScript | HTML de servidor estático |
feedparser | Feeds RSS/Atom | Catálogos HTML arbitrários |
Use BeautifulSoup para ergonomia; backend lxml para velocidade. Use lxml diretamente quando precisar de XPath em XML rigoroso.
urllib.parse.urljoin(base_url, href) em valores a["href"] extraídos.
Mantenha fixtures HTML em tests/fixtures/ e afirme dataclasses analisadas - sem rede em testes unitários.
Ele pode "embelezar" ou reescrever tags - trate a saída como derivada, não como fonte autoritativa.
Use urllib.robotparser ou um framework de raspagem que verifica robots antes da busca.
Passe cookies de sessão via cliente httpx - nunca cometa credenciais; use gerenciador de segredos.
Limite a taxa, rotacione user agents de forma responsável, cacheie respostas ETag - não faça crawling agressivo.
pandas.read_html usa lxml/html5lib internamente - bom para extração de tabelas pontuais.
Registre namespaces no XPath do lxml: namespaces={"ns": "http://..."}.
A análise é limitada por CPU - execute parse_catalog(html) em asyncio.to_thread após a busca assíncrona.
Versões de Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026