Extrair um catálogo completo de produtos a partir de um site público é uma necessidade comum em projetos de migração de plataforma, inteligência de mercado ou treinamento de modelos analíticos. No entanto, o que parece ser uma tarefa simples de extração pontual pode rapidamente se tornar complexo: estruturas de páginas com renderização dinâmica, dezenas de milhares de imagens em alta resolução e especificações técnicas aninhadas em tabelas irregulares costumam interromper scripts ingênuos.
Neste artigo, você entenderá como arquitetar um pipeline de extração de dados eficiente em Python, separando a coleta de metadados do download de arquivos de mídia e garantindo integridade estrutural do início ao fim.
1. Desacoplando Metadados e Mídia
O erro mais frequente em raspagens pontuais é tentar baixar imagens pesadas no mesmo fluxo síncrono em que se navega pelas páginas de produto. Isso eleva o tempo de execução e aumenta a chance de falhas por timeout.
A abordagem correta envolve duas fases bem delimitadas:
- Fase de Coleta Estrutural: Navegação pelas listagens e páginas de detalhe para coletar URLs canônicas, títulos, preços, SKUs, tabelas técnicas e URLs diretas das imagens, salvando esses registros em formato intermediário (JSONL ou banco SQLite).
- Fase de Ingestão de Ativos: Leitura da lista de URLs de imagens e download concorrente em lotes controlados.
2. Mapeamento de Dados e JSON-LD
Antes de escrever seletores CSS complexos para cada campo visual da página, verifique o código-fonte em busca de scripts do tipo application/ld+json. A maioria dos e-commerces modernos injeta dados estruturados de schema de produto diretamente no HTML para fins de SEO.
Exemplo prático de extração combinada em Python usando BeautifulSoup:
python
import json
from bs4 import BeautifulSoup
def extrairdadosproduto(htmlcontent: str) -> dict:
soup = BeautifulSoup(htmlcontent, ‘html.parser’)
dados = {}
# Tentativa de extração via JSON-LD (Schema.org)
schema_tag = soup.find('script', type='application/ld+json')
if schema_tag:
try:
schema_data = json.loads(schema_tag.string)
if schema_data.get('@type') == 'Product':
dados['titulo'] = schema_data.get('name')
dados['descricao'] = schema_data.get('description')
dados['sku'] = schema_data.get('sku')
dados['imagens'] = schema_data.get('image', [])
except (json.JSONDecodeError, TypeError):
pass
# Fallback para seletores CSS se campos críticos estiverem ausentes
if not dados.get('titulo'):
h1 = soup.find('h1', class_='product-title')
dados['titulo'] = h1.get_text(strip=True) if h1 else None
# Coleta de especificações técnicas em tabela
especificacoes = {}
for linha in soup.select('table.specs-table tr'):
colunas = linha.find_all(['th', 'td'])
if len(colunas) == 2:
chave = colunas[0].get_text(strip=True)
valor = colunas[1].get_text(strip=True)
especificacoes[chave] = valor
dados['especificacoes'] = especificacoes
return dados
3. Download Concorrente de Imagens com aiohttp
Quando lidamos com milhares de produtos, baixar imagens sequencialmente inviabiliza a operação. O uso de asyncio e aiohttp com um limitador de semáforo permite transferências rápidas sem saturar a banda local ou disparar bloqueios no servidor de origem.
python
import asyncio
import aiohttp
from pathlib import Path
async def baixarimagem(session: aiohttp.ClientSession, url: str, destino: Path, semaforo: asyncio.Semaphore):
async with semaforo:
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=15)) as resposta:
if resposta.status == 200:
conteudo = await resposta.read()
destino.writebytes(conteudo)
except Exception as erro:
print(f”Falha ao baixar {url}: {erro}”)
async def pipelinedownload(urlsimagens: list[tuple[str, Path]], maxconexoes: int = 10):
semaforo = asyncio.Semaphore(maxconexoes)
async with aiohttp.ClientSession() as session:
tarefas = [
baixarimagem(session, url, caminho, semaforo)
for url, caminho in urlsimagens
]
await asyncio.gather(*tarefas)
4. Normalização com Técnicas de IA
Como especialista em IA e processamento de dados, observo que um dos maiores gargalos pós-extração é a inconsistência textual de tabelas técnicas (por exemplo, variações como ‘Voltagem: 110V’, ‘Tensão: 127V’, ‘Alimentação: 110 Volts’). Em vez de criar centenas de expressões regulares manuais, pipelines avançados utilizam modelos de linguagem compactos em modo batch ou técnicas de similaridade por embeddings para agrupar e padronizar chaves de atributos automaticamente em um esquema unificado.
5. Resiliência Operacional
Mesmo para uma extração única, implemente:
- Mecanismo de Retentativa: Aplique retentativas com backoff exponencial via biblioteca
tenacity. - Checkpoints: Salve o progresso a cada página processada para permitir retomada imediata em caso de falha de conexão.
- Headers Reais: Envie cabeçalhos de requisição realistas (User-Agent atualizado, Accept-Language e Referer) para evitar rejeições básicas por proxies.
Se sua empresa necessita de uma extração completa e precisa de dados de catálogos complexos, com tratamento de especificações e entrega estruturada pronta para consumo, conheça as soluções em automação e engenharia de dados oferecidas pela consultoria do Thiago Programador.


