Datos abiertos con Socrata: accede a los datos públicos de España y Cataluña con Python
Hay toneladas de datos públicos disponibles de forma gratuita. Datos de presupuestos, padrones municipales, estadísticas de emergencias, contratos públicos… todo ahí, publicado por administraciones de España y Cataluña. El problema es que la mayoría de la gente no sabe que existe o no sabe cómo acceder a ellos de forma programática.
Si alguna vez has entrado a un portal de datos abiertos, descargado un CSV enorme y luego intentado hacer algo útil con él, ya sabes el dolor que eso supone. Hay una forma mejor.
Socrata es la plataforma que usa el portal de datos abiertos de la Generalitat de Catalunya, y tiene una API REST muy bien documentada con su propio lenguaje de consulta. En este artículo te enseño cómo sacarle partido con Python desde cero.
Qué es Socrata y por qué importa
Socrata es una plataforma SaaS para publicar y gestionar datos abiertos. La usan cientos de administraciones públicas en todo el mundo: ciudades de Estados Unidos, el gobierno federal americano, y en nuestro caso, la Generalitat de Catalunya con su portal analisi.transparenciacatalunya.cat.
Lo que lo hace interesante para nosotros como desarrolladores es su API REST estándar, conocida como SODA (Socrata Open Data API), que viene acompañada de SoQL (Socrata Query Language), un lenguaje parecido a SQL pero pensado para peticiones HTTP.
El portal de España
datos.gob.esy el de Barcelonaopendata-ajuntament.barcelona.catusan CKAN, no Socrata. Si quieres datos de esos portales, el enfoque es diferente. En este artículo nos centramos en el portal de Cataluña, que sí usa Socrata.
Los portales de datos abiertos que debes conocer
Antes de ponernos con el código, una visión general de los recursos disponibles:
| Portal | URL | Tecnología | Datasets |
|---|---|---|---|
| Cataluña (Transparència) | analisi.transparenciacatalunya.cat | Socrata | +500 |
| España | datos.gob.es | CKAN | +19.000 |
| Barcelona | opendata-ajuntament.barcelona.cat | CKAN | +555 |
El portal de Cataluña es el más interesante para usar con la API de Socrata porque da acceso directo a datasets de la Generalitat: servicios de emergencias, salud, territorio, economía, y mucho más.
Cómo funciona la API de Socrata
Cada dataset en Socrata tiene un identificador único de ocho caracteres separados por un guión (por ejemplo: kxrz-cgci). Lo encuentras al final de la URL del dataset en el portal.
El endpoint base para consultar cualquier dataset sigue este patrón:
https://{dominio}/resource/{dataset-id}.json
Por ejemplo, para el dataset de entidades del sector público de Cataluña:
https://analisi.transparenciacatalunya.cat/resource/kxrz-cgci.json
Y eso es todo. Una petición GET a esa URL ya te devuelve datos en JSON. Sin autenticación obligatoria para empezar.
Formatos de respuesta
Socrata soporta varios formatos de salida, simplemente cambiando la extensión:
# JSON (el más habitual)
/resource/{id}.json
# CSV
/resource/{id}.csv
# XML
/resource/{id}.xml
Para el trabajo con Python y pandas, JSON es lo más cómodo.
SoQL: consultas SQL para la web
SoQL (Socrata Query Language) te permite filtrar, ordenar y paginar los datos directamente en la URL mediante parámetros GET. Si sabes SQL, lo pillas en cinco minutos.
Los parámetros principales:
| Parámetro | Qué hace | Ejemplo |
|---|---|---|
$select | Columnas a devolver | $select=nom,poblacio |
$where | Filtro de filas | $where=poblacio > 10000 |
$order | Ordenación | $order=poblacio DESC |
$limit | Número máximo de filas | $limit=500 |
$offset | Desplazamiento para paginar | $offset=1000 |
$group | Agrupar resultados | $group=provincia |
$q | Búsqueda de texto completo | $q=barcelona |
Un ejemplo real en URL:
https://analisi.transparenciacatalunya.cat/resource/kxrz-cgci.json
?$select=nom,tipus
&$where=tipus='Empresa pública'
&$order=nom ASC
&$limit=50
Sin $limit explícito, Socrata devuelve como máximo 1.000 filas por defecto. Si el dataset tiene más, necesitas paginar.
Ejemplo práctico con Python
Vamos al código. Lo más directo es usar requests y pandas, sin librerías específicas de Socrata.
Instalación
pip install requests pandas
Consulta básica
import requests
import pandas as pd
BASE_URL = "https://analisi.transparenciacatalunya.cat/resource"
DATASET_ID = "kxrz-cgci" # Entitats del sector públic de Catalunya
url = f"{BASE_URL}/{DATASET_ID}.json"
params = {
"$limit": 100,
"$order": "nom ASC"
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
df = pd.DataFrame(response.json())
print(df.head())
print(f"\nTotal registros: {len(df)}")
Así de simple. La API devuelve una lista de objetos JSON que pandas convierte directamente en un DataFrame.
Consulta con filtros
Supón que quieres solo las empresas públicas:
params = {
"$select": "nom,tipus,municipi",
"$where": "tipus='Empresa pública'",
"$order": "nom ASC",
"$limit": 200
}
response = requests.get(url, params=params, timeout=10)
df = pd.DataFrame(response.json())
print(df)
O municipios con más de 50.000 habitantes, usando otro dataset:
# Dataset: Cens de població i habitatges
DATASET_ID = "ftq3-r7yx"
url = f"{BASE_URL}/{DATASET_ID}.json"
params = {
"$select": "nom_municipi,total_habitants",
"$where": "total_habitants > 50000",
"$order": "total_habitants DESC",
"$limit": 50
}
response = requests.get(url, params=params, timeout=10)
df = pd.DataFrame(response.json())
print(df.to_string(index=False))
Paginación para datasets grandes
El límite por defecto es 1.000 registros. Para datasets grandes, necesitas iterar con $limit y $offset:
def fetch_all(dataset_id: str, **extra_params) -> pd.DataFrame:
url = f"{BASE_URL}/{dataset_id}.json"
batch_size = 1000
offset = 0
all_records = []
while True:
params = {
"$limit": batch_size,
"$offset": offset,
**extra_params
}
response = requests.get(url, params=params, timeout=30)
response.raise_for_status()
batch = response.json()
if not batch:
break
all_records.extend(batch)
offset += batch_size
print(f"Descargados {len(all_records)} registros...")
return pd.DataFrame(all_records)
# Ejemplo: descargar el dataset completo de entidades públicas
df = fetch_all("kxrz-cgci", **{"$order": "nom ASC"})
print(f"Total: {len(df)} registros")
Datasets reales del portal de Cataluña
Algunos datasets interesantes que puedes explorar ahora mismo:
Emergencias CAT112
Estadísticas de llamadas al 112 de los servicios de emergencias de Cataluña.
# Llamadas por tipo de emergencia
DATASET_ID = "hn4c-sqxf" # CAT112 - Dades operatives
url = f"{BASE_URL}/{DATASET_ID}.json"
params = {
"$select": "any,mes,tipus_emergencia,total_activacions",
"$where": "any='2023'",
"$order": "total_activacions DESC",
"$limit": 20
}
response = requests.get(url, params=params, timeout=10)
df = pd.DataFrame(response.json())
print(df)
Cómo encontrar el ID de un dataset
- Ve a analisi.transparenciacatalunya.cat
- Busca el dataset que te interesa
- Ábrelo y mira la URL: termina con el identificador de 8 caracteres
- También está en “API” > “API Endpoint” dentro de cada dataset
# Puedes verificar un dataset directamente desde curl
curl "https://analisi.transparenciacatalunya.cat/resource/kxrz-cgci.json?$limit=1"
App tokens: cómo evitar el throttling
Sin autenticación, Socrata aplica límites de peticiones bastante restrictivos. Con un app token gratuito subes a 1.000 peticiones por hora rodante, que es suficiente para la mayoría de proyectos.
Cómo obtenerlo:
- Regístrate en dev.socrata.com
- Crea una aplicación y copia el token
- Pásalo en la cabecera
X-App-Tokende cada petición
import requests
import pandas as pd
APP_TOKEN = "tu_app_token_aqui"
def get_data(dataset_id: str, params: dict) -> pd.DataFrame:
url = f"https://analisi.transparenciacatalunya.cat/resource/{dataset_id}.json"
headers = {"X-App-Token": APP_TOKEN}
response = requests.get(url, params=params, headers=headers, timeout=10)
response.raise_for_status()
return pd.DataFrame(response.json())
df = get_data("kxrz-cgci", {"$limit": 500, "$order": "nom ASC"})
print(df.head())
Para scripts de análisis puntuales no necesitas el token. Para proyectos en producción o que hacen muchas peticiones en poco tiempo, regístrate y úsalo siempre.
Un cliente reutilizable
Si vas a trabajar con varios datasets, merece la pena encapsular la lógica en una clase sencilla:
import requests
import pandas as pd
from typing import Optional
class SocrataClient:
def __init__(self, domain: str, app_token: Optional[str] = None):
self.base_url = f"https://{domain}/resource"
self.headers = {}
if app_token:
self.headers["X-App-Token"] = app_token
def query(
self,
dataset_id: str,
select: Optional[str] = None,
where: Optional[str] = None,
order: Optional[str] = None,
limit: int = 1000,
offset: int = 0,
) -> pd.DataFrame:
params = {"$limit": limit, "$offset": offset}
if select:
params["$select"] = select
if where:
params["$where"] = where
if order:
params["$order"] = order
url = f"{self.base_url}/{dataset_id}.json"
response = requests.get(url, params=params, headers=self.headers, timeout=15)
response.raise_for_status()
return pd.DataFrame(response.json())
def fetch_all(self, dataset_id: str, **kwargs) -> pd.DataFrame:
batch_size = 1000
offset = 0
frames = []
while True:
df = self.query(dataset_id, limit=batch_size, offset=offset, **kwargs)
if df.empty:
break
frames.append(df)
offset += batch_size
return pd.concat(frames, ignore_index=True) if frames else pd.DataFrame()
# Uso
client = SocrataClient(
domain="analisi.transparenciacatalunya.cat",
app_token="tu_token_opcional"
)
# ✅ Consulta simple
df = client.query(
"kxrz-cgci",
select="nom,tipus,municipi",
where="tipus='Empresa pública'",
order="nom ASC",
limit=100
)
# ✅ Descarga completa con paginación automática
df_completo = client.fetch_all("kxrz-cgci", order="nom ASC")
print(f"Total entidades: {len(df_completo)}")
Errores comunes y cómo evitarlos
❌ Olvidar que los valores string van entre comillas simples en SoQL:
# ❌ Esto falla
params = {"$where": "tipus=Empresa pública"}
# ✅ Correcto
params = {"$where": "tipus='Empresa pública'"}
❌ Asumir que la primera petición trae todos los datos:
# ❌ Solo trae 1.000 filas (el límite por defecto)
response = requests.get(url)
# ✅ Especifica el límite que necesitas o usa paginación
params = {"$limit": 5000}
❌ No manejar errores de red ni timeouts:
# ❌ Sin timeout, puede colgarse indefinidamente
response = requests.get(url, params=params)
# ✅ Con timeout y manejo de errores
try:
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
except requests.exceptions.Timeout:
print("La petición tardó demasiado")
except requests.exceptions.HTTPError as e:
print(f"Error HTTP: {e.response.status_code}")
Conclusión
La API de Socrata es una de las más accesibles para empezar a trabajar con datos públicos. No necesitas registrarte para hacer las primeras pruebas, la documentación es buena, y SoQL te permite filtrar y paginar sin tener que descargar archivos enormes.
El portal de Cataluña tiene datos realmente interesantes: emergencias, salud, territorio, economía pública… Si trabajas con datos de la administración o quieres hacer periodismo de datos o análisis propios, esto es un punto de partida sólido.
Mi recomendación: empieza explorando el portal en el navegador, encuentra un dataset que te interese, y luego construye el cliente Python para automatizar la descarga. En menos de una hora tienes datos limpios en un DataFrame listos para analizar.
Preguntas frecuentes
¿Es gratuita la API de Socrata? Sí, completamente gratuita. El app token también es gratuito y solo sirve para subir el límite de peticiones por hora.
¿Necesito autenticación para acceder a los datos? No para lectura. Los datos son abiertos y públicos. El app token es opcional pero recomendable para proyectos con muchas peticiones.
¿Puedo usar estos datos en proyectos comerciales? Depende de la licencia de cada dataset. Revisa la ficha de cada dataset en el portal. La mayoría usan licencias abiertas (Creative Commons), pero compruébalo siempre.
¿Cómo sé cuántos registros tiene un dataset?
Puedes usar el endpoint de metadatos: /api/views/{dataset-id}.json y mirar el campo rowsUpdatedAt y las estadísticas del dataset. También puedes hacer una consulta con $select=count(*) para contar registros.
¿Funciona igual para otros portales Socrata fuera de Cataluña? Sí, la API SODA es estándar. Cambia el dominio y el dataset ID y el código funciona igual para cualquier portal Socrata, sea de otra ciudad o país.
Artículos relacionados
2 jun 2026
Circuit Breaker: el fusible que evita que tu microservicio se hunda
Patrón Circuit Breaker explicado con una simulación interactiva y un ejemplo real con Spring Boot y Resilience4j. Cuándo usarlo y cuándo no.
30 may 2026
Mocks no son Stubs: la diferencia que cambia cómo testeas
Guía práctica sobre test doubles en Spring Boot: cuándo usar mocks, stubs, fakes o spies, y por qué confundirlos genera tests frágiles e inútiles.
27 abr 2026
Tu IA necesita un plan: explora, planifica y ejecuta mejor
Flujo dirigido por especificaciones para reducir alucinaciones de la IA y mejorar la calidad técnica, desde la exploración hasta la ejecución.
Newsletter
Aprende algo útil cada semana.
Ideas sobre programación, arquitectura e IA para mejorar tu código en menos de 5 minutos de lectura.
Sin spam · Baja cuando quieras