Jaime Gómez-Obregón Profile picture
Ingeniero hackeando para mejorar la Administración pública. Ayúdame a seguir 👉 https://t.co/QkIuB8saBA

Mar 29, 2022, 39 tweets

A continuación voy a explicar cómo descargar la Base de Datos Nacional de Subvenciones (BDNS) desde su portal oficial del Ministerio de Hacienda: infosubvenciones.es.

✅ El portal ofrece un buscador limitado
⛔ Pero no permite descargar los datos

¡Vamos allá! 💪

🧵…

El portal oficial tiene notables limitaciones. Entre ellas destacan dos: los límites a la descarga de datos y el tiempo de respuesta del portal.

1️⃣ La funcionalidad de descarga que ofrece el Ministerio simplemente no funciona si tu búsqueda comprende más de 10.000 resultados.

El Ministerio podría haber paliado parcialmente esta limitación permitiendo la exportación de los primeros 10.000 resultados de las búsquedas que arrojen más. En vez de esto, ponen al ciudadano en un callejón sin salida: si hay muchos resultados, no puedes exportar ninguno. 🤷

2️⃣ La segunda limitación más prominente del portal oficial es su penosa velocidad de respuesta.

Una búsqueda de beneficiarios puede tardar CASI TRES MINUTOS en completarse. Algo tan común como pasar de página se torna una tarea exasperante.

⚠️ Esto es un torpedo al derecho de la ciudadanía a acceder a los datos para controlar la actuación de los gestores públicos. El mecanismo habilitado para ello es tan lento que en la práctica es inusable. El ciudadano tira la toalla; desiste de ejercer su derecho.

Nótese que la BDNS es un tesoro que comprende una ingente cantidad de información pública:

✅ 10,5 millones de subvenciones
✅ 350.000 convocatorias

Sin embargo, el valor de estos datos está cautivo tras un sitio web cutre y lento.

¡Se hace preciso liberar estos datos! 👇

El portal oficial ofrece, en esencia, dos tipos de registros: convocatorias y concesiones.

1️⃣ Cursando una búsqueda vacía en la pestaña «Convocatorias» provocamos la carga de la primera página de una consulta que devuelve, paginados, la totalidad de los resultados.

Cada página contiene 50 resultados, lo que hace un total de 7.015 páginas. Pero tal y como decíamos arriba…

❌ Los enlaces de descarga no funcionan
❌ La lentitud del servidor imposibilita iterar por todas las páginas

Entonces, ¿cómo podemos descargar estos datos? 🤔

La búsqueda provoca una petición XHR al servidor del Hacienda. Podemos copiarla para analizarla y replicarla con cURL en la línea de comandos.

De los siete parámetros que la aplicación envía al «endpoint» de búsqueda, identificamos inmediatamente dos:

✅ «nd», que contiene un «timestamp», esto es; el número de milisegundos transcurridos desde el 1 de enero de 1970.
✅ «rows», que controla el número de filas por página.

⚠️ Nótese que los términos que definen la búsqueda, y que hemos dejado en blanco, no viajan en la petición del usuario, sino que son mantenidos en el servidor a través de una variable de sesión que el servidor rescata a partir de una «cookie» que instala en el navegador.

Esta singular implentación es innecesariamente compleja y tiene, entre otras, las siguientes consecuencias negativas:

👎 Dificulta la descarga automatizada de resultados y, por lo tanto, la exploración por la ciudadanía de estos datos desde fuera del portal oficial.

👎 Impide que los buscadores como Google encuentren las subvenciones y sus beneficiarios.

👎 Provoca la caducidad de las peticiones, que solo funcionarán mientras no expire la variable de sesión en el servidor.

👎 Imposibilita enlazar y compartir los resultados de una búsqueda.

👎 Supone un sobreconsumo de recursos en el servidor del Ministerio, al obligarlo a gestionar el estado («state») de cada usuario que utilice el portal (!).

Esto impacta en el rendimiento del servicio y, a la postre, promueve los exasperantes tiempos de respuesta observados.

La aplicación web de Hacienda ofrece al ciudadano la posibilidad de obtener los resultados en páginas de 50, 100 o 200 resultados.

El desplegable del sitio web simplemente controla el valor del parámetro «rows» que, como hemos visto, se envía en la petición XHR al servidor.

Se considera una mala práctica de programación y un riesgo de seguridad no comprobar en el servidor los valores recibidos del usuario, pues estos podrían haber sido manipulados para provocar resultados no contemplados.

Que es justo lo que va a suceder en el siguiente tuit. 😉

Y es que aunque el interfaz de usuario del buscador de Hacienda solo permite solicitar páginas de 50, 100 o 200 resultados, en la práctica nada nos impide solicitar una página con 50.000.000 de ellos.

Obtenemos así, y en una única consulta, las 350.000 convocatorias de la BDNS.

Bajo la propiedad «rows» del fichero JSON resultante encontramos tantos objetos como convocatorias de subvenciones constan en el portal oficial.

Exploramos uno cualquiera:

