Regional Serie parada Principado de Asturias

Asturias — Subvenciones y ayudas del Principado

CSVs directos del Principado de Asturias con subvenciones concedidas (histórico 2016-2023 y fichero de 2024) y convocatorias. Formato poco habitual: separador «§», Latin-1, NIF pegado al nombre y fechas en dos formatos. Ojo: muchos importes de 2023 perdieron la coma decimal y salen multiplicados por 10 o por 100.

Serie parada. Sin datos nuevos desde diciembre de 2024 (los ficheros no se tocan desde abril de 2025). Los datos publicados siguen siendo válidos para análisis históricos, pero no esperes registros nuevos.

Ficha técnica

Formato
CSV (separador «§», Latin-1)
Registros
~354.500 concesiones
Cobertura
Concesiones de 2016 a 2024
Actualización
Sin cambios desde abril de 2025 (último dato: diciembre de 2024)
Licencia
CC BY 4.0
Entidad
Principado de Asturias

Descripción

El Principado de Asturias publica las subvenciones y ayudas concedidas por su administración como CSVs directos en descargas.asturias.es: un histórico de concesiones de 2016 a 2023, un fichero «de 2024 en adelante» y un fichero de convocatorias. Los enlaces son estables y no requieren autenticación. Se federa en datos.gob.es con el identificador a03002951.

Pese al nombre, en octubre de 2026 el fichero «2024-» solo llegaba al 31 de diciembre de 2024 y no se modificaba desde abril de 2025. No hemos encontrado un conjunto que lo continúe ni en descargas.asturias.es ni en datos.gob.es, así que para 2025 y 2026 hay que ir a la BDNS y filtrar por el Principado. Entre los dos ficheros suman unas 354.500 concesiones.

El formato da guerra y conviene saberlo antes de abrirlo:

- El separador es «§» y la codificación Latin-1 (ISO-8859-1). En pandas hace falta engine='python', porque el motor C no admite ese separador. - El NIF va pegado al nombre en la columna BENEFICIARIO («P3302100G AYUNTAMIENTO DE CUDILLERO»); en personas físicas aparece enmascarado con asteriscos. - Las fechas vienen en dos formatos, AAAA/MM/DD y DD/MM/AAAA, y se mezclan incluso dentro del histórico (el bloque de 2023 usa el segundo). En el fichero de 2024 la columna se llama FECHA-CONCESION en lugar de FECHA. - Los importes llevan punto de miles y coma decimal («70.801,00»). - El histórico arrastra columnas vacías al final de cada fila.

El problema más serio está en los importes de 2023. Ese año suma unos 24.300 millones de euros, frente a 300-600 millones en el resto, y no es que estén en céntimos: muchos importes perdieron la coma decimal al generar el fichero y se les añadió «,00». Así, 3.274,25 euros aparece como «327.425,00» (cien veces más) y 4.655,40 euros, como «46.554,00» (diez veces más, seguramente porque el cero final ya se había perdido antes). Los importes sin céntimos no cambian: 6.000 euros siguen siendo «6.000,00».

Lo comprobamos en octubre de 2026 cruzando 150 concesiones de 2023 con la BDNS por NIF y fecha. Las que tenían céntimos distintos de cero coincidían (27 de 28; la otra no apareció en la BDNS con esa fecha). De las 122 que acababan en «,00», 76 coincidían tal cual, 34 estaban multiplicadas por 100, 8 por 10 y 4 no las encontramos. Los años 2016-2022 y el fichero de 2024 están bien. Afecta a casi todas las filas de enero a noviembre de 2023 (el 99,5 % acaba en «,00») y a parte de diciembre, en todos los departamentos. Las versiones XLSX y JSON del histórico tienen el mismo error y el Principado no ha publicado una corrección.

En la práctica, de las 51.882 concesiones de 2023 solo son seguras las 6.786 con céntimos. En las otras 45.096 el fichero no permite saber si el importe está bien o multiplicado, así que hay que contrastarlas con la BDNS. Por ejemplo, las 43 concesiones de 2023 al Ayuntamiento de Gijón suman 1.634,7 millones en el CSV y 29,98 millones según la BDNS.

Estructura de datos

  • DEPARTAMENTO — Consejería u organismo concedente
  • CONVOCATORIA — Título de la convocatoria
  • APLICACION PRESUPUESTARIA — Solo en el histórico 2016-2023
  • BENEFICIARIO — NIF y nombre en la misma columna
  • INSTRUMENTO — Tipo de ayuda
  • FECHA / FECHA-CONCESION — Fecha de concesión (AAAA/MM/DD o DD/MM/AAAA)
  • IMPORTE — Importe con punto de miles y coma decimal
  • TRIMESTRE — Trimestre de publicación (AAAA/T)

Ejemplos de código

Descargar CSVs directos curl
# Concesiones históricas 2016-2023 (~120 MB)
curl -sL -o asturias_subv_2016_2023.csv \
  "https://descargas.asturias.es/asturias/opendata/SectorPublico/subvenciones/concesiones-subvs-2016-2023.csv"

# Concesiones de 2024
curl -sL -o asturias_subv_2024.csv \
  "https://descargas.asturias.es/asturias/opendata/SectorPublico/subvenciones/concesiones-subvs-2024-.csv"

