Usar el API v2 de estadística desde Python y R
En el post anterior hablamos de las mejoras que trae el API V2 de las estadísticas del sistema financiero dominicano. Hoy vamos a hablar sobre cómo integrar estas mejoras en dos lenguajes muy utilizados en la ciencia de datos.
Contenido
· Introducción
· Consumir el API V2 desde Python.
· Consumir el API V2 desde R.
· Conclusiones
Introducción
Antes de iniciar, debemos entender el concepto central de esta mejora, el cual consiste en la paginación.
Un API paginado devuelve la información en pequeñas partes o páginas en lugar de entregar toda la información en una sola respuesta (como ocurre en el API que tenemos actualmente). El usuario debe especificar el número de página y el tamaño de página que desea recuperar, y se devuelve la página solicitada con información adicional sobre el número total de elementos y páginas disponibles. Esto es beneficioso para manejar grandes conjuntos de datos de manera eficiente y manejable en pequeñas partes.
Según la definición anterior, ahora en cada petición recibiremos unos metadatos que nos guiarán a través del proceso para obtener la información. Estos metadatos serán parte del encabezado (header) de la respuesta. A continuación, enumeramos estos metadatos:
x-pagination: [JSON] Es el nombre del atributo del encabezado (header) que contiene los metadatos.
CurrentPage: [Entero] Es el atributo que nos informa en que página nos encontramos.
RequestRecords: [Entero] Nos informa del número de páginas que hemos especificado en la consulta.
RecordsResponse: [Entero] Nos indica el número de página que ha traído la petición.
HasPrevious: [Booleano] Nos indica si hay paginas anteriores a la que estamos consultando.
HasNext: [Booleano] Nos indica si hay páginas posteriores a la que estamos consultando.
TotalRecords: [Entero] Nos indica el total de registro en la consulta.
TotalPages: [Entero] Nos indica el total de páginas en la consulta.
Ahora que comprendemos los cambios en el API V2, vamos a mostrar un ejemplo de cómo consultarlo utilizando estos dos lenguajes.
Consumir el API V2 desde Python.
#requirements.txt
#pandas==1.5.3
#requests==2.32.3
#python-dotenv==1.0.1
import json
import os
from urllib.parse import urlencode, urljoin
from dotenv import load_dotenv
import pandas as pd
import requests
load_dotenv()
headers:dict = {
'Ocp-Apim-Subscription-Key': os.getenv('API_KEY_DATOS_FINANCIEROS'), #Sustituir con tu API Key
'User-Agent': (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/111.0.0.0 Safari/537.36"
),
}
base_url:str = 'https://apis.sb.gob.do/estadisticas/v2/'
def obtener_datos_financieros_rd(end_point: str, params:dict) -> pd.DataFrame:
"""
Obtiene datos financieros desde una API REST y devuelve un DataFrame de pandas.
Esta función realiza múltiples solicitudes a un endpoint de la API de
datos públicos de la Superintendencia de Bancos de la República Dominicana
para recuperar datos financieros, paginando a través de los resultados.
Los datos se recopilan en un DataFrame de pandas que se devuelve al finalizar.
Parámetros
----------
end_point : str
El endpoint de la API que se utilizará para la solicitud de datos.
params : str
Filtros a ser aplicados en la petición al endpoint
Returns
-------
pd.DataFrame
Un DataFrame de pandas que contiene los datos financieros obtenidos
del API.
Raises
------
requests.HTTPError
Si la respuesta de la API indica un error HTTP.
json.JSONDecodeError
Si la respuesta JSON no puede ser decodificada correctamente.
Exception
Si ocurre un error inesperado durante el proceso de obtención de datos.
Ejemplo
------
obtener_datos_financieros_rd('indicadores/morosidad-estresada','2024-01','2024-04')
Notes
-----
- La función gestiona la paginación automáticamente, asegurándose de que
se recuperen todos los registros disponibles en el rango de fechas especificado.
- Se asume que la respuesta de la API incluye un encabezado `x-pagination`
con metadatos que indican si hay más páginas de datos disponibles.
- Es necesario tener la biblioteca `requests` y `pandas` instaladas en el entorno
donde se ejecute esta función.
"""
next_page = True
registros_list: list[pd.DataFrame] = []
while next_page:
# Construir la URL final
url = urljoin(base_url, end_point) + '?' + urlencode(params)
#https://apis.sb.gob.do/estadisticas/v2/indicadores/financieros?periodoInicial=2022-01&periodoFinal=2022-02&tipoEntidad=BM&paginas=1®istros=50000
try:
# Hacemos la petición
response = requests.get(url, headers=headers)
# El método raise_for_status() es una función de la biblioteca requests
# que se utiliza para verificar si la solicitud fue exitosa
#Códigos de Éxito desde 200 hasta 299
#Códigos de Error: desde Si el código de estado es 4xx o 5xx
#(por ejemplo, 404 Not Found, 500 Internal Server Error)
response.raise_for_status()
# Parseamos la respuesta con los datos a JSON
datos = response.json()
# Agregamos los datos a una lista conformada por DataFrames de pandas
registros_list.append(pd.DataFrame(datos))
# Obtenemos los metadatos necesarios de la respuesta
metadatos = json.loads(response.headers['x-pagination'])
next_page = metadatos['HasNext']
total_pages = metadatos['TotalPages']
total_record = metadatos["TotalRecords"]
# Imprimimos la página actual y el total de páginas
print('Página:', params['paginas'], '/', total_pages)
# Incrementamos 1 para ir a la siguiente página
params['paginas'] += 1
except requests.HTTPError as http_err:
print("Error en la petición HTTP:", http_err)
raise
except json.JSONDecodeError as json_err:
print("Error al decodificar la respuesta JSON:", json_err)
raise
except Exception as e:
print("Ha ocurrido un error:", e)
raise
# Concatenamos la lista de DataFrames en uno solo
registros_finales = pd.concat(registros_list, ignore_index=True)
return registros_finales
params = dict(
periodoInicial = "2022-01", # Fecha Inicial
periodoFinal = "2022-02",
tipoEntidad = "BM",
paginas = 1,
registros = 1000,
)
indicadores_financiero = obtener_datos_financieros_rd('indicadores/financieros',params)
indicadores_financiero.head()
Consumir el API V2 desde R.
# Importar librerias necesarias
library(httr)
library(jsonlite)
library(dplyr)
library(dotenv)
# Cargar la clave API desde un archivo .env
# Nota: Este script asume que posees un archivo .env con las credenciales de tu API. Esto es por motivos de
# seguridad de tu clave privada. Sin embargo, puedes modificar el codigo facilmente si quieres introducir directamente
# la clave en el script.
dotenv::load_dot_env()
api_key <- Sys.getenv("API_KEY_DATOS_FINANCIEROS") #Sustituir con tu API Key
# Establecer headers para el request
headers <- add_headers(
'Ocp-Apim-Subscription-Key' = api_key,
'User-Agent' = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
)
# Establecer la URL base (o raiz) a partir de la cual se construyen los endpoints y las diferentes consultas
base_url <- "https://apis.sb.gob.do/estadisticas/v2/"
# Definimos la funcion para consultar los datos
obtener_datos_financieros_rd <- function(end_point, params) {
############################### DOC STRING #####################################
# Obtiene datos financieros desde una API REST y devuelve un DataFrame de pandas.
#
# Esta función realiza múltiples solicitudes a un endpoint de la API de
# datos públicos de la Superintendencia de Bancos de la República Dominicana
# para recuperar datos financieros, paginando a través de los resultados.
# Los datos se recopilan en un DataFrame de pandas que se devuelve al finalizar.
#
# Parámetros
# ----------
# end_point : str
# El endpoint de la API que se utilizará para la solicitud de datos.
#
# params : str
# Filtros a ser aplicados en la petición al endpoint
#
# Returns
# -------
# data.frame
# Un DataFrame que contiene los datos financieros obtenidos
# del API.
#
#
# Ejemplo de uso
# ------
# params <- list(
# periodoInicial = "2022-01", # Fecha Inicial
# periodoFinal = "2022-02",
# tipoEntidad = "BM",
# paginas = 1,
# registros = 150
# )
# obtener_datos_financieros_rd('indicadores/morosidad-estresada',params)
#
# Notes
# -----
# - La función gestiona la paginación automáticamente, asegurándose de que
# se recuperen todos los registros disponibles en el rango de fechas especificado.
# - Se asume que la respuesta de la API incluye un encabezado `x-pagination`
# con metadatos que indican si hay más páginas de datos disponibles.
##################################################################################
next_page <- TRUE
registros_list <- list()
while (next_page) {
# Concatenar la base de URL con el endpoint especificado
url <- paste0(base_url, end_point)
# Añadir los parámetros de consulta
url <- modify_url(url, query = params)
tryCatch({
# Hacer la solicitud
response <- GET(url, headers)
# Verificar si la solicitud fue exitosa
stop_for_status(response)
# Parsear la respuesta JSON
datos <- fromJSON(content(response, "text"), flatten = TRUE)
# Agregar los datos a una lista de DataFrames
registros_list <- append(registros_list, list(as.data.frame(datos)))
# Obtener metadatos de la respuesta
metadatos <- fromJSON(response$headers[['x-pagination']])
next_page <- metadatos$HasNext
total_pages <- metadatos$TotalPages
total_record <- metadatos$TotalRecords
# Imprimir la página actual y el total de páginas
print(paste('Página:', params['paginas'], '/', total_pages))
# Incrementar 1 para la siguiente página
params['paginas'] <- as.numeric(params['paginas']) + 1
}, error = function(e) {
print(paste("Ha ocurrido un error:", e))
stop(e$message)
# next_page <- FALSE
})
}
# Combinar los registros en un solo DataFrame
registros_finales <- bind_rows(registros_list)
return(registros_finales)
}
# Definir los parámetros
params <- list(
periodoInicial = "2022-01", # Fecha Inicial
periodoFinal = "2022-02",
tipoEntidad = "BM",
paginas = 1,
registros = 100
)
# Llamar a la función
resultados <- obtener_datos_financieros_rd("indicadores/financieros", params)
# Guardar datos en .csv
write.csv(resultados, "consulta_api.csv", row.names = FALSE)
print(resultados)
Conclusiones
El código expuesto anteriormente es informativo y puede ser modificado, optimizado y compartido.
Para tener un mayor entendimiento de los códigos HTTP recomendamos la siguiente lectura: HTTP response status codes — HTTP | MDN (mozilla.org).