🇪🇸 BOE Explorer
February 18, 2026 · View on GitHub
🌐 Demo en vivo: https://test.pro-eurtec.com/
Plataforma open-source de análisis, enriquecimiento y visualización de datos públicos del Boletín Oficial del Estado (BOE), Base de Datos Nacional de Subvenciones (BDNS), Boletín Oficial del Registro Mercantil (BORME), Congreso de los Diputados y Promesas Electorales.
📋 Índice
- Descripción
- Características principales
- Arquitectura del sistema
- Fuentes de datos
- Stack tecnológico
- Algoritmos y NLP
- API REST
- Almacenamiento de datos
- Instalación
- Configuración del cron
- Contribuir al proyecto
- Roadmap
- Licencia
🎯 Descripción
BOE Explorer es una plataforma 100% open-source que agrega, enriquece y cruza datos de las cinco principales fuentes de datos abiertos del Estado español:
| Fuente | Datos |
|---|---|
| BOE | Legislación, licitaciones, adjudicaciones, nombramientos, convenios |
| BDNS | Subvenciones públicas, convocatorias, destinatarios |
| BORME | Registro mercantil, socios, administradores, cargos empresariales |
| Congreso | Votaciones parlamentarias, asistencia, transferencias de voto, correlación por CCAA |
| Promesas | Promesas electorales, cumplimiento, patrimonio de diputados, contradicciones políticas |
El objetivo es democratizar el acceso a la información pública, facilitando la detección de patrones de gasto, concentración empresarial, actividad parlamentaria y seguimiento de compromisos electorales.
✨ Características principales
📊 Dashboard multi-fuente
- Agregación diaria automática de BOE + BDNS + BORME
- KPIs en tiempo real: documentos del día, tendencias semanales/mensuales
- Gráficos interactivos con drill-down (click en cualquier segmento para ver el detalle)
🔍 Motor de búsqueda avanzado
- Búsqueda federada unificada (BOE + Licitaciones + Subvenciones simultáneamente)
- Filtros combinables: empresa, NIF/CIF, departamento, tipo, CCAA, rango de importes, procedimiento
- Búsqueda accent-insensitive (encontrar "García" buscando "garcia")
💰 Análisis de licitaciones
- Enriquecimiento XML individual de cada licitación
- Extracción de importes (6 patrones prioritarios: adjudicación > estimado > presupuesto)
- Datos de adjudicatario + NIF, CPV, procedimiento, ofertas mayor/menor (13.2/13.3)
- Desglose por departamento, empresa, tipo de contrato, CCAA, sector y timeline
🔗 Motor de referencias cruzadas
- Correlación automática entre documentos BOE y licitaciones
- Scoring multi-signal con confianza ponderada (0.0–1.0)
- Detección de afinidad departamental, coincidencia de keywords, solapamiento de términos
🏢 Inteligencia empresarial (BORME)
- Parsing de PDFs del Registro Mercantil con
pdftotext - Extracción de socios, administradores, consejeros (30+ tipos de cargo)
- Seguimiento de nombramientos y ceses con estado activo/cesado
- 92,000+ empresas indexadas
🎯 Análisis de subvenciones (BDNS)
- Clasificación por sector, nivel administrativo, entidad y destino
- Detección de destinos internacionales (80+ países, 6 regiones)
- Timeline de convocatorias con tendencias
⚠️ Alertas de transparencia
- Concentración de contratos por empresa (flag ≥3, alerta alta ≥5)
- Recurrencia empresa-departamento
- Clasificación de 17 tipos de entidad jurídica española por NIF/CIF
🏛 Congreso de los Diputados
- Votaciones parlamentarias: 1,666 votaciones de 114 sesiones (XV Legislatura)
- Diagrama Sankey de transferencias de voto entre partidos
- Muro de la Vergüenza: ranking de diputados por asistencia y patrones de voto
- Correlación por CCAA: análisis de afinidad de voto entre comunidades autónomas
- Buscador de diputados: búsqueda por nombre, filtro por grupo parlamentario, ordenación por nombre/asistencia/votos
- Tabla de resultados con 8 columnas: ranking, nombre, grupo, asistencia, sí, no, abstención, no_vota
📊 Promesas Electorales
- Promesómetro: barras de progreso apiladas por partido (PSOE, Sumar, PP, VOX) con indicadores gobierno/oposición
- Buscador de promesas: filtro por texto libre, partido y estado (cumplida, parcial, en_trámite, incumplida, rechazada)
- Nubes de Palabras: comparativa programa electoral vs. actividad legislativa real, con pestañas por partido
- Timeline de Contradicciones: 7 casos documentados de "lo que dijeron" vs. "lo que hicieron" con referencias BOE
- Patrimonio de diputados: tabla comparativa antes/después de ser electos + gráfico de variación patrimonial
- 34 promesas reales con evidencias, timeline y estado de cumplimiento
- Extracción automatizada de keywords desde PDFs de programas electorales (vía
pdftotext)
🏗 Arquitectura del sistema
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND (SPA) │
│ index.html (~4,100 líneas) │
│ Vanilla JS · Chart.js 4.4.1 · Tailwind CSS · WordCloud │
│ 90+ funciones · 25+ gráficos · Sankey · Dark/Light mode │
└───────────────────────────┬─────────────────────────────────┘
│ HTTP/JSON
┌───────────────────────────┴─────────────────────────────────┐
│ API REST (PHP 8.x) │
│ api/index.php (router) │
│ 18 endpoints │
├──────────┬──────────┬──────────┬──────────┬─────────────────┤
│ boe_ │ bdns_ │ borme_ │ congreso │ promesas_parser │
│ parser │ parser │ parser │ _parser │ 367 LoC │
│ 375 LoC │ 680 LoC │ 727 LoC │ 568 LoC │ │
├──────────┴──────────┴──────────┴──────────┴─────────────────┤
│ data_store.php (743 LoC) · cross_ref (194 LoC) │
│ Búsqueda · Análisis · Sectores · Empresas · Keywords │
├─────────────────────────────────────────────────────────────┤
│ config.php (151 LoC) │
│ Cache · HTTP client · Normalización │
└───────────────────────────┬─────────────────────────────────┘
│ Flat-file JSON
┌───────────────────────────┴─────────────────────────────────┐
│ ALMACENAMIENTO │
│ api/data/boe/YYYY-MM-DD.json (557+ días) │
│ api/data/bdns/convocatorias.json (10K+ registros) │
│ api/data/borme/YYYY-MM-DD.json (42+ días) │
│ api/data/congreso/votaciones/ (114 sesiones, 1666 JSON) │
│ api/data/promesas/promesas.json (34 promesas, patrimonio) │
│ api/cache/*.json (TTL: 5-60 min) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ FUENTES DE DATOS EXTERNAS │
│ │
│ BOE XML ── BDNS REST ── BORME PDF ── Congreso Datos Abiertos│
│ boe.es hacienda.gob boe.es/borme congreso.es/opendata │
└─────────────────────────────────────────────────────────────┘
📡 Fuentes de datos
| Fuente | Protocolo | URL Base | Formato |
|---|---|---|---|
| BOE (Boletín Oficial del Estado) | REST/XML | https://www.boe.es/datosabiertos/api | XML (sumarios + documentos individuales) |
| BDNS (Base Nacional de Subvenciones) | REST/JSON | https://www.pap.hacienda.gob.es/bdnstrans/api | JSON (con autenticación XSRF + cookies) |
| BORME (Registro Mercantil) | REST/JSON + PDF | https://www.boe.es/datosabiertos/api/borme/ | JSON (sumario) + PDF (actas) |
| Congreso (Datos Abiertos) | REST/JSON | https://www.congreso.es/es/opendata/votaciones | JSON (sesiones + votaciones individuales) |
| Contratación del Estado | ATOM Feed | https://contrataciondelestado.es | XML/ATOM (parser legacy) |
🛠 Stack tecnológico
Backend
| Tecnología | Uso |
|---|---|
| PHP 8.x (vanilla, sin framework) | API REST, parsers, procesamiento |
| cURL (ext-curl) | HTTP client para APIs externas |
| pdftotext (poppler-utils) | Extracción de texto de PDFs BORME |
| JSON flat-file | Almacenamiento sin base de datos |
| OPcache | Caché de bytecode PHP |
Frontend
| Tecnología | Versión | Uso |
|---|---|---|
| Vanilla JavaScript | ES2021+ | SPA, 90+ funciones, async/await |
| Chart.js | 4.4.1 | 25+ gráficos interactivos con drill-down |
| chartjs-chart-sankey | 0.12.1 | Diagrama Sankey de transferencias de voto |
| chartjs-chart-wordcloud | 4.4.3 | Nubes de palabras (programa vs legislativo) |
| Tailwind CSS | 3.x (CDN) | Diseño responsive, dark mode |
| Inter (Google Fonts) | Variable weight | Tipografía |
| Material Symbols | Outlined | Iconografía |
Infraestructura
| Componente | Detalle |
|---|---|
| Servidor | Debian Linux, Virtualmin |
| PHP-FPM | Worker pool con OPcache |
| Cron | Actualización diaria automática |
| Caché | Archivos JSON, TTL configurable (5–60 min) |
Total: ~11,000+ líneas de código (sin datos ni tests)
🧠 Algoritmos y NLP
1. Motor de Referencias Cruzadas
Archivo: api/cross_reference.php (194 LoC)
Scoring multi-señal que combina 5 dimensiones para calcular la confianza (0.0 – 1.0) de la correlación entre un documento BOE y una licitación:
| Señal | Peso máximo | Método |
|---|---|---|
| Keywords temáticos | +0.15/categoría | 8 categorías × ~10 keywords cada una |
| Afinidad departamental | +0.30 | 13 diccionarios de alias ministeriales |
| Solapamiento de palabras | +0.30 | Tokens ≥4 caracteres, Jaccard-like |
| Afinidad tipo documento | +0.10 | Bonus para tipos de contratación |
| Matching de referencia ID | +0.50 | Coincidencia exacta de identificadores |
Niveles de confianza: Alta (≥70%), Media (40-70%), Baja (20-40%), Muy baja (<20%)
2. Clasificador de sectores
Archivos: api/data_store.php + api/bdns_parser.php
Clasificador NLP basado en keywords con 14 sectores y 100+ keywords por conjunto, aplicado tanto a licitaciones como a subvenciones:
Salud · Educación · Cultura · Vivienda · Medio Ambiente
Agricultura · Industria · Transporte · Empleo · Seguridad
Justicia · Cooperación · Digitalización · Servicios Generales
Técnicas: normalización accent-insensitive, lowercase matching, priorización por especificidad.
3. Parser BORME (NLP sobre PDF)
Archivo: api/borme_parser.php (727 LoC)
Pipeline de extracción:
PDF → pdftotext -layout → Limpieza headers/footers → Split por nº registro
→ Detección de secciones (Nombramientos/Ceses) → Extracción de personas
→ Clasificación de 30+ tipos de cargo → Merge activo/cesado
Cargos reconocidos: Administrador Único, Consejero Delegado, Presidente, Secretario, Apoderado, Liquidador, Auditor, Representante, Socio, y 20+ variantes.
4. Enriquecimiento de licitaciones
Archivo: api/boe_parser.php (375 LoC)
Cada licitación se enriquece individualmente fetching su XML del BOE:
- 6 patrones de extracción de importe (prioridad: adjudicación > estimado > presupuesto > oferta)
- Parsing de números españoles (1.234.567,89 → float)
- Extracción de adjudicatario + NIF/CIF (campos 12.1, 12.2)
- Detección PYME, códigos CPV, tipo de procedimiento
- Ofertas mayor/menor (campos 13.2, 13.3)
5. Detección de destinos internacionales
Archivo: api/bdns_parser.php
Clasificador geo-NLP:
- 80+ países con variantes de gentilicio y nombre
- 6 agrupaciones regionales (África, América Latina, Asia, UE, Oriente Medio, Países en desarrollo)
- Word-boundary regex para keywords cortos (≤6 chars) para evitar falsos positivos
6. Clasificación de entidades jurídicas
Archivo: api/data_store.php
Identificación de 17 tipos de entidad a partir del prefijo NIF/CIF:
A → S.A. | B → S.L. | C → S.Colectiva | D → S.Comanditaria
E → Comunidad | F → Cooperativa | G → Asociación | H → C.Propietarios
J → Civil | N → Extranjera | P → Corporación | Q → Organismo Público
R → Congregación | S → Estatal/Autonómico | U → UTE | V → Otros | W → Sucursal Extranjera
7. Alertas de transparencia (Red Flags)
Detección automática de:
- Concentración: empresa con ≥3 contratos → flag, ≥5 → alerta alta
- Recurrencia: misma empresa + mismo departamento ≥2 veces
- Análisis PYME vs Gran empresa por volumen de adjudicación
8. Parser del Congreso (Votaciones)
Archivo: api/congreso_parser.php (568 LoC)
Pipeline de procesamiento de datos abiertos del Congreso:
API Congreso → Descarga sesiones → JSON votaciones individuales
→ Agregación por diputado (asistencia, votos Sí/No/Abs/NoVota)
→ Cálculo de flujos (Sankey) entre grupos parlamentarios
→ Correlación de voto por CCAA → Rankings (mejores/peores)
Capacidades:
- 1,666 votaciones procesadas de 114 sesiones (XV Legislatura)
- 407 diputados únicos (incluye reemplazos)
- 37 flujos de transferencia de voto entre grupos para diagrama Sankey
- 19 correlaciones por CCAA para análisis de afinidad territorial
- Caché de asistencia incremental para rendimiento
9. Parser de Promesas Electorales
Archivo: api/promesas_parser.php (367 LoC)
Sistema de seguimiento de compromisos electorales:
promesas.json → Estadísticas por partido → Búsqueda multi-criterio
→ Extracción de keywords de PDFs (pdftotext) → Cross-ref con BOE
→ API JSON con stats, patrimonio, contradicciones
Funciones principales:
promesas_stats()— Agregados por partido: % cumplida, en proceso, incumplida, rechazadapromesas_buscar()— Búsqueda multi-criterio: texto, partido, categoría, estadopromesas_extract_keywords_from_pdf()— NLP sobre PDFs de programas electorales (tokenización, stopwords español, top-N keywords)promesas_buscar_en_boe()— Cruce de keywords de promesas con datos BOE existentes
Datos curados:
- 34 promesas reales (PSOE: 12, Sumar: 8, PP: 8, VOX: 6) con estados, evidencias y timeline
- 8 patrimonios de diputados notables (antes/después de ser electos)
- 7 contradicciones documentadas con referencias BOE
- Keywords estimadas de programa vs. actividad legislativa por partido
📡 API REST
Base URL: /api/?action=
Endpoints principales (18)
| Endpoint | Params | Descripción |
|---|---|---|
status | — | Salud del sistema, versión, conteos |
dashboard | — | KPIs del día, tendencias, últimos documentos |
documentos | texto, departamento, seccion, tipo, fecha_* | Búsqueda de documentos BOE (paginado) |
licitaciones | texto, empresa, nif, tipo, departamento, ccaa, importe_min/max, procedimiento, fecha_* | Búsqueda de licitaciones (paginado) |
referencias | confianza_min, limite | Referencias cruzadas BOE↔Licitaciones |
resumen-gasto | periodo (diario/semanal/mensual) | Análisis de gasto por múltiples dimensiones |
analisis-empresas | — | Concentración empresarial + alertas |
analisis-tematico | — | Análisis temático por keywords |
subvenciones | — | Analytics de BDNS (sector, nivel, destino, timeline) |
subvenciones-buscar | texto, nivel, sector, fecha_* | Búsqueda de convocatorias BDNS (paginado) |
subvenciones-chart-detalle | campo, valor | Drill-down de gráficos BDNS |
subvenciones-destino-detalle | destino | Detalle por destino internacional |
busqueda-global | q | Búsqueda federada (BOE + Licitaciones + Subvenciones) |
socios | empresa | Socios/cargos de empresa desde BORME |
borme-status | — | Estado de procesamiento BORME |
departamentos | — | Lista de departamentos únicos (30 días) |
congreso | — | Votaciones, asistencia, Sankey, correlación CCAA (caché 30 min) |
promesas | — | Promesómetro, stats, patrimonio, contradicciones, keywords (caché 1h) |
Ejemplo de uso
# Buscar licitaciones de Defensa con importe > 1M€
curl "https://tu-dominio.com/api/?action=licitaciones&departamento=Defensa&importe_min=1000000"
# Buscar socios de Telefónica en BORME
curl "https://tu-dominio.com/api/?action=socios&empresa=TELEFONICA"
# Análisis de gasto mensual
curl "https://tu-dominio.com/api/?action=resumen-gasto&periodo=mensual"
# Datos del Congreso (votaciones, Sankey, diputados)
curl "https://tu-dominio.com/api/?action=congreso"
# Promesas electorales (promesómetro, patrimonio, contradicciones)
curl "https://tu-dominio.com/api/?action=promesas"
💾 Almacenamiento de datos
Filosofía: Zero-Database
BOE Explorer usa almacenamiento flat-file JSON intencionalmente:
- ✅ Sin dependencias — No necesita MySQL, PostgreSQL ni MongoDB
- ✅ Portabilidad total — Los datos son archivos legibles por humanos
- ✅ Backup trivial —
cp -r api/data/ backup/ - ✅ Versionable — Compatible con git (aunque no recomendado por volumen)
- ✅ Procesamiento incremental — Un archivo por día, merge selectivo
Estructura
api/data/
├── meta.json # Índice global: conteos diarios, rango de fechas, totales
├── boe/
│ └── YYYY-MM-DD.json # Array de documentos BOE del día (~557 archivos)
├── bdns/
│ ├── convocatorias.json # Todas las convocatorias (merge deduplicado por ID)
│ ├── taxonomias.json # Datos de referencia (regiones, sectores, etc.)
│ └── meta.json # Metadata de actualización BDNS
├── borme/
│ ├── YYYY-MM-DD.json # Actas parseadas de todas las provincias del día
│ ├── index.json # Índice invertido empresa → fechas
│ └── meta.json # Metadata de procesamiento BORME
├── congreso/
│ ├── votaciones/ # 114 directorios de sesión
│ │ └── sesionNN/ # JSON por cada votación individual
│ ├── diputados.json # Índice de diputados y grupos parlamentarios
│ ├── asistencia_cache.json # Caché incremental de asistencia
│ └── meta.json # Metadata: 114 sesiones, 1666 votaciones
├── promesas/
│ └── promesas.json # 34 promesas, 8 patrimonios, 7 contradicciones, keywords
└── .htaccess # "Deny from all" (seguridad)
Caché
api/cache/
├── {md5_hash}.json # Cache con TTL configurable por endpoint
└── .htaccess # "Deny from all"
| Endpoint | TTL |
|---|---|
| BOE día | 10 min |
| Dashboard | 5 min (rendered: 1h) |
| Licitaciones | 15 min |
| Analytics | 1 hora |
| Congreso | 30 min |
| Promesas | 1 hora |
🚀 Instalación
Requisitos previos
- PHP 8.0+ con extensiones:
curl,json,mbstring,xml - pdftotext (poppler-utils) para parsing BORME
- Servidor web con soporte PHP (Apache/Nginx)
- ~500 MB de espacio en disco para datos históricos
Pasos
# 1. Clonar el repositorio
git clone https://github.com/vbmedina91/boeexplorer.git
cd boeexplorer
# 2. Instalar pdftotext (si no está instalado)
sudo apt-get install poppler-utils
# 3. Crear directorios de datos
mkdir -p api/data/boe api/data/bdns api/data/borme api/data/congreso api/data/promesas api/cache
# 4. Configurar permisos
chmod 755 api/data api/cache
chown -R www-data:www-data api/data api/cache
# 5. Proteger directorios de datos (si usas Apache)
echo "Deny from all" > api/data/.htaccess
echo "Deny from all" > api/cache/.htaccess
# 6. Ejecutar primera carga de datos
php cron_update.php
# 7. (Opcional) Backfill histórico — carga los últimos N días
php backfill.php --days=30
# 8. Abrir en el navegador
# http://tu-dominio.com/
Verificar instalación
# Comprobar estado del sistema
curl "http://tu-dominio.com/api/?action=status"
# Resultado esperado:
# {"version":"2.1.0","total_documentos":119000,...}
⏰ Configuración del cron
# Actualización diaria a las 20:00 (cuando BOE publica el sumario del día siguiente)
0 20 * * * cd /ruta/al/proyecto && php cron_update.php >> /var/log/boe_cron.log 2>&1
El cron ejecuta secuencialmente:
- Fetch BOE — Descarga sumario del día y clasifica documentos
- Enriquecimiento — Fetch XML individual de cada licitación para importes, adjudicatarios
- BDNS Update — Descarga nuevas convocatorias de subvenciones
- BORME Update — Descarga y parsea PDFs del Registro Mercantil
- Limpieza de caché — Invalida cachés afectados
🤝 Contribuir al proyecto
¡Las contribuciones son bienvenidas! BOE Explorer es un proyecto comunitario para mejorar la transparencia del Estado español.
¿Cómo puedes contribuir?
🐛 Reportar bugs
Abre un issue describiendo:
- Qué esperabas vs qué ocurrió
- Pasos para reproducir
- Capturas de pantalla si aplica
💡 Proponer mejoras
Abre un issue con la etiqueta enhancement describiendo:
- El problema que resuelve
- Propuesta de solución
- Impacto esperado
🔧 Contribuir código
- Fork del repositorio
- Crea una rama para tu feature:
git checkout -b feature/mi-mejora - Haz commit de tus cambios:
git commit -m "Añadir: descripción" - Push a tu fork:
git push origin feature/mi-mejora - Abre un Pull Request describiendo los cambios
📝 Mejorar documentación
- Corregir errores en el README
- Añadir ejemplos de uso de la API
- Traducir a otros idiomas (inglés, catalán, etc.)
Áreas donde más se necesita ayuda
| Área | Descripción | Dificultad |
|---|---|---|
| Nuevos parsers | Parsear DOGC (Cataluña), BOJA (Andalucía), otros boletines autonómicos | Media-Alta |
| Machine Learning | Reemplazar clasificadores de keywords por modelos NLP (spaCy, BERT) | Alta |
| Base de datos | Migración opcional a SQLite/PostgreSQL para mejor rendimiento | Media |
| Tests | Crear suite de tests unitarios (PHPUnit) | Media |
| Visualización | Nuevos tipos de gráficos, mapas interactivos de España | Media |
| API pública | Documentación OpenAPI/Swagger, rate limiting, API keys | Media |
| Mobile | App React Native o PWA mejorada | Alta |
| Accesibilidad | Mejoras WCAG 2.1, navegación por teclado | Baja-Media |
| Internacionalización | i18n para interfaz multilingüe | Baja |
| Datos abiertos | Exportación CSV/Excel/JSON de resultados | Baja |
Convenciones de código
- PHP: Sin framework, código limpio y documentado con PHPDoc
- JS: Vanilla ES2021+, funciones con nombres descriptivos
- Commits: En español, formato
Tipo: descripción(Añadir, Corregir, Mejorar, Refactor) - Sin dependencias externas (Composer/npm) — el proyecto funciona con
git clone+ PHP
🗺 Roadmap
✅ Completado
- Congreso de los Diputados — Votaciones, Sankey, asistencia, correlación CCAA, buscador de diputados
- Promesas Electorales — Promesómetro, nubes de palabras, timeline de contradicciones, patrimonio
- Extracción de keywords desde PDFs — vía pdftotext sobre programas electorales
- Cross-reference promesas ↔ BOE — Búsqueda automática de keywords en datos BOE existentes
🔜 Pendiente
- Boletines autonómicos (DOGC, BOJA, BOCM, etc.)
- Exportación de datos (CSV, Excel, JSON)
- Mapas interactivos por CCAA con datos georreferenciados
- Alertas personalizadas por email/Telegram
- API pública con documentación Swagger
- Tests unitarios y CI/CD
- Migración opcional a SQLite para mejor rendimiento
- PWA con soporte offline
- Análisis de redes: grafos de relaciones empresa-departamento
- Machine Learning para clasificación temática
- Ampliar promesas a más partidos (ERC, PNV, Bildu, JxCAT)
- Automatización completa de keywords con PDFs reales de programas
📄 Licencia
Este proyecto está bajo la licencia MIT. Ver LICENSE para más detalles.
🙏 Créditos
- Datos: BOE, BDNS, BORME, Congreso Datos Abiertos
- Herramientas: PHP, Chart.js, chartjs-chart-sankey, chartjs-chart-wordcloud, Tailwind CSS, poppler-utils
Hecho con ❤️ para la transparencia del Estado español
⭐ Dale una estrella si te resulta útil