Crea file PDF da modelli con Python e Google Scripts

Spesso, è utile creare file PDF dai tuoi script Python. Sia che tu stia creando fatture, lettere, rapporti o altri documenti che contengono molte ripetizioni di formattazione ma solo un po ‘di contenuto dinamico, l’aggiunta di un po’ di automazione può farti risparmiare molte ore.

Hai alcune opzioni per questo. I soliti sono:

  1. Utilizzare una libreria PDF come reportlab per generare direttamente i file PDF (ad es. https://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/)
  2. Utilizzare una libreria di template HTML come Jinja2 e convertire da HTML a PDF (ad esempio, vedere http://pbpython.com/pdf-reports.html)
  3. Utilizzare un’API di terze parti come https://pdfgeneratorapi.com/.

Per l’opzione 1, la generazione di PDF direttamente dall’interno di Python può rendere la formattazione molto difficile. Devi disegnare tutto ciò di cui hai bisogno elemento per elemento, usando il codice, e anche una volta che hai un modello che sembra nel modo desiderato, è difficile da mantenere.

L’opzione 2 può spesso funzionare meglio, ma devi ancora costruire il Jinja HTML boilerplate, e talvolta la conversione da HTML a PDF non esce come previsto.

L’opzione 3 richiede di creare il modello prima utilizzando l’interfaccia web di un servizio online. Anche se ottieni un’interfaccia drag-and-drop, è piuttosto goffo e difficile rendere il tuo modello come vuoi. Di solito, devi anche pagare per utilizzare il servizio.

Mentre una delle opzioni di cui sopra può funzionare per voi, se non ti piace nessuno di loro, si può anche incidere insieme un documento API generazione basata su Google Drive. Otterrai un’API gratuita e sarai in grado di utilizzare Google Docs come strumento di template, che è abbastanza potente e ha molti modelli preesistenti per cose come fatture, lettere e CV.

Ho iniziato con un modello di fattura che ho trovato online. Sembra questo:

Google Docs Invoice Template

In questo tutorial, andremo attraverso la creazione di un’API che genera queste fatture e consente di inserire a livello di programmazione il numero di fattura da uno script Python esterno. In realtà, dovresti fare lo stesso per molti altri campi, ma inizieremo con un semplice esempio per motivi dimostrativi.

Scriveremo alcune righe di codice Script di Google App e alcune righe di codice Python.

Creazione di un documento modello

Utilizza uno dei modelli di documenti Google integrati, cerca online uno che corrisponda alle tue esigenze o crea il tuo su docs.google.com. (Avrete bisogno di un account Google).

Aggiungi segnaposto dove hai bisogno di informazioni dinamiche. Nell’esempio seguente, ho aggiunto la FATTURA NO {invoice_id} al posto dell’ID “456” che avevo sul documento originale. Non c’è niente di speciale in questa sintassi: useremo una funzione di ricerca e sostituzione di base in seguito per scambiarla con le informazioni reali, quindi usa qualcosa che è improbabile che appaia effettivamente nel documento finale.

Prendi nota dell’ID documento, che è la parte evidenziata nella barra degli URL.

Modello di fattura con segnaposto

Impostazione di uno script Google personalizzato

Vai su Google Drive, premi “Nuovo” nell’angolo in alto a sinistra. In “Altro”, seleziona “Google Apps Script” se è disponibile o “Connetti più app” se non lo vedi.

Connessione di più app

Cerca “script app” e scegli di collegarlo. Potresti vedere alcuni messaggi di avviso che chiedono se ti fidi di te stesso. Di ‘ che ce l’hai.

Aggiunta di script app

Una volta creato un nuovo script app, verrà visualizzato uno script vuoto predefinito che appare come segue.

Blank Google Apps Script

Elimina il codice che vedi lì e sostituiscilo con una funzione createDocument che appare come segue.

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";}

Alla riga 2, disattiva TEMPLATE_ID con l’ID documento che hai copiato dalla barra degli URL sul tuo Google Doc basato su modelli.

Questo codice trova il documento basato su modelli, ne crea una copia e imposta il nome del file su “Fattura” più tutto ciò che invoice_id passiamo. Quindi apre il nuovo file tramite DocumentApp (invece dell’app Drive, in modo da poter effettivamente ottenere il contenuto del file e modificarli). Cerca nel documento il segnaposto che abbiamo aggiunto ({invoice_id}) e lo sostituisce con l’effettivo invoice_id che la funzione prende come input. Quindi imposta il documento per essere accessibile pubblicamente e restituisce un URL che andrà direttamente a un’esportazione PDF per quel documento.

Sotto questa funzione, aggiungine un’altra chiamata doGet. Mentre la funzione precedente può essere nominata qualsiasi cosa, doGetè una funzione speciale negli script di Google Apps, quindi dovrai nominarla esattamente doGet. Questa funzione gestirà le richieste Web in arrivo dopo aver distribuito la nostra app.

Il codice per la funzione doGet è il seguente. Incolla questo sotto la precedente funzione createDocument().

function doGet(e) { var invoice_id = e.parameter.invoice_id; var url = createDocument(invoice_id); return ContentService.createTextOutput(url);}

Questo accetta invoice_id come parametro URL, lo passa alla nostra funzione createDocument che abbiamo appena scritto e restituisce l’URL del documento creato come testo normale.

Pubblicazione della nostra API

Dal menu” Pubblica”, selezionare “Distribuisci come web app”

Distribuisci come web app

Ti verrà chiesto di nominare il progetto. Dagli un nome come “API PDF” o qualsiasi altra cosa tu voglia.

Denominazione del progetto

Verrà visualizzato un nuovo menu per impostare le opzioni per la distribuzione della tua app web.

Opzioni di distribuzione

Aggiungi un messaggio come “distribuzione iniziale” sotto dove dice “Nuovo” e scegli “Chiunque, anche anonimo” dalle impostazioni di accesso. Lasciare le impostazioni di esecuzione come “Me”.

Attenzione: se condividi il link in un luogo pubblico, le persone potrebbero abusare del servizio e inviarlo via spam con richieste automatiche. Google può bloccare il tuo account per abuso se questo accade, in modo da mantenere il collegamento sicuro.

Premi il pulsante Distribuisci e prendi nota dell’URL che vedi nel prossimo pop-up.

URL della tua app

Aggiungi “?invoice_id=1 ” alla fine dell’URL e visitalo nel tuo browser. Dovrebbe sembrare qualcosa di simile

https://script.google.com/macros/s/AKfycbxDiKpTGqMijZmU8-0cPj06DBFjDOPYZJ9IFvhcO111GCh8jqxC/exec?invoice_id=1

Se tutto è andato bene, si dovrebbe vedere un link Google Docs visualizzato.

Risposta dalla nostra applicazione web

Se si visita l’URL, un PDF della fattura con il segnaposto commutato con 1 dovrebbe essere scaricato.

Aggiornamento dell’applicazione

Se invece vedi un errore o non ricevi una risposta, probabilmente hai commesso un errore nel codice. È possibile modificarlo e aggiornare la distribuzione nello stesso modo in cui è stata distribuita inizialmente. La schermata di aggiornamento è solo leggermente diversa dalla schermata di distribuzione.

Aggiorna le opzioni di distribuzione

L’unica cosa complicata è che devi selezionare “Nuovo” come versione per ogni modifica apportata. Se si apportano modifiche al codice e si aggiorna una versione precedente, le modifiche non avranno effetto, il che non è ovvio dall’interfaccia utente. (Puoi vedere che mi ci sono voluti alcuni tentativi per farlo bene.).

Creare le nostre fatture da Python

Ora possiamo creare fatture e salvarle localmente da uno script Python. Il codice seguente mostra come generare tre fatture in un ciclo 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)

Si noti che il processo di creazione e download è piuttosto lento, quindi ci vorranno alcuni secondi per ogni fattura creata.

Probabilmente hai notato che questa è una soluzione piuttosto “hacky” per generare file PDF dall’interno di Python. La funzionalità “sostituisci” è piuttosto limitata rispetto a un linguaggio di template appropriato e anche il passaggio dei dati attraverso una richiesta get ha delle limitazioni. Se passi attraverso qualcosa di più complicato di un ID fattura, dovrai prima codificare i dati. Puoi farlo in Python usando il modulo urllib.parse. Un esempio di modifica dello script Python per gestire dati più complicati è il seguente.

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)

Ma ci sono ancora limitazioni sul tipo di dati e su quanto è possibile passare solo utilizzando gli URL, quindi è necessario modificare lo script per utilizzare le richieste POST se si inviavano molti dati dinamici.

È anche piuttosto lento rispetto ad alcuni degli altri metodi che abbiamo discusso all’inizio, e Google ha alcune limitazioni su quanti file è possibile creare automaticamente in questo modo.

Detto questo, essere in grado di generare modelli utilizzando Google Docs può essere veloce e potente, quindi dovrai valutare i compromessi per te stesso.

Si noti inoltre che questo è un esempio piuttosto artificioso, in cui avremmo potuto eseguire lo script Python dall’ecosistema di Google, evitando di dover impostare un’API pubblica che potrebbe potenzialmente essere abusata se altre persone scoprissero l’URL. Tuttavia, potresti avere un’applicazione Python esistente, non ospitata su Google, che devi connettere con i file PDF generati automaticamente, e questo metodo ti consente comunque di impostare un “microservizio” autonomo all’interno dell’ecosistema di Google che consente una facile generazione di PDF.

Conclusione