Como transformar JSON de uma API num DataFrame pandas
As APIs de dados devolvem quase sempre JSON com estrutura aninhada, ou seja, dicionários dentro de dicionários. Esse formato é ótimo para transportar dados, mas mau para analisar: para filtrar, agrupar ou criar gráficos precisas de uma tabela plana. Transformar o JSON de uma API num DataFrame do pandas é exatamente esse passo, e a função pandas.json_normalize resolve-o em poucas linhas. A seguir vês como, com uma API pública real como exemplo.
Pré-requisitos
- Python 3.9 ou superior instalado.
- As bibliotecas
pandaserequests(instala compip install pandas requests). - Conhecimentos básicos de Python: variáveis, listas e dicionários.
- Ligação à internet para chamar a API pública de exemplo.
Passo 1: Obter os dados da API
Como exemplo usamos uma API pública e gratuita que devolve uma lista de utilizadores, cada um com campos aninhados de morada e de empresa. Fazemos o pedido com requests, verificamos se correu bem com raise_for_status() e convertemos a resposta em objetos Python com .json().
import requests
import pandas as pd
url = "https://jsonplaceholder.typicode.com/users"
resposta = requests.get(url, timeout=10)
resposta.raise_for_status() # lança um erro se o pedido falhar
dados = resposta.json()
print(type(dados), len(dados))
print(dados[0])
A variável dados é uma lista de dicionários. Repara que campos como address e company contêm, por sua vez, outros dicionários — é essa a estrutura aninhada que vamos aplanar no próximo passo.
Passo 2: Transformar o JSON num DataFrame
A função pandas.json_normalize percorre cada registo e cria uma coluna para todos os campos, incluindo os que estão aninhados. Por omissão, une os vários níveis com um ponto — por exemplo, o campo city dentro de address passa a chamar-se address.city.
df = pd.json_normalize(dados)
print(df.shape)
print(df.columns.tolist())
O resultado tem colunas como id, name, address.city, address.geo.lat e company.name. Num único passo, o JSON aninhado passou a uma tabela plana com uma linha por utilizador.
Dica: json_normalize aplana automaticamente todos os níveis de dicionários, por muito fundos que estejam. Não precisas de percorrer o JSON à mão.
Passo 3: Nomes de colunas mais limpos
O ponto nos nomes funciona, mas pode dar erro quando escreves código como df.address.city. Com o parâmetro sep escolhes outro separador, como o traço inferior, e a seguir ficas só com as colunas que interessam para a tua análise.
df = pd.json_normalize(dados, sep="_")
colunas = ["id", "name", "email", "address_city", "company_name"]
print(df[colunas].head())
Agora as colunas chamam-se address_city ou company_name, muito mais fáceis de usar no resto do trabalho.
Passo 4: Aplanar uma lista dentro do JSON
Muitas APIs não devolvem uma lista simples: devolvem um objeto com alguns metadados e a lista de registos lá dentro. Nesses casos, indica o caminho até à lista com record_path e os campos de nível superior que queres manter em cada linha com meta.
resposta_api = {
"empresa": "bConcepts",
"pais": "PT",
"clientes": [
{"id": 1, "nome": "Ana", "cidade": "Porto"},
{"id": 2, "nome": "Bruno", "cidade": "Lisboa"},
],
}
df_clientes = pd.json_normalize(
resposta_api,
record_path="clientes",
meta=["empresa", "pais"],
)
print(df_clientes)
O resultado tem uma linha por cliente e as colunas empresa e pais repetem-se em cada linha. É assim que juntas os registos detalhados à informação de contexto que veio no topo da resposta.
Verificar o resultado
Para confirmar que a conversão correu bem, verifica a forma da tabela, espreita as primeiras linhas e garante que já não sobrou nenhum dicionário por aplanar:
print(df.shape) # (linhas, colunas)
print(df.head())
# Procurar colunas que ainda contenham dicionarios:
aninhadas = [c for c in df.columns if df[c].apply(lambda v: isinstance(v, dict)).any()]
print("Colunas ainda aninhadas:", aninhadas)
Se a lista aninhadas vier vazia, todos os campos foram aplanados e o DataFrame está pronto para análise.
Conclusão
Em poucas linhas transformaste o JSON de uma API numa tabela pronta a usar: obtiveste os dados, aplanaste os campos aninhados com json_normalize e arrumaste os nomes das colunas. A partir daqui podes guardar o resultado com df.to_csv("dados.csv", index=False), carregá-lo para uma base de dados ou combiná-lo com a paginação para trazer todas as páginas de uma vez. Qual será a próxima API que vais precisar de transformar num DataFrame?