← PORTAFOLIOPORTFOLIO / proyectos / cufe-dian

// PRJ_008 · 2024

CUFE Scraper DIANCUFE DIAN Scraper

Automatización fiscal · PythonTax automation · Python

Consultar facturas electrónicas en la DIAN una por una era lento. Este servicio lo hace en lote y guarda los resultados.Looking up e-invoices on the DIAN site one by one was slow. This service does it in bulk and stores the results.

En detalleIn detailServicio Flask + Selenium que automatiza la consulta masiva de CUFEs en el catálogo DIAN. Extrae datos de emisor, receptor y eventos; los persiste en MySQL vía REST API. Dockerizado, con tests (pytest) y CI en GitHub Actions.Flask + Selenium service that automates bulk CUFE lookups in the DIAN catalog. Extracts issuer, receiver and event data; persists it in MySQL via REST API. Dockerized, with tests (pytest) and CI on GitHub Actions.

RolRole
Desarrollador a cargoLead developer
AñoYear
2024
GitHub
ver repo ↗view repo ↗
Stack
Python · Flask · Selenium

// IMPACTO// IMPACT

REST APIREST API
interfazinterface
DIANDIAN
fuentesource
DockerDocker
runtimeruntime

El problemaThe problem

Consultar el portal DIAN manualmente es lento, repetitivo y propenso a errores. Necesitaba un servicio que recibiera un array de CUFEs y devolviera la información estructurada sin intervención humana.Manually querying the DIAN portal is slow, repetitive and error-prone. I needed a service that receives an array of CUFEs and returns structured data without human intervention.

Cómo lo resolvíHow I solved it

Construí un servicio Flask con Selenium que automatiza la navegación en el catálogo DIAN. Recibe CUFEs vía POST, extrae emisor, receptor, eventos y enlace a representación gráfica, y guarda todo en MySQL.Built a Flask service with Selenium that automates navigation in the DIAN catalog. Receives CUFEs via POST, extracts issuer, receiver, events and graphic representation link, and saves everything in MySQL.

Arquitectura y stackArchitecture & stack

  1. [01]Array CUFEs
  2. [02]Flask API
  3. [03]Selenium
  4. [04]Portal DIAN
  5. [05]MySQL
  • Python
  • Flask
  • Selenium
  • MySQL
  • Docker
# routes.py — endpoint principal
@app.route('/api/v1/consult_invoice_information', methods=['POST'])
def consult_invoice():
    cufes = request.json.get('cufes', [])
    results = []
    for cufe in cufes:
        data = scraper.query(cufe)
        db.save(data)
        results.append(data)
    return jsonify(results)

Lo que aprendíWhat I learned

01 //

Selenium frágil

El scraping depende del DOM. Un cambio en el portal rompe todo. Tests de regresión son clave.

02 //

Rate limiting

El portal DIAN tiene límites. Delays entre requests salvan el servicio.

03 //

Docker primero

Containerizar desde el día 1 evita el 'funciona en mi máquina'.

01 //

Selenium is fragile

Scraping depends on the DOM. A portal change breaks everything. Regression tests are key.

02 //

Rate limiting

The DIAN portal has limits. Delays between requests save the service.

03 //

Docker first

Containerizing from day 1 avoids 'works on my machine'.