# Convocatorias
curl -sL -o asturias_convocatorias.csv \
  "https://descargas.asturias.es/asturias/opendata/SectorPublico/subvenciones/convocatorias-subvs.csv"

# Ver las primeras líneas en UTF-8
head -3 asturias_subv_2024.csv | iconv -f latin1 -t utf-8
Cargar y unir histórico + 2024 con pandas (marcando los importes dudosos de 2023) python
import pandas as pd

BASE = 'https://descargas.asturias.es/asturias/opendata/SectorPublico/subvenciones'

# Separador «§» y codificación Latin-1; el motor C de pandas no admite «§»
opts = dict(sep='§', encoding='latin-1', engine='python', dtype=str)
hist = pd.read_csv(f'{BASE}/concesiones-subvs-2016-2023.csv', **opts)
nuevo = pd.read_csv(f'{BASE}/concesiones-subvs-2024-.csv', **opts)

# El histórico trae columnas vacías al final; el fichero nuevo llama FECHA-CONCESION a la fecha
hist = hist.loc[:, ~hist.columns.str.startswith('Unnamed')]
nuevo = nuevo.rename(columns={'FECHA-CONCESION': 'FECHA'})
df = pd.concat([hist, nuevo], ignore_index=True)

# Fechas en dos formatos (AAAA/MM/DD y DD/MM/AAAA), a veces en el mismo fichero
iso = pd.to_datetime(df['FECHA'], format='%Y/%m/%d', errors='coerce')
df['FECHA'] = iso.fillna(pd.to_datetime(df['FECHA'], format='%d/%m/%Y', errors='coerce'))

# En 2023 muchos importes perdieron la coma decimal: «3274,25» se publicó como «327.425,00».
# Solo son fiables los de 2023 con céntimos distintos de cero; el resto puede estar
# multiplicado por 1, 10 o 100 y no hay forma de saberlo sin consultar la BDNS.
df['IMPORTE_DUDOSO'] = (df['FECHA'].dt.year == 2023) & df['IMPORTE'].str.endswith(',00', na=False)

# Importe con punto de miles y coma decimal: «70.801,00»
df['IMPORTE'] = pd.to_numeric(df['IMPORTE'].str.replace('.', '', regex=False)
                              .str.replace(',', '.', regex=False))

# El NIF va pegado al nombre en BENEFICIARIO: «P3302100G AYUNTAMIENTO DE CUDILLERO»
df[['NIF', 'NOMBRE']] = df['BENEFICIARIO'].str.extract(r'^([A-Z0-9]{9})\s+(.*)$')

print(f'Registros totales: {len(df):,}')
print(df['FECHA'].min(), '->', df['FECHA'].max())

# Totales por año sin los importes dudosos de 2023
fiables = df[~df['IMPORTE_DUDOSO']]
print(fiables.groupby(fiables['FECHA'].dt.year)['IMPORTE'].agg(['count', 'sum']))
print(f"Concesiones de 2023 con importe dudoso: {df['IMPORTE_DUDOSO'].sum():,}")
Corregir los importes de 2023 de un beneficiario contra la BDNS python
import pandas as pd
import requests

URL = ('https://descargas.asturias.es/asturias/opendata/SectorPublico/'
       'subvenciones/concesiones-subvs-2016-2023.csv')
BDNS = 'https://www.infosubvenciones.es/bdnstrans/api/concesiones/busqueda'
NIF = 'P3302400A'  # Ayuntamiento de Gijón

df = pd.read_csv(URL, sep='§', encoding='latin-1', engine='python', dtype=str)
df['FECHA'] = pd.to_datetime(df['FECHA'], format='%d/%m/%Y', errors='coerce')  # 2023 usa DD/MM/AAAA
df['IMPORTE_CSV'] = pd.to_numeric(df['IMPORTE'].str.replace('.', '', regex=False)
                                  .str.replace(',', '.', regex=False))
gijon = df[(df['FECHA'].dt.year == 2023) & df['BENEFICIARIO'].str.startswith(NIF, na=False)].copy()

def importes_bdns(nif, fecha):
    """Importes que la BDNS registra para ese NIF y ese día, solo del Principado."""
    dia = fecha.strftime('%d/%m/%Y')
    resp = requests.get(BDNS, params={'vpd': 'GE', 'nifCif': nif, 'fechaDesde': dia,
                                      'fechaHasta': dia, 'pageSize': 200}, timeout=60)
    return [c['importe'] for c in resp.json()['content']
            if c.get('nivel2') == 'PRINCIPADO DE ASTURIAS']

def corregir(fila):
    """Prueba el importe del CSV tal cual, entre 100 y entre 10; si nada encaja, lo deja vacío."""
    candidatos = importes_bdns(NIF, fila['FECHA'])
    for factor in (1, 100, 10):
        valor = round(fila['IMPORTE_CSV'] / factor, 2)
        if any(abs(valor - c) < 0.01 for c in candidatos):
            return pd.Series({'IMPORTE': valor, 'FACTOR': factor})
    return pd.Series({'IMPORTE': None, 'FACTOR': None})

gijon[['IMPORTE', 'FACTOR']] = gijon.apply(corregir, axis=1)
print(gijon['FACTOR'].value_counts(dropna=False))
print(f"Suma en el CSV: {gijon['IMPORTE_CSV'].sum():,.2f} EUR")
print(f"Suma corregida: {gijon['IMPORTE'].sum():,.2f} EUR")