Este é o terceiro artigo da série. Em «Parser do DOM» aprendemos a transformar a página em uma árvore de nós e, no artigo sobre seletores CSS, a endereçar com precisão os elementos necessários dessa árvore. Mas, quando o nó já foi localizado, dentro dele costuma haver texto «sujo»: «Preço: 12 990 € (antes 15 990)», um telefone com caracteres a mais, um código de referência misturado à descrição. É para extrair dessa string exatamente o número ou o código que existem as expressões regulares.
Uma expressão regular (regex) é um padrão que descreve um conjunto de strings. O motor de regex percorre o texto e encontra os trechos que se encaixam no padrão. No scraping de sites, é uma ferramenta indispensável de limpeza final e extração de dados.
Quando as regex são necessárias — e quando não
Primeiro, um aviso importante. Não se faz o parsing do HTML inteiro com expressões regulares. O HTML é uma estrutura aninhada e não regular; tentar desmontá-la com um único padrão leva a um código frágil e ilegível. Para navegar pela marcação existem os parsers do DOM e os seletores CSS dos artigos anteriores.
As regex brilham em outro papel — processar um texto curto já extraído:
- tirar o valor numérico do preço de uma string com moeda e espaços;
- normalizar um telefone ou um email;
- extrair a referência, o SKU, uma data, o valor do desconto;
- destrinchar parâmetros de uma URL ou do texto de um
<script>.
A regra é simples: a estrutura se pega com seletores; o valor dentro do nó, com uma regex.
Sintaxe básica
A maioria dos caracteres de um padrão representa a si mesma: o padrão preço encontrará a substring «preço». O poder vem com os caracteres especiais (metacaracteres).
| Símbolo | Significado |
|---|---|
. |
qualquer caractere (exceto a quebra de linha) |
\d |
dígito 0–9 |
\D |
não dígito |
\w |
letra, dígito ou _ |
\W |
o oposto de \w |
\s |
caractere de espaço (espaço, tabulação, quebra) |
\S |
caractere que não é espaço |
\b |
fronteira de palavra |
Para usar um metacaractere como caractere comum (por exemplo, o ponto de um número), escape-o com barra invertida: \., \$, \(.
Classes de caracteres
Os colchetes definem um conjunto de caracteres admissíveis em uma posição:
[aeiou] uma das vogais listadas
[0-9] qualquer dígito (o mesmo que \d)
[a-zA-Z] qualquer letra latina básica
[a-zA-ZáàâãéêíóôõúçÁÀÂÃÉÊÍÓÔÕÚÇ] qualquer letra portuguesa, com acentos e cedilha
[^0-9] qualquer caractere EXCETO dígito (^ dentro de colchetes = negação)
[\d.,] um dígito, um ponto ou uma vírgulaOs intervalos (a-z, 0-9) e as enumerações podem ser combinados. ^ no início da classe inverte o conjunto.
Quantificadores: quantas repetições
O quantificador indica quantas vezes o elemento anterior se repete.
| Quantificador | Quantas vezes |
|---|---|
* |
0 ou mais |
+ |
1 ou mais |
? |
0 ou 1 (opcional) |
{3} |
exatamente 3 |
{2,5} |
de 2 a 5 |
{2,} |
2 ou mais |
\d+ um ou mais dígitos: «12990»
\d{1,3} de um a três dígitos (um grupo de milhar)
colou?r «color» e «colour»Quantificadores gulosos e preguiçosos
Por padrão, os quantificadores são gulosos — capturam o máximo possível. Um ? a mais os torna preguiçosos — capturam o mínimo:
".*" guloso: da primeira aspa até a ÚLTIMA da string
".*?" preguiçoso: da primeira aspa até a MAIS PRÓXIMAÉ uma das armadilhas mais frequentes: o padrão guloso «engole» texto demais. Na prática, para extrair valores curtos, quase sempre convém a variante preguiçosa ou uma classe de caracteres mais estreita no lugar de ..
Âncoras e fronteiras
As âncoras não casam com caracteres — elas fixam o padrão a uma posição:
^começo ^ — início da string
fim$ $ — final da string
^\d+$ a string inteira é composta de dígitos
\bSKU\b «SKU» como palavra independente, não como parte de outraAs âncoras protegem contra falsos positivos: ^\d+$ garante que a célula contém apenas um número, e não «12 un.».
Grupos
Os parênteses ( ) agrupam uma parte do padrão e capturam o trecho correspondente para recuperá-lo depois.
(\d+)[.,](\d+) a parte inteira e a parte decimal do número em separadoOs grupos são numerados da esquerda para a direita: o grupo 1 é (\d+) antes do separador; o grupo 2, o que vem depois.
Grupos sem captura
Se os parênteses servem apenas para agrupar (por exemplo, sob um quantificador), mas o resultado não interessa, usa-se (?: ):
(?:https?://)?(\S+) «http://» ou «https://» opcional, sem armazená-loGrupos nomeados
Para não ficar contando números, o grupo recebe um nome (?P<name>...) (em Python) ou (?<name>...):
(?P<eur>\d+)[.,](?P<cent>\d{2})Depois, o acesso é feito com match.group("eur") — legível e resistente à reordenação dos grupos.
Referências retroativas
Dentro do padrão é possível referenciar um grupo já capturado com \1, \2:
<(\w+)>.*?</\1> tag pareada: a de abertura e a de fechamento têm o mesmo nome
(["']).*?\1 string entre aspas simples ou duplas\1 exige que na segunda posição apareça o mesmo caractere que casou no primeiro grupo.
Verificações à frente e atrás
As construções lookaround verificam o contexto sem incluí-lo no resultado — muito úteis para «se prender» a um rótulo e devolver apenas o valor.
| Construção | Significado |
|---|---|
(?=...) |
à frente há... (positive lookahead) |
(?!...) |
à frente NÃO há... (negative lookahead) |
(?<=...) |
atrás há... (positive lookbehind) |
(?<!...) |
atrás NÃO há... (negative lookbehind) |
\d+(?=\s*€) número SEGUIDO do símbolo do euro — retorna só o número
(?<=Preço:\s)\d+ número PRECEDIDO de «Preço: » — retorna só o número
\d+(?!\d) o último dígito do númeroO lookbehind é especialmente prático quando é preciso extrair o valor que vem depois de um rótulo fixo sem arrastar o próprio rótulo para o resultado.
Flags (modificadores)
As flags mudam o comportamento do padrão inteiro:
| Flag (Python) | Efeito |
|---|---|
re.I / (?i) |
sem diferenciar maiúsculas e minúsculas |
re.S / (?s) |
. casa também com a quebra de linha |
re.M / (?m) |
^ e $ atuam em cada linha |
re.X / (?x) |
modo «verboso» — permite comentar o padrão |
re.findall(r"preço", text, re.I) # «Preço», «PREÇO», «preço»Exemplos práticos para o scraping
Vamos reunir os padrões típicos em Python (módulo re). Funções úteis: re.search (primeira ocorrência), re.findall (todas, em lista), re.sub (substituição), re.finditer (iterador com grupos).
O preço a partir de uma string «suja»:
import re
text = "Preço: 12 990,50 € (antes 15 990 €)"
# Extraímos o primeiro número ignorando os espaços que separam os milhares
m = re.search(r"(\d[\d\s]*\d|\d)(?:[.,](\d{2}))?", text)
eur = re.sub(r"\s", "", m.group(1)) # «12990»
cent = m.group(2) or "00" # «50»
price = float(f"{eur}.{cent}") # 12990.5Todos os preços do texto (o novo e o antigo):
prices = re.findall(r"\d[\d\s]*\d(?=\s*€)", text)
# ['12 990', '15 990'] → depois limpamos os espaços
clean = [int(re.sub(r"\D", "", p)) for p in prices] # [12990, 15990]Referência / SKU:
sku = re.search(r"\bReferência[:\s]+([A-Z0-9\-]+)", text)Telefone (normalização para dígitos):
digits = re.sub(r"\D", "", "+55 11 91234-5678") # «5511912345678»Email:
emails = re.findall(r"[\w.+-]+@[\w-]+\.[\w.-]+", text)Extrair um valor JSON de um script inline:
# Na página de produto, o preço costuma estar em um <script> como window.__DATA__ = {...}
m = re.search(r'"price"\s*:\s*"?(\d+(?:\.\d+)?)"?', script_text)As regex em conjunto com o DOM e o CSS
Onde a regex mais rende não é no lugar das ferramentas dos artigos anteriores, e sim ao lado delas:
from bs4 import BeautifulSoup
import re
soup = BeautifulSoup(html, "html.parser")
# 1) O seletor CSS obtém o nó necessário
raw = soup.select_one("span.price").get_text(strip=True)
# 2) A regex limpa o texto até sobrar o número
price = int(re.sub(r"\D", "", raw))O seletor responde ao «onde»; a regex, ao «o que exatamente desse texto». Essa separação torna o scraper preciso e legível ao mesmo tempo.
Aplicação no monitoramento de preços
No monitoramento de preços de lojas online, as expressões regulares cobrem a «última milha» da extração de dados:
- Normalização do preço para um formato numérico único: remover os espaços separadores e a moeda e trocar a vírgula por ponto — caso contrário, é impossível comparar os valores de plataformas diferentes.
- Decomposição do desconto em strings como «−23 %» ou «economia de 3000 €».
- Limpeza da disponibilidade: de «restam 4 un.» extrair a quantidade
\d+. - Identificadores de produto — SKU, EAN/código de barras (
\b\d{13}\b), referência — para o pareamento do mesmo produto entre vendedores diferentes. - Dados a partir dos scripts: muitas lojas guardam o preço em um JSON dentro de
<script type="application/ld+json">ou em variáveis inline — a regex extrai o campo necessário sem um parsing completo do JS.
A combinação «seletor → regex» é a base operacional do motor de scraping de sites: ele percorre as fichas de produto conforme um calendário, extrai os nós via CSS e converte o conteúdo deles em números limpos com expressões regulares.
Desempenho e armadilhas
- Compile os padrões de uso frequente —
re.compile(...)uma única vez, em vez de reanalisar o padrão em um laço sobre milhares de produtos. - Evite o backtracking catastrófico. Quantificadores ambíguos aninhados como
(\d+)+ou(.*)*podem «travar» com uma string escolhida de propósito (ou por acaso). Mantenha as classes de caracteres estreitas e prefira os quantificadores preguiçosos aos gulosos quando fizer sentido. - Não complique além da conta. Se o padrão ficou ilegível, divida a tarefa em duas regex simples ou volte aos seletores: talvez o valor buscado esteja em um atributo
data-separado, mais fácil de pegar diretamente (veja o artigo sobre seletores CSS). - Teste com exemplos reais. Preços são escritos de mil maneiras:
1 990,1.990,1990,00,a partir de 1990. Rode o padrão contra um conjunto de strings reais de lojas diferentes.
Conclusão
As expressões regulares são uma ferramenta para extrair valores do texto, não para desmontar estruturas. Os metacaracteres e as classes descrevem quais caracteres são esperados; os quantificadores, quantos; os grupos e o lookaround, como isolar o trecho buscado no seu contexto. Em dupla com o parsing do DOM e os seletores CSS, elas formam a cadeia completa do scraping de sites: encontrar o nó, extrair o texto, transformá-lo em dados limpos. É exatamente essa combinação que sustenta um monitoramento de preços de lojas online confiável, em que é preciso obter com regularidade números comparáveis a partir dos layouts díspares dos concorrentes.
Com isso, fecha-se a série básica sobre ferramentas: o DOM fornece a árvore; os seletores CSS, o endereçamento; as expressões regulares, a limpeza final dos dados.