Resumo: A extração de dados da Web com expressões regulares (regex) é ideal quando se precisa de padrões de texto curtos e previsíveis (preços, SKUs, e-mails, datas) a partir de código HTML em que já se confia. Combine o módulo re com o Beautiful Soup, limite os seus padrões a um nó analisado em vez de marcação bruta e mantenha as expressões regulares afastadas da análise completa da árvore HTML. Este guia apresenta um scraper funcional de títulos e preços, funcionalidades avançadas de expressões regulares e as armadilhas que afetam os scrapers reais em produção.Introdução
A maioria dos scrapers em Python acaba por chegar a um ponto em que os seletores CSS e o XPath deixam de ser suficientes. Tens o <div>, mas dentro dele está uma string como "$1,299.00 USD (incl. VAT)" e precisa apenas do número. É aí que o web scraping com expressões regulares mostra o seu valor: é uma técnica de extração de texto baseada em padrões que visa formas específicas dentro do HTML bruto ou do texto visível por trás de uma página, em vez de navegar pela árvore DOM.
Este guia destina-se a programadores Python de nível intermédio que já sabem como obter uma página com requests e analisá-la com o Beautiful Soup, e agora querem integrar expressões regulares nesse conjunto de ferramentas sem tornar o scraper frágil. Abordaremos quando o web scraping com regex é a escolha certa (e quando realmente não é), uma ficha de referência de tokens focada em scraping, um scraper funcional de títulos e preços que escreve CSV estruturado, e os recursos avançados re (grupos nomeados, lookarounds, flags, re.compile) que mantêm os padrões legíveis à medida que o projeto cresce. Seremos também honestos quanto aos limites das expressões regulares em HTML dinâmico e malformado, e em que situações deve recorrer a seletores ou a uma API de scraping gerida.
Quando a regex é a ferramenta certa para o scraping (e quando não é)
As expressões regulares são excelentes para padrões de texto curtos e bem definidos: preços, datas, ISBNs, números de telefone, hashes, parâmetros de consulta dentro de URLs. São uma má escolha para navegar em árvores HTML arbitrárias com tags aninhadas, atributos opcionais e espaços em branco inconsistentes.
Uma regra de decisão simples para o scraping na web com expressões regulares:
- Recorra à regex quando o campo tiver uma forma estável (
\d+\.\d{2}, um e-mail, um UUID), a página for HTML renderizado pelo servidor e já for possível isolar o nó circundante com um analisador. - Evite expressões regulares quando os dados estiverem enterrados em tags profundamente aninhadas, a marcação alterar nomes de classes a cada implementação ou a página for renderizada em JavaScript e os valores que pretende só aparecerem depois de o navegador executar os scripts.
Folha de referência de tokens de expressões regulares para scraping
Só precisa de um pequeno conjunto de tokens para quase todas as tarefas de scraping na Web com expressões regulares. A tabela abaixo é focada em scraping: cada exemplo é algo que pode realmente extrair do HTML.
|
Token |
O que corresponde |
Exemplo de scraping |
|---|---|---|
|
|
Qualquer dígito (0–9) |
|
|
|
Caractere de palavra (letras, dígitos, |
|
|
|
Qualquer espaço em branco |
Tolerância à formatação HTML irregular |
|
|
Qualquer caractere, exceto nova linha |
|
|
|
Início/fim de string (ou linha) |
Ancoragem de um nó de texto limpo |
|
|
0+, 1+, 0–1 repetições (greedy) |
|
|
|
Variantes não gananciosas |
|
|
|
Classe de caracteres |
|
|
|
Grupo de captura |
Extrair apenas o preço de |
|
|
Captura nomeada |
|
|
|
Lookahead / lookbehind |
|
|
|
Escape |
Corresponder a um literal |
Para qualquer coisa além disto, consulte a documentação do módulo Python re e o guia oficial de Expressões Regulares, em vez de copiar e colar de blogs aleatórios.
Passo a passo: extrair títulos e preços de produtos com Python
Para tornar isto mais concreto, vamos extrair uma página estática de listagem de produtos e recolher dois campos: o título do produto e o preço. Escolha qualquer sandbox ou loja de demonstração que tenha permissão para extrair; o padrão abaixo pressupõe HTML renderizado pelo servidor com um cartão por produto. As quatro subetapas abrangem a configuração do ambiente, a obtenção e isolamento de cartões, a escrita de padrões e o armazenamento da saída estruturada.
Configure o Python, o requests e o Beautiful Soup
Um ambiente virtual limpo mantém as dependências controladas e o histórico do shell organizado. O re vém incluído na biblioteca padrão, pelo que as únicas instalações de terceiros são o cliente HTTP e o analisador. Se estiver a avaliar diferentes ferramentas de extração, o nosso resumo de clientes HTTP para Python é uma boa leitura complementar.
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install requests beautifulsoup4import csv
import re
import requests
from bs4 import BeautifulSoupRecuperar a página e isolar os cartões de produto
Restringe sempre o âmbito antes de usares expressões regulares. Executar padrões num documento HTML inteiro é a forma de acidentalmente corresponderes à tag errada duas mil linhas mais abaixo. Usa o Beautiful Soup para extrair os cartões de produto e, em seguida, opera no HTML de cada cartão isoladamente. Se requests.get retornar um <body> e os dados residem numa <script> ou só carrega após a execução do JS, a expressão regular na resposta bruta não vai ajudar; precisas de um navegador headless ou de uma API de renderização.
URL = "https://example.com/products" # replace with a target you are allowed to scrape
html = requests.get(URL, timeout=15).text
soup = BeautifulSoup(html, "html.parser")
cards = soup.find_all("div", attrs={"data-testid": "product-card"})Escreva padrões de expressão regular para títulos e preços
Ancore os seus padrões em atributos estáveis, não em nomes de classes CSS com hash como css-7u5e79. Esses hash de classes são regenerados em cada implementação do front-end e o seu scraper irá avariar silenciosamente. Prefira data-* atributos, tags semânticas (<h4>, <h2>) ou itemprop marcação quando o site a disponibilizar.
TITLE_RE = re.compile(r'<h4[^>]*itemprop="name"[^>]*>(.*?)</h4>', re.DOTALL)
PRICE_RE = re.compile(r'<span[^>]*itemprop="price"[^>]*>\s*\$?([\d,]+\.\d{2})\s*</span>')Três coisas que vale a pena destacar quando se usa web scraping com expressões regulares nesta camada:
(.*?)não é não-greedy; sem o?sua correspondência de título iria alegremente abranger vários cartões.[^>]*permite que a tag tenha quaisquer outros atributos (class,id, ganchos de análise) sem quebrar a correspondência.re.DOTALLpermite que.corresponder a novas linhas, para que um título que quebra para uma nova linha ainda seja capturado.
Percorra os resultados e guarde-os num ficheiro estruturado
Dumps de texto simples são adequados para depuração, mas quase sempre se prefere CSV ou JSON para trabalhos posteriores. CSV com cabeçalhos explícitos torna a saída autoexplicativa e fácil de carregar no pandas ou numa folha de cálculo. Mantenha HTML bruto, CSV analisado e registos de execução em pastas separadas para que as reexecuções não se sobrescrevam.
rows = []
for card in cards:
html_chunk = str(card)
t = TITLE_RE.search(html_chunk)
p = PRICE_RE.search(html_chunk)
rows.append({
"title": t.group(1).strip() if t else "",
"price_usd": p.group(1) if p else "",
})
with open("data/products.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["title", "price_usd"])
writer.writeheader()
writer.writerows(rows)Para campos aninhados (variantes, especificações), mude para JSON.
Combine expressões regulares com o Beautiful Soup para uma extração mais limpa
As expressões regulares e um verdadeiro analisador HTML não são concorrentes; são camadas. O Beautiful Soup percorre a árvore e fornece-lhe uma cadeia de caracteres específica, e a utilização de expressões regulares com o Beautiful Soup transforma essa cadeia no campo exato que pretende. Isto é muito mais seguro do que executar web scraping com expressões regulares na resposta bruta.
Dois padrões que vale a pena memorizar. Primeiro, passe uma expressão regular compilada diretamente para find_all ou find para filtrar tags por valor de atributo:
price_tags = soup.find_all("span", class_=re.compile(r"^price"))Segundo, procure elementos cujo texto visível corresponda a um padrão:
in_stock = soup.find_all(string=re.compile(r"\bIn stock\b", re.IGNORECASE))Se quiseres uma exploração mais aprofundada do lado do analisador, o nosso guia do Beautiful Soup abrange seletores, navegação e casos extremos.
Padrões avançados de expressões regulares que os criadores de scrapers devem conhecer
Depois de dominar o básico, algumas re funcionalidades tornam a extração de dados da Web com expressões regulares muito mais fácil de manter.
- Grupos nomeados (
(?P<name>...)) substituem a indexação posicional frágil.m.group("price")é autoexplicativo e mantém-se mesmo com a reordenação do padrão. - As análises à frente e atrás permitem-lhe fazer correspondências sem consumir.
\d+(?= USD)captura um número apenas seUSDo seguir;(?<=Price:\s)\$\d+captura$199apenas após o rótulo literal. - Os sinalizadores mantêm os padrões curtos.
re.IGNORECASEparaIn Stockvsin stock,re.DOTALLassim.cruza as novas linhas,re.VERBOSEpor isso pode escrever padrões de várias linhas com comentários. re.compilevale a pena quando se rastreiam milhares de páginas: compile uma vez, reutilize ao longo do ciclo e obtenha um pequeno, mas real, aumento de velocidade.re.finditero stream faz as correspondências de forma preguiçosa, o que é mais amigo da memória do quefindallpara documentos enormes.
PRICE = re.compile(r"\$(?P<amount>[\d,]+\.\d{2})(?=\s*USD)", re.IGNORECASE)
for m in PRICE.finditer(page_text):
print(m.group("amount"))Armadilhas comuns e limites do web scraping com regex
Lista honesta de coisas que o vão fazer tropeçar:
- Nomes de classes com hash (
css-7u5e79 eag3qlw7) mudam a cada implementação. Em vez disso, baseie-sedata-*,itempropou em tags semânticas. - As tags aninhadas quebram a correspondência
(.*?)quando o HTML interno contém a mesma tag que está a tentar fechar. - HTML malformado (tags não fechadas, aspas incompatíveis) torna a expressão regular frágil; um analisador real tolera isso.
- O conteúdo renderizado por JavaScript simplesmente não está no corpo da resposta. As expressões regulares não conseguem conjurar dados que o servidor nunca enviou.
- Problemas de codificação surgem através de
&,'e aspas curvas; normalize o texto antes da correspondência.
Quando duas destas situações ocorrem ao mesmo tempo, mude para seletores ou uma API de renderização que devolva HTML pós-JS.
Expressões regulares vs. XPath e seletores CSS: qual escolher
Use seletores para a estrutura e expressões regulares para o texto dentro dessa estrutura. Os seletores CSS são concisos e rápidos para pesquisas baseadas em classes e tags; o XPath é mais expressivo quando precisa de eixos, posições ou predicados de texto. As expressões regulares entram em ação assim que tiver o nó certo e precisar de analisar a sua string. O nosso guia de XPath e a comparação entre XPath e seletores CSS aprofundam o assunto, caso esteja a escolher entre os dois.
Pontos-chave
- Trate o web scraping com expressões regulares como uma ferramenta de precisão para padrões de texto curtos e previsíveis; mantenha a navegação completa na árvore HTML no Beautiful Soup ou no lxml.
- Ancore sempre os padrões em atributos estáveis (
data-*,itemprop, tags semânticas), e não a nomes de classes CSS com hash que mudam a cada implementação. - Combine
find/find_allcomre.compilepara que os padrões sejam executados em nós isolados em vez de em todo o corpo da resposta. - Recorra a grupos nomeados, lookaheads
re.DOTALL,re.IGNORECASEere.compileassim que o seu scraper ultrapassar uma única página. - Guarde a saída como CSV (ou JSON para dados aninhados), com cabeçalhos explícitos e uma estrutura de pastas organizada para garantir a reprodutibilidade.
Perguntas frequentes
Posso extrair páginas renderizadas em JavaScript apenas com expressões regulares?
Não. A expressão regular corresponde a caracteres que já estão na resposta. Se os valores de que precisa forem injetados no DOM por JavaScript do lado do cliente, o HTML bruto devolvido por requests simplesmente não os contém. Precisa de um navegador headless (Playwright, Puppeteer, Selenium) ou de uma API de renderização que devolva o HTML pós-JS; só então poderá aplicar expressões regulares a essa saída.
Como posso testar padrões de expressões regulares antes de os colocar em produção?
Utilize um testador interativo, como o regex101 ou o pythex, para validar padrões em trechos de HTML representativos, selecionando a variante Python. Em seguida, adicione pequenos testes unitários que executem cada padrão num ficheiro de fixture guardado e verifiquem os grupos capturados. Os fixtures protegem-no quando o site muda, porque um teste com falha aponta para o padrão exato que falhou.
Devo usar re.compile() ao fazer scraping de muitas páginas?
Sim. re.compile() Analisa o padrão uma vez e reutiliza o objeto compilado em todas as chamadas, o que evita o custo de análises repetidas dentro de loops intensos. O ganho de desempenho numa única correspondência é pequeno, mas ao longo de milhares de páginas acumula-se. A maior vantagem é a legibilidade: os padrões compilados podem ficar no nível superior do módulo com nomes claros, em vez de literais de cadeia de caracteres embutidos.
Qual é a diferença entre correspondência gananciosa e não gananciosa ao extrair HTML?
Os quantificadores gananciosos (*, +) correspondem ao máximo de texto possível, o que pode engolir conteúdo em vários registos. As variantes não-gavanas (*?, +?) correspondem ao mínimo possível, parando na primeira fechadura válida. Para a extração de HTML, (.*?)</h4> captura corretamente um título; (.*)</h4> engoliria todo o documento até ao último </h4>.
Como lido com correspondências de várias linhas e espaços em branco irregulares em HTML extraído?
Pass re.DOTALL so . corresponde a novas linhas, e re.MULTILINE se fixar com ^ ou $ por linha. Para espaços irregulares dentro de tags, use \s* (zero ou mais espaços em branco, incluindo novas linhas) entre os tokens esperados, em vez de espaços literais. Normalize as entidades (&, ) e as aspas Unicode antes da correspondência, para que não quebrem silenciosamente padrões que, de outra forma, estariam corretos.
Conclusão e próximos passos
A extração de dados da Web com expressões regulares é uma ferramenta poderosa, mas não universal. Use-a onde ela realmente vale a pena: analisando strings curtas e previsíveis dentro de HTML que você já isolou com um analisador. Mantenha os seus padrões ancorados em atributos estáveis, dê preferência a grupos nomeados e padrões compilados, e mude para seletores ou uma camada de renderização no momento em que a página se tornar pesada em JavaScript ou a marcação ficar aninhada. A maioria dos scrapers de produção acaba por utilizar expressões regulares, Beautiful Soup e clientes HTTP em conjunto; escolha a camada que se adequa ao campo que está a extrair e fique por aí.
Se preferir não ter de se preocupar com proxies, tentativas de repetição e CAPTCHAs enquanto se concentra nos padrões, a WebScrapingAPI da nossa equipa devolve HTML renderizado e JSON estruturado por trás de um único ponto de extremidade, para que o seu re código Python e Beautiful Soup continuem a funcionar enquanto a camada de pedidos é gerida por nós. A partir daqui, a próxima leitura natural é o nosso guia mais abrangente de web scraping em Python e o manual de análise de dados para transformar campos extraídos em registos limpos.




