Herramienta de consulta y análisis del DENUE (Directorio Estadístico Nacional de Unidades Económicas, INEGI) — inteligencia territorial y de mercado sobre los ~5 millones de establecimientos registrados en México.
Public-data tooling for Mexican business intelligence, built on INEGI's official DENUE API.
Consulta la API pública del DENUE por giro (SCIAN) + municipio + tamaño y construye una base local (SQLite/CSV) con la que corres análisis territorial sin volver a tocar la red: resumen y presencia digital, densidad por zona, comparativa entre municipios, mapa HTML y reporte markdown.
Las fuentes públicas de datos de México no tienen herramientas modernas ni integraciones de IA. Este proyecto es parte de un esfuerzo por modernizar el acceso a datos públicos mexicanos y ayudar a que negocios y organizaciones adopten mejores prácticas y sistemas basados en datos.
- Datos oficiales y abiertos: solo la API pública y gratuita del INEGI, respetando sus términos de uso y límites de peticiones.
- Análisis agregado, no perfilado: el objeto de estudio son establecimientos económicos y territorios, nunca personas.
- Reproducible: cualquiera con un token gratuito del INEGI puede correr las consultas.
H1–H4 cerrados (extracción, análisis, visual, capa agente): 168 tests, ruff limpio. Hoy la herramienta:
- descarga establecimientos del DENUE por giro + municipio + estrato y los guarda en SQLite/CSV (
fetch/export); - calcula resúmenes por giro/estrato y % de presencia digital (
summary); - calcula densidad por municipio o colonia (
density); - compara 2+ municipios lado a lado (
compare); - genera un mapa HTML interactivo (
map); - arma un reporte markdown que enlaza todo lo anterior (
report); - expone los 7 comandos con salida
--jsony exit codes predecibles para que un agente de IA los encadene.
Pendiente (H5): este README, un artículo de acompañamiento (docs/articulo.md) y la publicación del repo.
Requiere Python ≥3.11.
uv syncTambién funciona con pip si no usas uv:
pip install -e .Todos los comandos que consultan la API (fetch) necesitan un token gratuito del INEGI:
- Consíguelo en https://www.inegi.org.mx/app/api/denue/v1/tokenVerify.aspx (solo pide un correo).
- Copia
.env.examplea.env. - Pon el token:
INEGI_TOKEN=tu-token-aqui.
analysis/report (summary, density, compare, map, report) trabajan sobre la base local ya descargada y no necesitan el token ni red.
| Comando | Qué hace |
|---|---|
fetch |
Consulta la API del DENUE por giro + municipio (+ estrato opcional) y guarda los resultados en SQLite. |
export |
Exporta desde SQLite a CSV. |
summary |
Conteos por giro/estrato y % de presencia digital (sitio web / correo / teléfono). |
density |
Densidad de establecimientos por municipio o colonia. |
compare |
Comparativa lado a lado entre 2+ municipios (totales, mezcla de giros, presencia digital). |
map |
Mapa HTML (folium) con marcadores agrupados de los establecimientos consultados. |
report |
Reporte markdown con resumen + densidad + comparativa (si aplica) + liga al mapa. |
Todos aceptan --json (salida estructurada {"ok": bool, "data": …, "error": …}) y usan los mismos exit codes: 0 éxito · 1 error de uso/argumentos · 2 error de API/red/token · 3 consulta válida sin resultados. Detalle completo en docs/diseno.md §4.
Los ejemplos de summary, density y compare de abajo son salida real, generada corriendo estos comandos contra una base SQLite temporal poblada con la fixture de pruebas (tests/fixtures/establecimientos_h2.json: 24 establecimientos de prueba en Guadalajara, Zapopan y Monterrey) — no están inventados ni editados a mano.
uv run denue fetch --giro tortillerías --municipio Zapopan --jsonEste comando sí necesita un INEGI_TOKEN válido en .env y conexión a internet, así que aquí no hay una salida de ejemplo pegada — la puedes ver corriendo el comando tú mismo con tu propio token.
uv run denue summary --db denue.sqlite --por giroTotal: 24
Por giro:
311999 7 29.2% Descripcion SCIAN de prueba
311830 6 25.0% Descripcion SCIAN de prueba
312100 6 25.0% Descripcion SCIAN de prueba
31_500 5 20.8% Descripcion SCIAN de prueba
Presencia digital:
Sitio web: 8 33.3%
Correo: 8 33.3%
Telefono: 8 33.3%
Con --json la misma consulta da el contrato que consume un agente:
{"ok": true, "data": {"total": 24, "filtros": {"giro": null, "municipio": null, "entidad": null, "estrato": null, "por": "todo"}, "por_giro": [{"clave": "311999", "etiqueta": "Descripcion SCIAN de prueba", "total": 7, "pct": 29.2}, {"clave": "311830", "etiqueta": "Descripcion SCIAN de prueba", "total": 6, "pct": 25.0}, {"clave": "312100", "etiqueta": "Descripcion SCIAN de prueba", "total": 6, "pct": 25.0}, {"clave": "31_500", "etiqueta": "Descripcion SCIAN de prueba", "total": 5, "pct": 20.8}], "por_estrato": [...], "digital": {"total": 24, "con_sitio_web": 8, "con_correo": 8, "con_telefono": 8, "pct_sitio_web": 33.3, "pct_correo": 33.3, "pct_telefono": 33.3}}, "error": null}uv run denue density --db denue.sqlite --nivel municipio --top 5Densidad por municipio (total consultado: 24)
Monterrey: 10 (41.7%) · radio medio: 3.63 km (n=8)
Guadalajara: 8 (33.3%) · radio medio: 3.37 km (n=7)
Zapopan: 6 (25.0%) · radio medio: 2.20 km (n=5)
uv run denue compare --db denue.sqlite --municipios "Guadalajara,Zapopan,Monterrey"Total: 24
Métrica Guadalajara Zapopan Monterrey
Total 8 6 10
% sitio web 25.0% 33.3% 40.0%
% correo 37.5% 33.3% 30.0%
% telefono 37.5% 33.3% 30.0%
Giros comunes: 311830, 311999, 312100, 31_500
uv run denue map --db denue.sqlite --salida mapa.html --jsonContra la misma base de prueba esto genera un HTML real ({"ok": true, "data": {"ruta": "mapa.html", "total": 24, "con_coords": 20, "sin_coords": 4}, "error": null}): un mapa de Leaflet/OpenStreetMap centrado en el promedio de coordenadas de los resultados, con los 20 establecimientos que tienen lat/lon agrupados en clusters (MarkerCluster) que se separan al hacer zoom, cada uno con un popup con nombre, giro y estrato al hacer clic; los 4 sin coordenadas se cuentan en sin_coords pero no se dibujan. Ábrelo con doble clic o start mapa.html — necesita red la primera vez que lo abres (los tiles de OSM y el JS de Leaflet vienen de CDN, no van embebidos en el HTML).
No hay captura de pantalla ni GIF del mapa en este README: generarlos requiere un navegador (headless o no) que no está disponible en el entorno donde se escribió esta documentación. Genera el HTML tú mismo con el comando de arriba para verlo.
uv run denue report --db denue.sqlite --municipios "Guadalajara,Zapopan,Monterrey" --mapa mapa.html --salida reporte.md --jsonArma un .md con el resumen, la densidad, la comparativa (porque se pasaron 2+ --municipios) y una liga relativa al mapa.html generado arriba.
Además del uso manual, el proyecto trae una skill (skill/SKILL.md) que enseña a un agente a encadenar los 7 comandos con la salida --json como contrato: resolver rubro/plaza → fetch → summary/density/compare → map → report. Un agente con la skill instalada resuelve algo como:
"Analiza las tortillerías de Zapopan"
corriendo por su cuenta el flujo fetch → summary → density → map → report y presentando un resumen con los datos notables al final. La skill también refuerza la regla de no barrer por masas: confirma rubro, plaza y cantidad antes del primer fetch.
Ver docs/diseno.md para el diseño completo (módulos, flujo de datos, esquema, no-objetivos) y docs/tareas.md para el tablero de avance por hitos.
MIT — ver LICENSE.