Cree archivos PDF a partir de plantillas con Python y Scripts de Google
A menudo, es útil crear archivos PDF a partir de sus scripts de Python. Ya sea que esté creando facturas, cartas, informes o cualquier otro documento que contenga mucha repetición de formato pero solo un poco de contenido dinámico, agregar algo de automatización puede ahorrarle muchas horas.
Tiene algunas opciones para esto. Los habituales son:
- Utilice una biblioteca PDF como reportlab para generar archivos PDF directamente (p. ej. https://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/)
- Utilice una biblioteca de plantillas HTML como Jinja2 y convierta de HTML a PDF (por ejemplo, consulte http://pbpython.com/pdf-reports.html)
- Utilice una API de terceros como https://pdfgeneratorapi.com/.
Para la opción 1, generar archivos PDF directamente desde Python puede hacer que el formato sea muy difícil. Tienes que dibujar todo lo que necesites elemento por elemento, usando código, e incluso una vez que tienes una plantilla que se ve como la quieres, es difícil de mantener.
La opción 2 a menudo puede funcionar mejor, pero aún tiene que construir el código HTML de Jinja, y a veces la conversión de HTML a PDF no sale como esperaba.
La opción 3 requiere que construya la plantilla primero utilizando la interfaz web de un servicio en línea. Aunque tienes una interfaz de arrastrar y soltar, es bastante torpe y difícil hacer que tu plantilla se vea como quieras. Por lo general, también tiene que pagar para usar el servicio.
Si bien una de las opciones anteriores puede funcionar para usted, si no le gusta ninguna de ellas, también puede hackear una API de generación de documentos basada en Google Drive. Obtendrás una API gratuita y podrás usar Google Docs como herramienta de plantillas, que es bastante potente y tiene muchas plantillas preexistentes para cosas como facturas, cartas y CV.
Empecé con una plantilla de factura que encontré en línea. Se parece a esto:
En este tutorial, explicaremos cómo crear una API que genere estas facturas y le permita insertar mediante programación el número de factura desde un script Python externo. En realidad, tendría que hacer lo mismo para muchos de los otros campos, pero comenzaremos con un ejemplo simple por razones de demostración.
Escribiremos algunas líneas de código de script de Google App y algunas líneas de código Python.
Crear una plantilla de documento
Utilice una de las plantillas de documentos integradas de Google, busque en línea una que se ajuste a sus necesidades o cree la suya propia en docs.google.com. (Necesitarás una cuenta de Google).
Agregue marcadores de posición donde necesite información dinámica. En el ejemplo a continuación, he agregado el NÚMERO DE FACTURA {invoice_id}
en lugar de la identificación» 456 » que tenía en el documento original. No hay nada especial en esta sintaxis using usaremos una función básica de búsqueda y reemplazo más adelante para cambiar esto por la información real, así que use algo que es poco probable que aparezca en el documento final.
Tome nota de su ID de documento, que es la parte resaltada en la barra de direcciones URL.
Configuración de un script personalizado de Google
Vaya a Google Drive, presione «Nuevo» en la esquina superior izquierda. En» Más», selecciona» Script de Google Apps «si está disponible o» Conectar más aplicaciones » si no lo ves.
Busque «script de aplicaciones» y elija conectarlo. Es posible que veas algunos mensajes de advertencia que te pregunten si confías en ti mismo. Di que sí.
Una vez que pueda crear un nuevo Script de aplicación, verá un script en blanco predeterminado que se ve de la siguiente manera.
Elimine el código que ve allí y reemplácelo con una función createDocument
que se vea de la siguiente manera.
function createDocument(invoice_id) { var TEMPLATE_ID = '1Ybq8r_SiWu4Z4-_Z6S0IW1L8FJywfpjPAATPCvvkKk8'; var documentId = DriveApp.getFileById(TEMPLATE_ID).makeCopy().getId(); drivedoc = DriveApp.getFileById(documentId); drivedoc.setName("Invoice " + invoice_id); doc = DocumentApp.openById(documentId); var body = doc.getBody(); body.replaceText('{invoice_id}', invoice_id); drivedoc.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT); return "https://docs.google.com/document/d/" + documentId + "/export?format=pdf";}
En la línea 2, cambie el TEMPLATE_ID
por el ID del documento que copió de la barra de direcciones URL de su documento de Google con plantilla.
Este código encuentra el documento con plantilla, crea una copia del mismo y establece el nombre del archivo en «Factura» más cualquier invoice_id
que pasemos. A continuación, abre el nuevo archivo a través de DocumentApp (en lugar de la aplicación Drive, para que podamos obtener el contenido del archivo y editarlo). Busca en el documento el marcador de posición que agregamos ({invoice_id}
) y lo reemplaza con el invoice_id
real que la función toma como entrada. A continuación, establece que el documento sea de acceso público y devuelve una URL que irá directamente a una exportación PDF para ese documento.
Debajo de esta función, agregue otra llamada doGet
. Mientras que la función anterior se puede nombrar cualquier cosa, doGet
es una función especial en los scripts de Google Apps, por lo que deberá nombrarla exactamente doGet
. Esta función se encargará de las solicitudes web entrantes después de que hayamos implementado nuestra aplicación.
El código para la función doGet
es el siguiente. Pegue esto debajo de la función anterior createDocument()
.
function doGet(e) { var invoice_id = e.parameter.invoice_id; var url = createDocument(invoice_id); return ContentService.createTextOutput(url);}
Esto toma el invoice_id como un parámetro de URL, lo pasa a nuestra función createDocument
que acabamos de escribir y devuelve la URL del documento creado como texto sin formato.
Publicación de nuestra API
En el menú» Publicar», seleccione «Implementar como aplicación web»
Se le pedirá que nombre el proyecto. Ponle un nombre como «API PDF» o cualquier otra cosa que quieras.
Verá un nuevo menú para establecer las opciones para implementar su aplicación web.
Agregue un mensaje como «implementación inicial» en donde dice » Nuevo «y elija» Cualquiera, incluso anónimo » en la configuración de acceso. Deje la configuración de ejecución como «Yo».
Advertencia: Si comparte el enlace en un lugar público, las personas pueden abusar del servicio y enviarlo spam con solicitudes automáticas. Google puede bloquear tu cuenta por abuso si esto sucede, así que mantén el enlace seguro.
Pulsa el botón Implementar y anota la URL que verás en la siguiente ventana emergente.
¿Agregar «?invoice_id = 1» hasta el final de la URL y visítela en su navegador. Debería verse algo como
https://script.google.com/macros/s/AKfycbxDiKpTGqMijZmU8-0cPj06DBFjDOPYZJ9IFvhcO111GCh8jqxC/exec?invoice_id=1
Si todo salió bien, deberías ver un enlace de Google Docs mostrado.
Si visita la URL, debe descargarse un PDF de la factura con el marcador de posición cambiado a 1
.
Actualización de la aplicación
Si ve un error en su lugar, o no recibe una respuesta, es probable que haya cometido un error en el código. Puede cambiarlo y actualizar la implementación de la misma manera que la implementó inicialmente. La pantalla de actualización solo es ligeramente diferente de la pantalla de implementación.
Lo único complicado es que debe seleccionar «Nuevo» como la versión para cada cambio que realice. Si realiza cambios en el código y actualiza una versión anterior, los cambios no surtirán efecto, lo que no es obvio en la interfaz de usuario. (Como pueden ver, me tomó varios intentos hacer esto bien.).
Crear nuestras facturas desde Python
Ahora podemos crear facturas y guardarlas localmente desde un script de Python. El siguiente código muestra cómo generar tres facturas en un bucle for
.
import requestsurl = "https://script.google.com/macros/s/AKfycbyYL5jhEstkuzZAmZjo0dUIyAmzUc1XL5B-01fHRHx8h63cieXc/exec?invoice_id={}"invoice_ids = for invoice_id in invoice_ids: print("processing ", invoice_id) response = requests.get(url.format(invoice_id)) print("file generated") response = requests.get(response.content) print("file downloaded") with open("invoice{}.pdf".format(invoice_id), "wb") as f: f.write(response.content)
Tenga en cuenta que el proceso de creación y descarga es bastante lento, por lo que tomará unos segundos cada factura que cree.
Probablemente haya notado que esta es una solución bastante «hackeada» para generar archivos PDF desde dentro de Python. La funcionalidad de «reemplazar» es bastante limitada en comparación con un lenguaje de plantillas adecuado, y el paso de datos a través de una solicitud get también tiene limitaciones. Si pasa por algo más complicado que un ID de factura, primero codificará la URL de los datos. Puede hacer esto en Python usando el módulo urllib.parse
. Un ejemplo de modificación del script Python para tratar datos más complicados es el siguiente.
import requestsimport urllib.parseurl = "https://script.google.com/macros/s/AKfycbyYL5jhEstkuzZAmZjo0dUIyAmzUc1XL5B-01fHRHx8h63cieXc/exec?"invoice_ids = for invoice_id in invoice_ids: print("processing ", invoice_id) payload = {"invoice_id": invoice_id} u = url + urllib.parse.urlencode(payload) response = requests.get(u) print("file generated") response = requests.get(response.content) print(response.content) print("file downloaded") with open("invoice{}.pdf".format(invoice_id), "wb") as f: f.write(response.content)
Pero todavía hay limitaciones de qué tipo de datos y cuánto puede pasar solo usando URL, por lo que tendría que modificar el script para usar solicitudes POST en su lugar si estuviera enviando muchos datos dinámicos.
También es bastante lento en comparación con algunos de los otros métodos que discutimos al principio, y Google tiene algunas limitaciones en la cantidad de archivos que puede crear automáticamente de esta manera.
Dicho esto, ser capaz de generar plantillas utilizando Google Docs puede ser rápido y potente, por lo que tendrás que evaluar las compensaciones por ti mismo.
También tenga en cuenta que este es un ejemplo bastante artificial, donde podríamos haber ejecutado el script Python desde el Ecosistema de Google, y evitar la necesidad de configurar una API pública que podría ser abusada si otras personas descubrieran la URL. Sin embargo, es posible que tenga una aplicación Python existente, no alojada en Google, que necesite conectarse con archivos PDF generados automáticamente, y este método aún le permite configurar un «microservicio» autónomo dentro del ecosistema de Google que permite una generación fácil de PDF.