Este proyecto, desarrollado en Python, emplea Selenium para automatizar la navegación y extracción de datos del portal Consulta Amigable (de actualización mensual) del Ministerio de Economía y Finanzas (MEF) de Perú.
El objetivo es obtener información sobre la ejecución del gasto público de la sección "¿Quién gasta?". El proceso sigue una estructura jerárquica, iterando por los niveles definidos en las rutas de navegación (ejemplo: año, departamento, provincia y municipalidad), siendo el último nivel de donde se obtienen los datos.
Esta versión cuenta con dos rutas de navegación predefinidas:
-
MUNICIPALIDADES (GOB. LOCALES → MUNICIPALIDADES):
- Niveles de iteración: Año → Departamento → Provincia → Municipalidad.
-
SECTORES (GOB. NACIONAL → SECTORES):
- Niveles de iteración: Año → Sector → Pliego → Ejecutora.
Los datos obtenidos se preprocesan y almacenan en formato XLSX/CSV.
El código está diseñado para ser modular y flexible, permitiendo la incorporación de nuevas rutas y niveles de navegación sin modificar la lógica central del código. Esto facilita la adaptación del script a posibles cambios en la estructura del portal o incluso su aplicación en otros portales web.
Para garantizar la trazabilidad y colaboración en el desarrollo, el proyecto se gestiona con Git y está alojado en GitHub, lo que permite el control de versiones y contribuciones de otros usuarios.
Este proyecto fue desarrollado con:
- Python 3.11
- ChromeDriver
- Git (recomendado para clonar el repositorio)
Para ejecutar se necesita tener instaladas las siguientes dependencias:
pandas==2.2.3
numpy==2.2.2
openpyxl==3.1.5
selenium==4.28.1
requests==2.32.3
Important
Para clonar el repositorio instalar Git.
-
Abrir una terminal o línea de comandos Git Bash.
-
Ejecutar el siguiente comando para clonar el repositorio en tu máquina local:
git clone https://github.com/AlexEvanan/Web-Scraping-Consulta-Amigable-MEF.git
- Establecer como directorio de trabajo la carpeta clonada.
cd Web-Scraping-Consulta-Amigable-MEF
Se recomienda utilizar un entorno virtual para gestionar las dependencias del proyecto de forma aislada.
-
Abrir una terminal CMD dentro del directorio del proyecto.
-
Ejecutar el siguiente comando para crear el entorno virtual.
python -m venv .venvWS
- Activar el entorno virtual.
.venvWS\Scripts\activate
Note
Verificar que el terminal muestre el entorno virtual activo. Ejemplo: (.venvWS) D:\...
En la terminal CMD ejecutar:
pip install -r requirements.txt
Desde la web oficial ChromeDriver descargar la version estable del .exe
en formato .zip
.
Los archivos extraídos del .zip
guardar y/o reemplazar en la carpeta 03_config\chromedriver\
Important
La versión del Chrome (el navegador regular) debe estar actualizado.
/WS CAMEF/
│
├── 01_data/ # Datos extraídos y procesados
│ ├── raw/
│ └── processed/
│
├── 02_src/ # Código fuente
│ ├── a_config.py # Configuración url, driver y otros
│ ├── b_scraper.py # Código relacionado con el scraping web
│ ├── c_cleaner.py # Código para limpiar y preprocesar los datos
│ └── d_analysis.ipnb # Scripts de análisis de los datos
│
├── 03_config/ # Driver para simular navegación
│ └── chromedriver/
│ ├── chromedriver.exe
│ ├── LICENSE.chromedriver
│ └── THIRD_PARTY_NOTICES.chromedriver
│
├── 04_results/ # Resultados y reportes
├── requirements.txt # Dependencias del proyecto
├── README.md # Documentación
└── .venvWS/ # Entorno virtual
A continuación se describe los códigos fuente (source) que se encuentran en la carpeta 02_src/
Define rutas, parámetros de ejecución, navegación en la web y procesamiento de datos.
- Configuración del directorio y URL.
Variable | Descripción |
---|---|
PATH_BASE |
Directorio principal |
PATH_DATA_RAW |
Ruta donde se almacenan los datos crudos |
PATH_DATA_PRO |
Ruta donde se guardan los datos preprocesados |
PATH_DRIVER |
Ubicación del WebDriver |
URL |
Plataforma de la cual se extraen los datos |
- Parámetros de Scraping y preprocesamiento
Variable | Descripción |
---|---|
YEARS |
Rango de años list(range(2015, 2026)) (no incluye el limite superior) |
GLOBAL_SELECTORS |
Diccionario con selector de año y frame principal de la web |
ROUTES |
Diccionario de rutas con sus respectivos niveles y acciones a ejecutar |
FILE_CONFIGS |
Diccionario con la configuración del archivo de salida, por cada ruta existente: - ENCABEZADOS_BASE - ARCHIVO_SCRAPING |
CLEANING_CONFIGS |
Diccionario con el nombre las columnas a procesar (ENCABEZADOS_BASE ) y los nuevos nombres, definidos por cada ruta existente. |
Note
Este script define los parámetros de configuración que pueden ser modificados de acuerdo a las necesidades. El objetivo es separar la configuración de la lógica del código principal.
Este script es el núcleo del proceso de scraping. Su función principal es automatizar la navegación en el portal definido, extraer los datos y almacenarla en un archivo de salida.
- Carga la configuración desde
a_config.py
. - Define funciones especializadas.
El script se compone de las siguientes funciones creadas:
Función | Descripción |
---|---|
initialize_driver() |
Configura y lanza el WebDriver. |
navigate_to_url() |
Accede a la URL objetivo. |
switch_to_frame() |
Reinicia/cambia el contexto al frame especificado. |
click_on_element() |
Hace clic en un elemento de la página. |
select_dropdown_option() |
Selecciona una opción en un desplegable. |
extract_table_data() |
Extrae datos de una tabla en la web. |
get_final_headers() |
Extrae los encabezados de la tabla en la web. |
navigate_levels() |
Función recursiva que gestiona la navegación a través de los niveles jerárquicos. |
extract_data_by_year() |
Inicia la navegación iterativa para extraer datos, utilizando el contexto definido. |
save_data() |
Guarda los datos extraídos. |
select_route() |
Solicita al usuario seleccionar una ruta de navegación. |
main() |
Función principal que llama a las funciones en orden correcto. |
El siguiente diagrama muestra la lógica de todo el proceso para el caso de la RUTA N°1: MUNICIPALIDADES.
---
title: State Diagram del Proceso de Web Scraping (Ruta 1)
---
stateDiagram
[*] --> IniciarDriver : initialize_driver()
IniciarDriver --> NavegarUrl : navigate_to_url()
%% Agrupar iteración por año
NavegarUrl --> SeleccionarAño : select_dropdown_option()
state "Iteración Años" as IA {
SeleccionarAño --> SeleccionarTipoGobierno : click_on_element()
SeleccionarTipoGobierno --> SeleccionarGobiernoLocal : click_on_element()
SeleccionarGobiernoLocal --> SeleccionarSubtipo : click_on_element()
SeleccionarSubtipo --> SeleccionarDepartamento : click_on_element()
}
%% Agrupar iteración por Departamento
state "Iteración Departamentos" as ID {
SeleccionarDepartamento --> LoopDepartamentos : por cada departamento
LoopDepartamentos --> ClickDepartamento : click_on_element(i)
ClickDepartamento --> SeleccionarProvincia : click_on_element()
}
%% Agrupar iteración por Provincia
state "Iteración Provincias" as IP {
SeleccionarProvincia --> LoopProvincias : por cada provincia
LoopProvincias --> ClickProvincia : click_on_element(j)
ClickProvincia --> SeleccionarMunicipalidad : click_on_element()
}
%% Agrupar extracción de datos
state "Extracción de Datos" as ED {
SeleccionarMunicipalidad --> ExtraerDatos : extract_table_data()
ExtraerDatos --> AgregarMetadatos : Metadatos (año, depto...)
AgregarMetadatos --> GuardaDatos : save_data()
}
%% Retornos a provincia
GuardaDatos --> VolverProvincia : driver.back()
VolverProvincia --> LoopProvincias : siguiente provincia
%% Retornos a departamento
LoopProvincias --> VolverDepartamento : driver.back()
VolverDepartamento --> LoopDepartamentos : siguiente departamento
%% Retornos a años
LoopDepartamentos --> VolverAño : driver.back()
VolverAño --> SeleccionarAño : siguiente año
%% Finalización del scraping
SeleccionarAño --> [*]: Fin iteración por año
Elaboración propia.
Nota: Este diagrama muestra el flujo de navegación y extracción de datos, detallando las iteraciones en la automatización. Implícitamente, después de cada click_on_element()
, se ejecuta switch_to_frame()
.
Este script se encarga de la limpieza y preprocesamiento de los datos extraídos.
- Carga los datos desde el archivo generado por
b_scraper.py
. - Aplica transformaciones y limpieza de columnas.
- Convierte valores numéricos y normaliza la estructura.
- Guarda los datos procesados en un nuevo archivo de salida.
El script se compone de las siguientes funciones:
Función | Descripción |
---|---|
read_files() |
Lee archivos Excel o CSV y los carga en un DataFrame. |
split_column() |
Divide las columnas (ENCABEZADOS_BASE ) en múltiples columnas según un delimitador definido en el diccionario CLEANING_CONFIGS . |
numeric_columns() |
Convierte columnas con valores numéricos eliminando caracteres no válidos (omite ENCABEZADOS_BASE ). |
save_data() |
Guarda el DataFrame procesado en un archivo Excel. |
main() |
Función principal que ejecuta la secuencia de limpieza y almacenamiento de datos. |
En la terminal CMD dentro del directorio del proyecto, ejecutar:
.venvWS\Scripts\activate
Los valores predeterminados no requieren modificaciones, excepto YEARS
, que debe modificarse según los años de interés para la extracción de datos.
-
Abrir el
a_config.py
. -
Definir el rango de años.
YEARS = list(range(2024, 2026))
Como resultado definirá los años 2024-2025 para el scraping (al definir un rango Python no incluye el rango superior).
- Guardar los cambios y cerrar
a_config.py
.
- Para iniciar el scraper ejecutar el siguiente comando en la terminal CMD dentro del directorio del proyecto:
python 02_src\b_scraper.py
- Le mostrará la lista de rutas de navegación disponible. Debe elegir una ruta introduciendo el número.
--- Rutas disponibles ---
1: MUNICIPALIDADES
2: SECTORES
Elige una ruta (número):
- Una vez finalice correctamente saldrá el siguiente mensaje.
✅ Proceso finalizado, driver cerrado.
Ejecuta la secuencia de limpieza y preprocesamiento de la data obtenida por b_scraper.py
.
- En la misma terminar de CMD ejecutar:
python 02_src\c_cleaner.py
- Ejecutará la limpieza de todos los archivos existentes basándose en la configuración definida en
a_config.py
.
Procesando data: MUNICIPALIDADES
- La data procesada se guarda en
01_data\02_processed\
con el prefijoPROCESADO_...
Caution
Esta configuración requiere de nociones sobre inspección HTML y uso de XPath para definir correctamente los botones y las rutas.
El diccionario ROUTES
en a_config.py
define las rutas de navegación para el scraper.
Estructura de una Ruta
Dentro ROUTES
el primer elemento es el nombre de la ruta, seguido de levels
tiene un conjunto de niveles (level_1, level_2, ... level_n
). Cada nivel incluye:
Acción/Elemento | Descripción |
---|---|
button |
El XPath del botón para seleccionar un elemento de la web. |
list_xpath (opcional) |
XPath de la lista de elementos a iterar (si hay selección múltiple). |
name_xpath (opcional) |
XPath para extraer el nombre de cada elemento en la lista. |
table_id (solo en el último nivel) |
ID de la tabla de la que se extraerán datos. |
next_level |
Nombre del siguiente nivel o None si es el último. |
Agregar una Nueva Ruta
Para agregar una nueva ruta llamada "GOBIERNOS REGIONALES"
(ejemplo), que sigue una estructura similar a las otras rutas.
-
Abrir el archivo
02_src/a_config.py
. -
Ubicar el diccionario
ROUTES
. -
Agregar la nueva ruta dentro del diccionario, siguiendo la estructura de niveles.
ROUTES = {
# Ruta 1
"MUNICIPALIDADES": {
...
},
# Ruta 2
"SECTORES": {
...
},
# Ruta 3 (Nueva Ruta)
"GOBIERNOS REGIONALES": {
"levels": {
"level_1": { # Primer nivel
"button": "XPath",
"next_level": "level_2",
},
"level_2": { # Segundo nivel
"button": "XPath",
"next_level": "level_3",
},
"level_3": { # Tercer
"button": "XPath",
"next_level": "level_4",
},
"level_4": { # Último nivel
"button": "XPath",
"table_id": "XPath",
"next_level": None,
},
},
},
}
-
Guardar los cambios en
a_config.py
. -
Ejecutar el script
b_scraper.py
. -
Verificar que la nueva ruta aparece en la lista de selección.
--- Rutas disponibles ---
1: MUNICIPALIDADES
2: SECTORES
3: GOBIERNOS REGIONALES
Elige una ruta (número):
Este proyecto está licenciado bajo la Licencia MIT. Consulta el archivo LICENSE para más detalles.
Evanan, M. A. (2025). Web Scraping: Consulta Amigable MEF (v1.1.0). Zenodo. https://doi.org/10.5281/zenodo.14876920