Publicado el 1 comentario

EXTRAER DATOS DE FACTURA XML (formato del SRI EC) USANDO PYTHON

Estoy creando un flujo de trabajo semiautomatizado para el control de gastos e ingresos. Así que lo primero fue establecer las tecnologías ha utilizar.

El presupuesto que establecí es de cero dólares ($0). Y la idea es tener un núcleo tecnológico desde el nacimiento de la empresa. Y pues si te lo preguntas, tener un núcleo tecnológico en tu empresa no significa pagar licencias o instalar software pirata. Significa que tu equipo sea capaz de generar soluciones con los recursos a tu alcance.

Nos decidimos por Python, ya que podemos tener el prototipo de una aplicación básica en poco tiempo. Y con jupyter notebooks, es prácticamente como tener una hoja de cálculo en Excel.

El código este tutorial simple, lo puedes encontrar en nuestro repositorio de github:

Para poder realizar este ejercicio vamos a necesitar importar las siguientes librerías, por comodidad de este tutorial usaremos un notebook.

#librerias a utilizar
#libreria parse XML
import xml.etree.ElementTree as ET
#expresiones regulares
import re
#pandas para dataframes
import pandas as pd
#acceder a path de directorios locales
import os

La librería xml.etree.ElementTree en específico nos ofrece métodos muy sencillos para poder extraer los datos de los nodos de un XML, e incluso soporta búsquedas xpath.

Empecemos por descargar uno de los archivos XML de la página del SRI, en mi caso una de las facturas recibidas por compras:

Una vez que tienes tu archivo de ejemplo, investiguemos un poco la estructura del XML. Puedes abrir el archivo en un editor de texto de tu pre­­­­­­­­ferencia.

xml de factura descargada del SRI

De este apartado nos interesa verificar las etiquetas o nodos existentes en el archivo. Entonces toda la etiqueta <?xml encierra el contenido que deseo obtener. Si continuo hacia abajo el siguiente nivel es <autorizacion>.

Si estas viendo el archivo en este momento, ya habras notado la similitud con un HTML (no es lo mismo), las etiquetas tienen tanto una apertura como un cierre, <apertura>  </cierre>.

Dicho esto, podemos notar que la etiqueta <autorizacion> tiene una apertura y le siguen las etiquetas de:

<estado>AUTORIZADO</estado>

<numeroAutorizacion>2502202221179004027500120</numeroAutorizacion>

<fechaAutorizacion>2021-03-24T10:34:45-05:00</fechaAutorizacion>

<ambiente>PRODUCCIÓN</ambiente>

<comprobante>

Hacemos un nuevo stop, al llegar a la etiqueta <comprobante> que también aparece como una apertura, el cierre de la misma esta en parte inferior y nos hace entender que esta etiqueta contiene todos los datos resaltados en amarillos. Estos son los datos que requiero para los informes, para estructurarlos y para la aplicación que tenemos en mente.

Para este momento ya tengo el notebook con las librerías a utilizar, y abierto el archivo de ejemplo:

Obtengo el listado de ejemplo usando la librería os, para obtener todos los archivos del directorio actual. Como el objeto que me devuelve este método es una lista, puedo seleccionar uno de ellos usando notación de corchetes[].

El siguiente paso como puedes ver en la imagen es obtener el XML del archivo, esto lo realizas pasándole a la función ET.parse() la factura, seguidamente de la función .getroot() que devuelve la raíz o por decirlo de alguna manera la etiqueta que abarca a todas las demás etiquetas que estamos investigando.

Si usas type para ver de que clase de objeto se trata obtienes el siguiente resultado:

type(root)
output: xml.etree.ElementTree.Element

Para acceder al contenido debo iterar sobre la variable root, con un ciclo for, los métodos que vamos utilizar .tag, .attrib y .text que viene de la librería ET.

.tag: devuelve el nombre de la etiquetas por ejemplo autorización, estado etc.

.attrib: devuelve los valores que contiene una etiqueta lo veremos mejor en el ejemplo

.text: devuelve el contenido en tipo str que contiene una etiqueta

#verificar las etiquetas child de root
for i in root:
    print(i.tag,":", i.attrib)

output:
estado : {}
numeroAutorizacion : {}
fechaAutorizacion : {}
ambiente : {}
comprobante : {}
mensajes : {}

Ten en mente que el objeto root es un diccionario, y los keys de este diccionario son los valores que estás obteniendo con la iteración. En este caso nos interesa el comprobante : {} al tratar de obtener los atributos o contenido nos devuelve un diccionario vació. Esto significa que dentro de estas etiquetas ya no existen sub-niveles o mas árboles de datos del XML. Pero esto no es verdad porque ya vimos que dentro de comprobante está toda la información de la factura. Para tener más claro el panorama envés de .attrib usamos .text y el resultado es el siguiente:

Si te fijaste, en el inicio de la investigación del archivo notaste que toda la información resaltada en amarillo esta encerrada en un <![CDATA[ no voy entrar en detalles de esto, pero llévate en la mente que todo lo que está encerrado en CDATA ahora es un texto plano.

Es decir que nuestra iteración es correcta, ya no existe un atributo en comprobante : {} lo que contiene ya es solo un texto.

Entonces para seguir usando la librería de ET, debemos abrir este string como un XML, y pues la misma librería de ET nos ofrece un método, este es ET.fromstring

#usando el metodo de fromstring abres el texto como XML
xml_comprobante=ET.fromstring(comprobante)
xml_comprobante

output:
<Element 'factura' at 0x000001C0BF278E50>

Ahora nuevamente tenemos un árbol de XML, que tiene la etiqueta ‘factura’. Podemos iterar sobre esta etiquetas y recolectar los datos de tag y los texto que contiene, en este caso debemos iterar un nivel mas bajo para ir sacando los contenidos que nos interesa.

Declaras un diccionario vacío para ir llenándolo con los datos, y a partir de este diccionario ya se puede construir un dataframe, para entregarlo a tus herramientas de análisis.

Por último generamos dos funciones para organizar el trabajo que hemos levantado. La primera función se va encargar de obtener el texto de comprobante, y devolver los datos al diccionario, y la otra nos va ayudar a la ingesta de las facturas que tenemos listadas.

Nos resta crear un bucle que acumule los valores que me van a devolver las funciones y generar un DataFrame con los datos de los diccionarios que obtengo de mis dos facturas ejemplo.

#usando las funciones para obtener datos
#facturas seleccionadas 
data_df=[]
for i in range(len(facturas)):
    textos=parser(facturas[i])
    data_df.append(obtener_dato(textos))

Con el resultado de data_df tenemos los datos para generar un dataframe. Así de sencillo obtuvimos los datos del archivo XML usando Python. La lógica aplicada para obtener datos de la etiqueta factura se puede replicar para investigar adicional a los datos que obtenemos, por ejemplo los detalles de cada ítem comprado, con su costo unitario, o el valor de impuesto que esta dentro de la etiqueta impuestos.

Si deseas estar pendiente de mis publicaciones, tutoriales o próximos lanzamientos de cursos de análisis de datos, te invito cordialmente a suscribirte.

Publicado el 1 comentario

Google Colab para Principiantes: Abrir archivos, gráficos, importar módulos

Escribo este post porque me hubiese gustado encontrar algo así cuando empecé a estudiar Python y análisis de datos.

Google Colab se ha convertido en mi caso en una herramienta super importante para el trabajo y para mi continuo aprendizaje basado en prueba y error. Tiene casi todas las librerías que podrías usar, y además cuenta con una ejecución por GPU y lo mejor de todo es gratis (hasta cierto límite) .

Google Colab

Para ingresar en un nuevo notebook es sencillo, puedes ir directamente con este link : https://colab.research.google.com

Primero es lo primero, cómo abrir un archivo desde tu servicio de Google Drive. Lo que vamos hacer con el siguiente código es darle permisos a Colab para que pueda tener acceso al directorio de Google Drive. Copia el siguiente código en el notebook que tengas abierto. Y ejecútalo con el comando CRTL + ENTER.

from google.colab import drive
drive.mount('/content/drive')

Una vez que lo ejecutes te pedirá ingresar un código de autorización, para obtenerlo ve al link que se muestra. Lo que hace es conceder permisos a Colab para usar Google Drive, por lo que deberás iniciar sesión en Drive, y copiar el código que se mostrara.

Para verificar que se ha completado, dirígete a la parte izquierda de la pantalla como se muestra en la imagen, y selecciona el icono de carpeta, ahí aparecerá la carpeta de Google Drive.

Ahora comprueba que tienes acceso usando pandas para abrir un archivo CSV, para que no tengas que preocuparte por el path de los archivos que requieres, basta como ubicar en la carpeta el archivo que necesitas, dar clic derecho y seleccionar la opción copiar dirección del archivo.

Listo ya tienes accesos tus set de datos guardados en la nube de manera sencilla y segura.

Importar módulos entre notebooks

Importar módulos es crucial a la hora de trabajar con notebooks, si un proyecto crece lo suficiente es una buena practica generar varias notebooks, en cada uno puedes ir desarrollando el código especifico que requieres para el análisis. Por ello es necesario tener la capacidad de importar funciones de otros notebooks.

Bueno si has trabajado en Jupyter Notebook, el siguiente código te será familiar, en este caso puedes referenciar módulos que están en Google drive con extensión ‘py’ o ‘ipynb’. Con el comando %run ‘ruta_del_archivo’ como leíste en el apartado anterior, debes primero tener accesos a Google Drive, ubica el archivo que deseas referencia o importar para usar las funciones que hayas desarrollado, copia la ruta y listo. Ya tienes tu modulo importado.

%run '/content/drive/My Drive/Colab Notebooks/PDE_VarianDesvStd.ipynb'

Gráficos en Google Colab

Si te estabas preguntando si puedes realizar gráficos en Colab, pues la respuesta es un rotundo sí. Puedes importar directamente las librerías más populares para realizar gráficos. En el siguiente ejemplo usaremos matplotlib.

import matplotlib.pyplot as plt

Ahora ya puedes empezar a practicar creando tus módulos y usándolos en análisis de tus archivos csv, json, Excel, o desde servicios de la nube. El potencial de esta herramienta es genial, te la recomiendo.

Si te gustó este post te invito a que te suscribas de esa forma recibirás alertas sobre entradas de este tipo y más.

La bondad es la única inversión que nunca falla.

H.D. Thoreau