(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como fazer enriquecimento geográfico em ETL: passo a passo

João Barros 15 de September de 2026 4 min de leitura

Este tutorial mostra como fazer enriquecimento geográfico em ETL para acrescentar latitude/longitude e município a registos de clientes. Enriquecer dados geográficos torna as análises e as visualizações mais úteis (mapas, segmentação por região) e melhora relatórios de negócio.

Pré-requisitos

  • Python 3.8+ instalado
  • Bibliotecas: requests, pandas
  • Ficheiro CSV com coluna de morada (address)
  • Chave de API de um serviço de geocodificação (ex.: Nominatim ou Google Geocoding)

Passo 1: Preparar os dados de entrada

Começa por carregar o CSV e garantir que a coluna address está normalizada (trim, remover duplicados óbvios). Isto evita chamadas desnecessárias à API e custos. Vamos também criar um identificador único para cada morada.

import pandas as pd

data = pd.read_csv('clientes.csv')
# Normalizar espaços e remover linhas sem morada
data['address'] = data['address'].astype(str).str.strip()
data = data[data['address']!='']
# Criar chave para deduplicação
data['addr_key'] = data['address'].str.lower()

Passo 2: Deduplicação antes do geocodificação

Fazer geocodificação é custoso; deduplicamos as moradas para chamar a API apenas uma vez por morada distinta. Mantemos um mapeamento para reaplicar aos registos originais.

# Obter moradas únicas
unique_addrs = data[['addr_key','address']].drop_duplicates().reset_index(drop=True)

Passo 3: Implementar a chamada à API de geocodificação com tratamento de erros

Criamos uma função simples que chama a API (exemplo com Nominatim) e trata erros básicos e limites de taxa. Em produção usa retries exponenciais e cache persistente.

import requests
import time

def geocode(address, email='seu_email@example.com'):
    # Exemplo com Nominatim (OpenStreetMap) — respeita políticas de uso
    url = 'https://nominatim.openstreetmap.org/search'
    params = {'q': address, 'format': 'json', 'limit': 1, 'addressdetails': 1, 'email': email}
    try:
        resp = requests.get(url, params=params, timeout=10)
        if resp.status_code == 200:
            j = resp.json()
            if j:
                lat = j[0].get('lat')
                lon = j[0].get('lon')
                city = j[0].get('address', {}).get('city') or j[0].get('address', {}).get('town') or j[0].get('address', {}).get('village')
                return {'latitude': float(lat), 'longitude': float(lon), 'city': city}
            return None
        else:
            return None
    except requests.RequestException:
        return None

# Teste rápido (apenas uma morada)
# print(geocode('Praça do Comércio, Lisbon'))

Passo 4: Executar geocodificação em lote com cache em memória

Percorremos as moradas únicas, guardamos resultados num dicionário (cache) e aplicamos um pequeno delay para evitar rate limits. Em cenários maiores, usa um cache persistente (Redis, ficheiro) e workers paralelos com throttling.

cache = {}
results = []
for idx, row in unique_addrs.iterrows():
    key = row['addr_key']
    addr = row['address']
    if key in cache:
        results.append({'addr_key': key, **cache[key]})
        continue
    res = geocode(addr)
    if res:
        cache[key] = res
        results.append({'addr_key': key, **res})
    else:
        cache[key] = {'latitude': None, 'longitude': None, 'city': None}
        results.append({'addr_key': key, 'latitude': None, 'longitude': None, 'city': None})
    time.sleep(1)  # Respeitar limites do serviço

geo_df = pd.DataFrame(results)

Passo 5: Reunir os dados geocodificados com o dataset original

Fazemos um join entre os resultados de geocodificação e o dataset original pelo campo addr_key. Assim cada cliente recebe latitude, longitude e cidade.

final = data.merge(geo_df, on='addr_key', how='left')
# Remover colunas temporárias se necessário
final = final.drop(columns=['addr_key'])
final.to_csv('clientes_enriquecidos.csv', index=False)

Verificar o resultado

Abre o ficheiro clientes_enriquecidos.csv e confirma que cada registo tem latitude e longitude válidas ou valores nulos controlados. Faz amostras: verifica 10 moradas com e sem coordenadas. Para validar geograficamente, carrega numa ferramenta de visualização (ex.: Power BI ou QGIS) e confirma que os pontos caem nos locais esperados.

Conclusão

Acabaste de implementar um fluxo de enriquecimento geográfico simples em ETL: normalização, deduplicação, geocodificação com tratamento básico de erros e junção dos resultados. Próximos passos: adicionar cache persistente, retries exponenciais, paralelismo controlado e validação de precisão (verificações de distância). Dica: começa por testar com um subconjunto antes de processar todo o dataset para evitar custos e bloqueios da API.