// 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.
// IMPACTO// IMPACT
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
- [01]Array CUFEs
- [02]Flask API
- [03]Selenium
- [04]Portal DIAN
- [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'.