Opret PDF-filer fra skabeloner med Python og Google Scripts
ofte er det nyttigt at oprette PDF-filer fra dine Python-scripts. Uanset om du opretter fakturaer, breve, rapporter eller andre dokumenter, der indeholder en masse formatering gentagelse, men kun en lille smule dynamisk indhold, tilføje nogle automatisering kan spare dig mange timer.
du har et par muligheder for dette. De sædvanlige er:
- brug et PDF-bibliotek som reportlab til at generere PDF-filer direkte (f. eks. https://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/)
- brug en HTML templating bibliotek som Jinja2 og konvertere fra HTML til PDF (f. eks se http://pbpython.com/pdf-reports.html)
- brug en tredjeparts API som https://pdfgeneratorapi.com/.
for Mulighed 1 kan generering af PDF-filer direkte indefra Python gøre formatering meget vanskelig. Du skal tegne alt, hvad du har brug for element for element, ved hjælp af kode, og selv når du har en skabelon, der ser ud som du vil have den, er det svært at vedligeholde.
Mulighed 2 kan ofte fungere bedre, men du skal stadig bygge Jinja HTML-kedelpladen, og nogle gange kommer HTML til PDF-konverteringen ikke helt ud som forventet.
valgmulighed 3 kræver, at du først bygger skabelonen ved hjælp af en onlinetjenestes internetgrænseflade. Selvom du får en træk-og-slip-grænseflade, er det ret klodset og svært at få din skabelon til at se ud som du vil. Normalt skal du også betale for at bruge tjenesten.
mens en af ovenstående muligheder muligvis fungerer for dig, hvis du ikke kan lide nogen af dem, kan du også hacke sammen en DOKUMENTGENERERINGS API baseret på Google Drev. Du får en gratis API, og du kan bruge Google Docs som dit skabelonværktøj, som er ret kraftfuldt og har mange allerede eksisterende skabeloner til ting som fakturaer, breve og CV ‘ er.
jeg startede med en faktura skabelon, som jeg fandt online. Det ser sådan ud:
i denne vejledning går vi gennem oprettelse af en API, der genererer disse fakturaer og lader dig programmatisk indsætte fakturanummeret fra et eksternt Python-script. I virkeligheden skal du gøre det samme for mange af de andre felter, men vi starter med et simpelt eksempel af demonstrationsårsager.
vi skriver et par linjer med Google App Script-kode og et par linjer med Python-kode.
oprettelse af et skabelondokument
brug en af de indbyggede Google-dokumentskabeloner, søg online efter en, der matcher dine behov, eller bygg din egen over på docs.google.com. (du skal bruge en Google-konto).
Tilføj pladsholdere, hvor du har brug for dynamisk information. I eksemplet nedenfor har jeg tilføjet faktura nr {invoice_id}
i stedet for ” 456 ” id, som jeg havde på originaldokumentet. Der er ikke noget særligt ved denne syntaks-vi bruger en grundlæggende søgnings-og udskiftningsfunktion senere for at bytte dette ud for de rigtige oplysninger, så brug noget, der sandsynligvis ikke vises i det endelige dokument.
noter dit dokument-id, som er den fremhævede del i URL-linjen.
opsætning af et brugerdefineret Google-Script
gå til Google Drev, tryk på “ny” i øverste venstre hjørne. Under” mere “skal du vælge” Google Apps Script”, hvis det er tilgængeligt, eller” Tilslut flere apps”, hvis du ikke kan se det.
Søg efter “apps script” og vælg at forbinde det. Du kan muligvis se nogle advarselsmeddelelser, der spørger, om du stoler på dig selv. Sig, at du gør.
når du kan oprette et nyt App Script, vil du se et standard tomt script, der ser ud som følger.
Slet den kode, du ser der, og erstat den med en createDocument
funktion, der ser ud som følger.
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";}
på linje 2 skal du skifte TEMPLATE_ID
med det dokument-ID, du kopierede fra URL-linjen på din templated Google Doc.
denne kode finder templated doc, opretter en kopi af den og sætter filnavnet til “faktura” plus hvad invoice_id
vi passerer ind. Derefter åbner den nye fil gennem DocumentApp (i stedet for Drive-appen, så vi faktisk kan få indholdet af filen og redigere dem). Den søger doc efter den pladsholder, vi tilføjede ({invoice_id}
) og erstatter den med den faktiske invoice_id
, som funktionen tager som input. Det indstiller derefter dokumentet til at være offentligt tilgængeligt og returnerer en URL, der går direkte til en PDF-eksport for det pågældende dokument.
under denne funktion skal du tilføje en anden kaldet doGet
. Mens den forrige funktion kan navngives hvad som helst, er doGet
en speciel funktion i Google Apps-Scripts, så du bliver nødt til at navngive den nøjagtigt doGet
. Denne funktion håndterer indgående internetanmodninger, efter at vi har implementeret vores app.
koden for funktionen doGet
er som følger. Indsæt dette under den forrige createDocument()
funktion.
function doGet(e) { var invoice_id = e.parameter.invoice_id; var url = createDocument(invoice_id); return ContentService.createTextOutput(url);}
dette tager invoice_id som en URL-parameter, sender dette videre til vores createDocument
– funktion, som vi lige har skrevet, og returnerer URL ‘ en til det oprettede dokument som almindelig tekst.
udgivelse af vores API
fra menuen” Publicer “skal du vælge ” Implementer som internetapp”
du bliver bedt om at navngive projektet. Giv det et navn som “PDF API” eller noget andet, du ønsker.
du får vist en ny menu til at indstille mulighederne for implementering af din internetapp.
Tilføj en meddelelse som “initial deploy” under hvor der står “Ny” og vælg “nogen, selv anonym” fra adgangsindstillingerne. Forlad Udførelsesindstillingerne som”mig”.
advarsel: hvis du deler linket på et offentligt sted, kan folk misbruge tjenesten og spam den med automatiske anmodninger. Google kan låse din konto for misbrug, hvis dette sker, så hold linket sikkert.
tryk på knappen Deploy og noter Den URL, du ser på den næste pop op.
Tilføj “?invoice_id=1 “til slutningen af URL’ en og besøg den i din bro.ser. Det skal se noget ud
https://script.google.com/macros/s/AKfycbxDiKpTGqMijZmU8-0cPj06DBFjDOPYZJ9IFvhcO111GCh8jqxC/exec?invoice_id=1
hvis alt gik godt, skal du se et Google Docs-link vises.
hvis du besøger URL ‘ en, skal en PDF af fakturaen med pladsholderen slået ud med 1
hentes.
opdatering af applikationen
hvis du ser en fejl i stedet eller ikke får svar, Har du sandsynligvis lavet en fejl i koden. Du kan ændre den og opdatere implementeringen på samme måde, som du oprindeligt implementerede den. Opdateringsskærmen er kun lidt anderledes end implementeringsskærmen.
Det eneste vanskelige er, at du skal vælge “Ny” som version for hver ændring, du foretager. Hvis du foretager ændringer i koden og opdaterer en tidligere version, træder ændringerne ikke i kraft, hvilket ikke er tydeligt fra brugergrænsefladen. (Du kan se, at det tog mig et par forsøg på at få det rigtigt .).
oprettelse af vores fakturaer fra Python
vi kan nu oprette fakturaer og gemme dem lokalt fra et Python-script. Følgende kode viser, hvordan du genererer tre fakturaer i en for
loop.
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)
Bemærk, at oprettelses-og overførselsprocessen er ret langsom, så det tager et par sekunder for hver faktura, du opretter.
du har sikkert bemærket, at dette er en ganske “hacky” løsning til at generere PDF-filer inde fra Python. Funktionen “erstat” er ret begrænset sammenlignet med et korrekt templeringssprog, og at videregive data gennem en get-anmodning har også begrænsninger. Hvis du gennemgår noget mere kompliceret end et faktura-ID, skal du først URL-kode dataene. Du kan gøre dette i Python ved hjælp af urllib.parse
modulet. Et eksempel modifikation af Python script til at håndtere mere komplicerede data er som følger.
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)
men der er stadig begrænsninger for, hvilken slags data og hvor meget du kan passere bare ved hjælp af URL ‘ er, så du bliver nødt til at ændre scriptet for at bruge POSTANMODNINGER i stedet, hvis du sendte en masse dynamiske data.
Det er også ret langsomt sammenlignet med nogle af de andre metoder, vi diskuterede i starten, og Google har nogle begrænsninger på, hvor mange filer du kan oprette automatisk på denne måde.
når det er sagt, kan det være hurtigt og kraftfuldt at kunne generere skabeloner ved hjælp af Google Docs, så du bliver nødt til at vurdere afvejningerne for dig selv.
Bemærk også, at dette er et ret konstrueret eksempel, hvor vi kunne have kørt Python-scriptet fra Googles økosystem og undgået at skulle oprette en offentlig API, der potentielt kunne misbruges, hvis andre mennesker opdagede URL ‘ en. Du har dog muligvis en eksisterende Python-applikation, der ikke er hostet på Google, som du har brug for at oprette forbindelse til automatisk genererede PDF-filer, og denne metode giver dig stadig mulighed for at oprette en selvstændig “mikroservice” i Googles økosystem, der giver mulighed for nem PDF-generation.