twórz pliki PDF z szablonów za pomocą skryptów Python i Google

często przydatne jest tworzenie plików PDF ze skryptów Python. Niezależnie od tego, czy tworzysz faktury, listy, raporty lub inne dokumenty, które zawierają wiele powtórzeń formatowania, ale tylko odrobinę dynamicznej treści, dodanie automatyzacji może zaoszczędzić wiele godzin.

masz do tego kilka opcji. Zwykle są to:

  1. użyj biblioteki PDF, takiej jak reportlab, aby bezpośrednio generować pliki PDF (np. https://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/)
  2. użyj biblioteki szablonów HTML, takiej jak Jinja2 i konwertuj z HTML na PDF (np. zobacz http://pbpython.com/pdf-reports.html)
  3. użyj zewnętrznego interfejsu API, takiego jak https://pdfgeneratorapi.com/.

w przypadku opcji 1, generowanie plików PDF bezpośrednio z wnętrza Pythona może bardzo utrudnić formatowanie. Musisz narysować wszystko, czego potrzebujesz, element po elemencie, używając kodu, a nawet gdy masz szablon wyglądający tak, jak chcesz, trudno go utrzymać.

Opcja 2 może często działać lepiej, ale nadal musisz zbudować kocioł HTML Jinja, a czasami konwersja HTML do PDF nie wychodzi tak, jak oczekiwałeś.

Opcja 3 wymaga najpierw zbudowania szablonu przy użyciu interfejsu internetowego usługi online. Chociaż masz interfejs przeciągania i upuszczania, jest to dość niezgrabne i trudne, aby Twój szablon wyglądał tak, jak chcesz. Zwykle za korzystanie z usługi trzeba również zapłacić.

chociaż jedna z powyższych opcji może działać dla Ciebie, jeśli nie podoba Ci się żadna z nich, możesz również zhakować interfejs API generowania dokumentów oparty na Dysku Google. Otrzymasz bezpłatny interfejs API i będziesz mógł używać Dokumentów Google jako narzędzia do tworzenia szablonów, które jest dość potężne i ma wiele istniejących szablonów dla rzeczy takich jak faktury, listy i CV.

zacząłem od szablonu faktury, który znalazłem w Internecie. Wygląda to tak:

szablon faktury Google Docs

w tym samouczku przejdziemy przez tworzenie interfejsu API, który generuje te faktury i pozwala programowo wstawiać numer faktury z zewnętrznego skryptu Pythona. W rzeczywistości musiałbyś zrobić to samo dla wielu innych dziedzin, ale zaczniemy od prostego przykładu z powodów demonstracyjnych.

napiszemy kilka linijek kodu Google App Script i kilka linijek kodu Pythona.

Tworzenie dokumentu szablonu

użyj jednego z wbudowanych szablonów dokumentów Google, wyszukaj w Internecie taki, który odpowiada twoim potrzebom lub zbuduj własny w docs.google.com. (będziesz potrzebował konta Google).

Dodaj symbole zastępcze, w których potrzebujesz dynamicznych informacji. W poniższym przykładzie dodałem fakturę nr {invoice_id} zamiast identyfikatora „456”, który miałem na oryginalnym dokumencie. Nie ma nic specjalnego w tej składni – użyjemy później podstawowej funkcji wyszukiwania i zamiany, aby zamienić ją na prawdziwe informacje, więc użyj czegoś, co prawdopodobnie nie pojawi się w ostatecznym dokumencie.

zanotuj swój identyfikator dokumentu, który jest podświetloną częścią paska adresu URL.

szablon faktury z symbolem zastępczym

Konfigurowanie niestandardowego skryptu Google

przejdź do Dysku Google, naciśnij „nowy” w lewym górnym rogu. W sekcji „Więcej” wybierz „skrypt Google Apps”, jeśli jest dostępny, lub „połącz więcej aplikacji”, jeśli go nie widzisz.

łączenie kolejnych aplikacji

wyszukaj „skrypt aplikacji” i wybierz, aby go połączyć. Możesz zobaczyć komunikaty ostrzegawcze z pytaniem, czy ufasz sobie. Powiedz, że tak.

dodawanie skryptu aplikacji

gdy możesz utworzyć nowy skrypt aplikacji, zobaczysz domyślny pusty skrypt, który wygląda następująco.

pusty skrypt Google Apps

Usuń widoczny tam kod i zastąp go funkcją createDocument, która wygląda następująco.

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

On line 2, Przełącz TEMPLATE_ID z identyfikatorem dokumentu, który skopiowałeś z paska adresu URL w szablonie Google Doc.

ten kod znajduje szablon doc, tworzy jego kopię i ustawia nazwę pliku na „Faktura” plus cokolwiek invoice_id przekazujemy. Następnie otwiera nowy plik za pośrednictwem DocumentApp (zamiast aplikacji Drive, abyśmy mogli pobrać zawartość pliku i edytować je). Przeszukuje dokument w poszukiwaniu elementu zastępczego, który dodaliśmy ({invoice_id}) i zastępuje go rzeczywistą invoice_id, którą funkcja przyjmuje jako wejście. Następnie ustawia dokument jako publicznie dostępny i zwraca adres URL, który przejdzie bezpośrednio do eksportu PDF dla tego dokumentu.

poniżej tej funkcji dodaj kolejną o nazwie doGet. Podczas gdy poprzednia funkcja może mieć dowolną nazwę, doGet jest specjalną funkcją w skryptach Google Apps, więc musisz ją nazwać dokładnie doGet. Ta funkcja będzie obsługiwać przychodzące żądania internetowe po wdrożeniu naszej aplikacji.

kod dla funkcji doGet jest następujący. Wklej to poniżej poprzedniej funkcji createDocument().

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

to pobiera invoice_id jako parametr URL, przekazuje go do naszej funkcji createDocument, którą właśnie napisaliśmy, i zwraca adres URL utworzonego dokumentu jako zwykły tekst.

publikowanie naszego API

z menu „Publikuj” wybierz „Wdróż jako aplikację internetową”

Wdróż jako aplikację internetową

zostaniesz poproszony o nadanie nazwy projektowi. Nadaj mu nazwę taką jak „PDF API” lub cokolwiek innego, co chcesz.

nazywając projekt

zobaczysz nowe menu, aby ustawić opcje wdrażania aplikacji internetowej.

opcje wdrażania

Dodaj wiadomość typu „initial deploy” pod adresem „New” i wybierz „Anyone, even anonymous” z ustawień dostępu. Pozostaw ustawienia wykonania jako „ja”.

ostrzeżenie: jeśli udostępnisz link w miejscu publicznym, ludzie mogą nadużywać Serwisu i spamować go automatycznymi żądaniami. Google może zablokować Twoje konto za nadużycia, jeśli tak się stanie, więc zachowaj link Bezpieczny.

naciśnij przycisk wdrażania i zanotuj adres URL, który widzisz w następnym wyskakującym okienku.

URL Twojej aplikacji

Dodaj „?invoice_id=1” na koniec adresu URL i odwiedź go w przeglądarce. Powinno wyglądać mniej więcej tak

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

jeśli wszystko poszło dobrze, powinieneś zobaczyć link Google Docs.

odpowiedź z naszej aplikacji internetowej

jeśli odwiedzisz adres URL, należy pobrać plik PDF z fakturą zastępczą wyłączoną z 1.

Aktualizacja aplikacji

jeśli zamiast tego widzisz błąd lub nie otrzymujesz odpowiedzi, prawdopodobnie popełniłeś błąd w kodzie. Możesz go zmienić i zaktualizować wdrożenie w taki sam sposób, w jaki zostało ono pierwotnie wdrożone. Ekran aktualizacji tylko nieznacznie różni się od ekranu wdrażania.

opcje wdrażania aktualizacji

jedyną trudną rzeczą jest to, że musisz wybrać „nowy” jako wersję dla każdej wprowadzonej zmiany. Jeśli wprowadzisz zmiany w kodzie i zaktualizujesz poprzednią wersję, zmiany nie wejdą w życie, co nie jest oczywiste z interfejsu użytkownika. (Widać, że zajęło mi kilka prób, aby to zrobić dobrze.).

Tworzenie naszych faktur z Pythona

możemy teraz tworzyć faktury i zapisywać je lokalnie ze skryptu Pythona. Poniższy kod pokazuje jak wygenerować trzy faktury w pętli 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)

zauważ, że proces tworzenia i pobierania jest dość powolny, więc zajmie to kilka sekund dla każdej utworzonej faktury.

prawdopodobnie zauważyłeś, że jest to dość „hacky” rozwiązanie do generowania plików PDF z wnętrza Pythona. Funkcja „zastąp” jest dość ograniczona w porównaniu do właściwego języka szablonów, a przekazywanie danych przez żądanie get ma również ograniczenia. Jeśli przejdziesz przez coś bardziej skomplikowanego niż identyfikator faktury, najpierw zakodujesz dane URL. Możesz to zrobić w Pythonie używając modułu urllib.parse. Przykładowa modyfikacja skryptu Pythona w celu radzenia sobie z bardziej skomplikowanymi danymi jest następująca.

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)

ale nadal istnieją ograniczenia dotyczące tego, jakiego rodzaju Dane i ile możesz przekazać za pomocą adresów URL, więc musisz zmodyfikować skrypt, aby zamiast tego używał żądań POST, jeśli wysyłasz dużo dynamicznych danych.

jest to również dość powolne w porównaniu do niektórych innych metod, które omówiliśmy na początku, a Google ma pewne ograniczenia dotyczące liczby plików, które można utworzyć automatycznie w ten sposób.

to powiedziawszy, możliwość generowania szablonów za pomocą Dokumentów Google może być szybka i wydajna, więc musisz sam ocenić kompromis.

zauważ również, że jest to dość wymyślny przykład, w którym mogliśmy uruchomić skrypt Pythona z ekosystemu Google i uniknąć konieczności konfigurowania publicznego interfejsu API, który mógłby być potencjalnie nadużywany, jeśli inne osoby odkryłyby adres URL. Być może jednak masz istniejącą aplikację Pythona, nie hostowaną w Google, którą musisz połączyć z automatycznie generowanymi plikami PDF, a ta metoda nadal pozwala skonfigurować samodzielną „mikrousługę” w ekosystemie Google, która pozwala na łatwe generowanie plików PDF.

podsumowanie