Saltar al contenido principal
🇬🇧 English 🇧🇷 Português 🇩🇪 Deutsch
Convertidor de imágenes Convertidor de vídeo Convertidor de audio Convertidor de documentos
Herramientas Guías Formatos Precios API
Iniciar sesión
Guía

Convertir HTML a PDF con Python: WeasyPrint, pdfkit y Playwright

PC Por Pablo Cirre

Conversiones relacionadas

Pon en práctica lo que acabas de aprender — convierte tus archivos ahora en segundos, gratis y sin registro.

Preguntas frecuentes

Para facturas (HTML estático con CSS, sin JS), WeasyPrint es claramente superior: 5× más rápido por documento, ocupa 5× menos memoria, no requiere Chromium en el contenedor Docker (Docker image de ~150 MB vs ~600 MB), y soporta CSS Paged Media nativamente. Playwright tiene sentido cuando la factura usa gráficos generados por JavaScript (ej. Chart.js para gráfico de evolución de gastos) o cuando usas las mismas plantillas HTML que tu app web React/Vue. Para puro HTML+CSS, WeasyPrint gana en cada métrica.

pdfkit usa wkhtmltopdf, que está basado en WebKit de 2016 — antes de que flexbox fuera completo y de que CSS Grid llegara a los navegadores. Tu CSS moderno simplemente no se interpreta. Tres opciones: (1) reescribir el CSS sin flexbox/grid usando floats y display:table, (2) cambiar a WeasyPrint que sí soporta flexbox y grid, (3) cambiar a Playwright que usa Chromium actual. Si el HTML viene de tu app moderna, WeasyPrint o Playwright son la única salida razonable.

Usa CSS Paged Media en tu hoja de estilos: <code>@page { @top-center { content: "Página " counter(page) " de " counter(pages); } }</code>. Funciona también @top-left, @top-right, @bottom-* y @left-middle. La numeración total (counter(pages)) se calcula automáticamente. Para suprimir cabecera en la primera página: <code>@page :first { @top-center { content: none; } }</code>. Esto es CSS estándar W3C — tu HTML/CSS de impresión funciona idéntico que en navegador.

Sí, con cuidado. Cada Chromium consume ~300 MB RAM y tarda ~1s en arrancar, así que: (1) NO arranques un Chromium nuevo por cada request — mantén un browser pool, (2) usa async/await para concurrencia (sync_playwright bloquea), (3) limita el HTML que aceptas (sin javascript: URLs ni file:// para evitar SSRF), (4) renderiza en sandbox / contenedor con permisos mínimos, (5) timeout estricto (30s) para evitar páginas infinitas. Considera servicios SaaS como Browserless si tu volumen no justifica gestionar Chromium tú mismo.

Tres causas habituales: (1) <code>@font-face</code> apunta a una URL relativa que no resuelve cuando el HTML se renderiza desde string — usa rutas absolutas (file://) o un <code>base_url</code> en WeasyPrint, (2) la fuente no está instalada en el sistema y el motor solo ve fuentes del sistema (en Docker, instala las fuentes en el container), (3) en Playwright, la fuente debe estar accesible cuando el navegador la pide — usa <code>data: URI</code> en la regla @font-face para evitar problemas de carga. Embedir Google Fonts: descárgalas localmente y sirvelas via base64, no confíes en CDN remoto desde un proceso server-side.

No realmente — wkhtmltopdf produce PDFs visualmente correctos pero sin estructura semántica accesible. Los lectores de pantalla no encuentran headings, tablas o landmarks. WeasyPrint genera PDFs con tags semánticos básicos (no certificados PDF/UA pero mejor que pdfkit). Para PDF/UA conforme con WCAG, ninguna librería Python actual basta — necesitas postprocessing con Adobe Acrobat Pro, PAC 2024, o un pipeline especializado. Si la accesibilidad es requisito legal (sector público europeo, sanidad EE.UU.), planifica una etapa adicional de tagging manual.

Usamos cookies y tecnologías similares para personalizar contenido y anuncios, y para analizar el tráfico. Más información sobre cookies.