La conversión del fichero JSON a un equivalente CSV explorable con herramientas como Excel o LibreOffice es trivial:

2️⃣ Vamos ahora con la descarga de los beneficiarios de las subvenciones, sin duda la parte más valiosa del conjunto de datos.

Es tentador proceder igual que con las concesiones, pero esto no funcionará.

¿Por qué?

El servidor del Ministerio tiene configurado un «timeout» que corta la corta la conexión HTTP antes de que le dé tiempo a recuperar y servir los 10,5 millones de registros.

‼️ He podido comprobar que este «timeout» está configurado con un valor excepcionalmente alto: UNA HORA.

Examinando las cabeceras de las respuestas HTTP deduzco que el contenido parece estar siendo servido con Microsoft IIS.

✅ El «timeout» predeterminado de IIS son 110 segundos.
⚠️ El Ministerio tiene un timeout 33 veces superior.

¿Cuál es la razón?

🔗 docs.microsoft.com/en-us/previous…

Personalmente, nunca había visto un servidor web (puertos 80 o 443) mantener abierta una petición HTTP durante tanto tiempo. Nótese que incluso la documentación oficial de Microsoft previene de asignar valores demasiado elevados a esta opción de configuración.

Y es que este «timeout» es una medida preventiva, pensada para evitar que un usuario arbitrario de internet pueda drenar recursos del servidor monopolizando durante más tiempo de lo necesario los canales de comunicación.

El «timeout» es como el airbag del coche, y asignarle un valor tan excepcionalmente alto como una hora equivale, en la práctica, a desconectarlo.

Pero, ¿por qué lo han hecho?

Mi conjetura es que el portal de la BDNS funcionaba bien cuando hace años lo desplegaron y no había aún un número abultado de subvenciones.

Pero es un sistema vivo, que cada día recibe nuevas convocatorias y cientos de nuevos beneficiarios…

El pobre diseño de la aplicación provoca que el rendimiento se desgrade proporcionalmente con el número de registros de la BDNS. De tal modo que cada día, y durante años, el servicio ha ido funcionando un poquito más despacio que el anterior.

📅 Esta progresiva degradación del rendimiento eventualmente debió de provocar, un buen día, que el tiempo de respuesta de la base de datos superara el tiempo de «timeout» del servidor.

El día que esto sucedió, el portal dejó de funcionar.

Y en lugar de actuar sobre la causa del problema —la arquitectura de la aplicación—, alguien decidió actuar sobre la consecuencia y simplemente incrementar el «timeout» del servidor a cinco minutos. Luego a media hora. Y finalmente… una hora. 🎉

Hay hasta memes sobre ello. 🤣

Esta colección de particularidades nos obliga a emplear una aproximación distinta a nuestro objetivo de descargar los beneficiarios de las subvenciones para auditar su reparto.

Vamos a abordarlo con dos «scripts» de Bash. 💪

En el primero consignamos un valor de compromiso para el tamaño de las páginas: 50.000 es una buena cifra, pues provoca respuestas que no disparan el «timeout», al tiempo que reduce el número de iteraciones necesarias a poco más de 200, que es un número asumible.

Utilizo «xargs» para acelerar el proceso paralelizando las consultas. Decido cursarlas de cinco en cinco para no sobrecargar el servidor.

El segundo «script» genera el (absurdo) «timestamp» y consuma la descarga emulando la petición cURL que antes inspeccionamos en el navegador.

Lanzamos el primer «script», que a su vez invoca sucesivamente el segundo, una vez por cada página, descargando 50.000 beneficiarios cada vez.

En lo que tarda el proceso nos bajamos al Scumm Bar y nos pimplamos dos jarras de grog pirata. 🍻😃

Acabadas las descargas, es conveniente transformar cada fichero JSON en su equivalente CSV y concatenarlos todos para reunir todas las concesiones de subvenciones en un único fichero de +5 GB.

Hasta aquí he detallado cómo descargar la totalidad de los contenidos públicos de la Base de Datos Nacional de Subvenciones con la finalidad de controlar la actuación de los gestores públicos.

Cuando la semana pasada hice esto mismo con el Registro de Licitadores, la respuesta del Ministerio fue «tumbar» el servicio, que a fecha de hoy sigue caído.

Es indiferente, porque ya había liberado sus datos:
🔗 docs.google.com/spreadsheets/d… docs.google.com/spreadsheets/d…

El resquicio hoy expuesto nos permite a los ciudadanos descargar todos los datos para explorarlos. Si el Ministerio lo tapa para impedir el acceso y no habilita un mecanismo alternativo eficaz, publicaré un segundo método que también he localizado, y que de momento me reservo. 😙

Más avanzada la semana publicaré todos los datos en GitHub, así como un Discord para organizarnos. Y un método para disociarlos y anonimizarlos, pues es imperativo proteger a las personas, sus circunstancias y sus datos.

¡Esto es lo que propongo! 👇

Y termino este episodio 🙂 con el primer tuit de esta disección, por si con tu retuit quieres ayudar a difundirlo. 👇

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling