openpyxl / python-docx / reportlab
Tres bibliotecas cubren la mayor parte de la automatización de documentos en Python: openpyxl para Excel, python-docx para Word y reportlab para la generación de PDF, comunes en flujos de trabajo de informes, exportaciones y cumplimiento.
Receta
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.title = "Summary"
ws.append(["sku", "qty", "revenue"])
ws.append(["ABC", 10, 199.90])
wb.save("report.xlsx")Cuándo usar esto:
- Exportar resultados de consultas a Excel para finanzas/operaciones
- Documentos de Word estilo combinación de correspondencia a partir de datos de CRM
- Facturas, albaranes y certificados en formato PDF
- Tareas programadas de informes en Celery/cron
Ejemplo de Trabajo
from __future__ import annotations
from datetime import datetime, timezone
from io import BytesIO
from openpyxl import Workbook
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
def build_sales_xlsx(rows: list[tuple[str, int, float]]) -> bytes:
wb = Workbook()
ws = wb.active
ws.title = "Sales"
ws.append(["product", "units", "revenue"])
for product, units, revenue in rows:
ws.append([product, units, revenue])
buf = BytesIO()
wb.save(buf)
return buf.getvalue()
def build_invoice_pdf(invoice_id: str, total: float) -> bytes:
buf = BytesIO()
c = canvas.Canvas(buf, pagesize=letter)
c.setFont("Helvetica", 12)
c.drawString(72, 720, f"Invoice {invoice_id}")
c.drawString(72, 700, f"Total: ${total:,.2f}")
c.drawString(72, 680, datetime.now(timezone.utc).isoformat())
c.showPage()
c.save()
return buf.getvalue()
if __name__ == "__main__":
xlsx = build_sales_xlsx([("widget", 3, 59.97)])
pdf = build_invoice_pdf("INV-1001", 59.97)
print(len(xlsx), len(pdf))Lo que esto demuestra:
- Libros de trabajo en memoria a través de
BytesIOpara respuestas HTTP - xlsx tabular simple sin la sobrecarga de pandas
- PDF mínimo con la API de lienzo de reportlab
- Marca de tiempo UTC en el PDF para pista de auditoría
Inmersión Profunda
Cómo Funciona
- openpyxl - OOXML xlsx;
load_workbookpara ediciones;data_only=Truelee los valores de fórmula cacheados. - python-docx - Manipula WordprocessingML; párrafos, tablas, estilos; fusión de plantillas reemplazando marcadores.
- reportlab - Lienzo PDF de bajo nivel más Platypus flowables para diseños complejos.
Selector de Bibliotecas
| Salida | Biblioteca | Notas |
|---|---|---|
| exportación xlsx | openpyxl | O to_excel de pandas (usa openpyxl/xlsxwriter) |
| Memo de Word | python-docx | Mantén la plantilla .docx en el repositorio |
| Factura PDF | reportlab | O WeasyPrint desde HTML si el equipo conoce CSS |
| PDF desde Word | docx2pdf (Win/Mac) | No para servidores Linux |
Notas de Python
from docx import Document
doc = Document("template.docx")
for p in doc.paragraphs:
if "{{NAME}}" in p.text:
p.text = p.text.replace("{{NAME}}", "Ada Lovelace")
buf = BytesIO()
doc.save(buf)Trampas
- Cargar xlsx no confiable - Existen variantes de bombas XML y billion-laughs. Solución: límites de tamaño, escaneo de virus, análisis en un worker aislado.
- Fórmulas vs valores -
load_workbookdevuelve fórmulas por defecto. Solución:data_only=Truepara valores mostrados (obsoleto hasta que Excel se abra). - Características no soportadas por python-docx - Las cabeceras/pies de página en plantillas complejas pueden fallar. Solución: simplificar la plantilla o usar plantillas docx mantenidas en Word.
- Licenciamiento de fuentes de reportlab - Incrusta solo fuentes licenciadas para PDFs comerciales. Solución: usa Helvetica incorporada o TTF licenciada.
- Memoria en exportaciones enormes - Crear un xlsx de un millón de filas en RAM causa OOM. Solución: CSV para datos grandes, o escrituras fragmentadas en modo
write_only=True. - Localización y fechas en Excel - Excel muestra formato local; almacena ISO en los datos de origen. Solución: formatos numéricos explícitos en openpyxl.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
pandas to_excel | DataFrame ya en memoria | Exportación simple de 3 columnas (openpyxl es más ligero) |
| WeasyPrint / wkhtmltopdf | El equipo prefiere diseños HTML/CSS | Dependencias mínimas en servidores restringidos |
| API de Google Sheets | Hojas en vivo colaborativas | Informes offline/air-gapped |
| LaTeX | Calidad científica de PDF | Usuarios de negocio editan plantillas en Word |
Preguntas Frecuentes
¿openpyxl o xlsxwriter?
openpyxl lee y escribe; xlsxwriter es solo escritura con formato enriquecido - elige según la necesidad de lectura.
¿Cómo devuelvo xlsx desde FastAPI?
Response(content=bytes, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") con cabecera de adjunto Content-Disposition.
¿Puede python-docx insertar imágenes?
Sí - document.add_picture(path, width=Inches(2)) para logotipos en documentos generados.
¿Cómo añado tablas en Word?
table = doc.add_table(rows=1, cols=3) luego rellena las celdas - estiliza con los estilos de tabla incorporados.
¿reportlab vs ReportBro?
reportlab es primero código; ReportBro es interfaz de diseñador - elige según quién mantenga los diseños.
¿Excel protegido con contraseña?
openpyxl tiene soporte limitado - descifra antes de cargar o rechaza cargas cifradas.
¿Cómo hago pruebas unitarias de la salida PDF?
Afirma que el PDF comienza con %PDF y contiene el texto esperado extraído a través de pypdf en las pruebas.
¿xlsm habilitado para macros?
Evita el lado del servidor - las macros son un riesgo de seguridad; acepta solo xlsx.
¿Unicode en PDF?
Registra una TTF que cubra tu conjunto de glifos - Helvetica incorporada carece de CJK.
¿Tarea de Celery generando informes?
Escribe en almacenamiento de objetos (S3) y devuelve una URL firmada - no adjuntos de correo electrónico de varios MB.
Relacionado
- Fundamentos de pandas - DataFrame a Excel
- celery - generación de informes asíncrona
- S3 - almacenamiento de documentos generados
- pendulum / arrow - fechas en informes
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.