Jak przekonwertować stronę internetową do formatu PDF za pomocą języka Python

95

Szukałem rozwiązania, aby wydrukować stronę internetową do lokalnego pliku PDF za pomocą Pythona. jednym z dobrych rozwiązań jest użycie Qt, które można znaleźć tutaj, https://bharatikunal.wordpress.com/2010/01/ .

Na początku nie działało, ponieważ miałem problem z instalacją PyQt4, ponieważ wyświetlał komunikaty o błędach, takie jak „ ImportError: No module named PyQt4.QtCore” i „ ImportError: No module named PyQt4.QtCore”.

To dlatego, że PyQt4 nie został poprawnie zainstalowany. Kiedyś biblioteki znajdowały się w C: \ Python27 \ Lib, ale nie jest to dla PyQt4.

W rzeczywistości wystarczy pobrać go z http://www.riverbankcomputing.com/software/pyqt/download (pamiętaj o poprawnej wersji Pythona, którego używasz) i zainstalować go w C: \ Python27 (mój przypadek). Otóż ​​to.

Teraz skrypty działają dobrze, więc chcę się nimi podzielić. Więcej opcji korzystania z Qprinter można znaleźć pod adresem http://qt-project.org/doc/qt-4.8/qprinter.html#Orientation-enum .

Mark K.
źródło

Odpowiedzi:

157

Możesz także użyć pdfkit :

Stosowanie

import pdfkit
pdfkit.from_url('http://google.com', 'out.pdf')

zainstalować

System operacyjny Mac: brew install Caskroom/cask/wkhtmltopdf

Debian / Ubuntu: apt-get install wkhtmltopdf

Okna: choco install wkhtmltopdf

Zobacz oficjalną dokumentację dla MacOS / Ubuntu / innego systemu operacyjnego: https://github.com/JazzCore/python-pdfkit/wiki/Installing-wkhtmltopdf

NorthCat
źródło
4
To niesamowite, o wiele łatwiejsze niż mieszanie się z reportlabem lub używanie dysku do konwersji do konwersji. Dzięki wielkie.
Dowlers
@NorthCat Czy możesz podać inny przykład konwersji tabel html za pomocą pdfkit?
Babel
1
Wygląda na to, że Windows nie obsługuje pdfkit. Czy to prawda?
Kane Chew
2
Idealny !! Nawet pobierz osadzone obrazy, nie kłopocz się tym! Będziesz musiałapt-get install wkhtmltopdf
Tinmarino
4
pdfkit zależy od pakietu wkhtmltopdf innego niż python, który z kolei wymaga działającego X serwera. Tak więc, chociaż jest to fajne w niektórych środowiskach, nie jest to odpowiedź, która działa ogólnie w Pythonie.
Rasmus Kaj
47

WeasyPrint

pip install weasyprint  # No longer supports Python 2.x.

python
>>> import weasyprint
>>> pdf = weasyprint.HTML('http://www.google.com').write_pdf()
>>> len(pdf)
92059
>>> open('google.pdf', 'wb').write(pdf)
JohnMudd
źródło
5
Czy zamiast adresu URL mogę podać ścieżkę do pliku?
Piyush S. Wanare
12
Myślę, że wolę ten projekt, ponieważ jego zależności są pakietami Pythona, a nie pakietem systemowym. Od stycznia 2018 wydaje się, że ma częstsze aktualizacje i lepszą dokumentację.
stv
4
Jest zbyt wiele rzeczy do zainstalowania. Zatrzymałem się w libpango i poszedłem po pdfkit. Nieprzyjemne dla całego systemu wkhtmltopdf, ale weasyprint wymaga również instalacji w całym systemie.
visoft
1
Chciałbym wierzyć, opcja powinna być 'wb', nie 'w', ponieważ pdfjest to bytesobiekt.
Anatolij Scherbakov
1
dla mnie pobiera tylko pierwszą stronę i ignoruje resztę
Fábio
24

dzięki poniższym postom i jestem w stanie dodać na stronie internetowej adres linku do wydrukowania i aktualny czas na wygenerowanym pliku PDF, bez względu na to ile stron ma.

Dodaj tekst do istniejącego pliku PDF za pomocą Pythona

https://github.com/disflux/django-mtr/blob/master/pdfgen/doc_overlay.py

Aby udostępnić skrypt jak poniżej:

import time
from pyPdf import PdfFileWriter, PdfFileReader
import StringIO
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from xhtml2pdf import pisa
import sys 
from PyQt4.QtCore import *
from PyQt4.QtGui import * 
from PyQt4.QtWebKit import * 

url = 'http://www.yahoo.com'
tem_pdf = "c:\\tem_pdf.pdf"
final_file = "c:\\younameit.pdf"

app = QApplication(sys.argv)
web = QWebView()
#Read the URL given
web.load(QUrl(url))
printer = QPrinter()
#setting format
printer.setPageSize(QPrinter.A4)
printer.setOrientation(QPrinter.Landscape)
printer.setOutputFormat(QPrinter.PdfFormat)
#export file as c:\tem_pdf.pdf
printer.setOutputFileName(tem_pdf)

def convertIt():
    web.print_(printer)
    QApplication.exit()

QObject.connect(web, SIGNAL("loadFinished(bool)"), convertIt)

app.exec_()
sys.exit

# Below is to add on the weblink as text and present date&time on PDF generated

outputPDF = PdfFileWriter()
packet = StringIO.StringIO()
# create a new PDF with Reportlab
can = canvas.Canvas(packet, pagesize=letter)
can.setFont("Helvetica", 9)
# Writting the new line
oknow = time.strftime("%a, %d %b %Y %H:%M")
can.drawString(5, 2, url)
can.drawString(605, 2, oknow)
can.save()

#move to the beginning of the StringIO buffer
packet.seek(0)
new_pdf = PdfFileReader(packet)
# read your existing PDF
existing_pdf = PdfFileReader(file(tem_pdf, "rb"))
pages = existing_pdf.getNumPages()
output = PdfFileWriter()
# add the "watermark" (which is the new pdf) on the existing page
for x in range(0,pages):
    page = existing_pdf.getPage(x)
    page.mergePage(new_pdf.getPage(0))
    output.addPage(page)
# finally, write "output" to a real file
outputStream = file(final_file, "wb")
output.write(outputStream)
outputStream.close()

print final_file, 'is ready.'
Mark K.
źródło
Dziękujemy za udostępnienie kodu! Masz jakąś radę, jak to zrobić dla lokalnych plików PDF? A może jest to tak proste, jak dodanie „file: ///” do adresu URL? Nie jestem zaznajomiony z tymi bibliotekami ... dzięki
user2426679
@ user2426679, masz na myśli konwersję PDF online do lokalnych plików PDF?
Mark K
dziękuję za odpowiedź ... przepraszam za moje spóźnienie. Skończyło się na tym, że użyłem wkhtmltopdf, ponieważ był w stanie obsłużyć to, co do niego rzucałem. Ale pytałem, jak załadować plik PDF, który był lokalny dla mojego dysku twardego. Pozdrawiam
user2426679
@ user2426679 przepraszam, nadal cię nie rozumiem. może dlatego, że też jestem nowicjuszem w Pythonie. Miałeś na myśli czytanie lokalnych plików PDF w Pythonie?
Mark K
Wystąpiły pewne problemy z html5libplikiem, który jest używany przez xhtml2pdf. To rozwiązanie rozwiązało problem: github.com/xhtml2pdf/xhtml2pdf/issues/318
Blairg23
14

oto ten działający dobrze:

import sys 
from PyQt4.QtCore import *
from PyQt4.QtGui import * 
from PyQt4.QtWebKit import * 

app = QApplication(sys.argv)
web = QWebView()
web.load(QUrl("http://www.yahoo.com"))
printer = QPrinter()
printer.setPageSize(QPrinter.A4)
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName("fileOK.pdf")

def convertIt():
    web.print_(printer)
    print("Pdf generated")
    QApplication.exit()

QObject.connect(web, SIGNAL("loadFinished(bool)"), convertIt)
sys.exit(app.exec_())
Mark K.
źródło
Co ciekawe, linki do stron internetowych są generowane jako tekst, a nie linki w wygenerowanym pliku PDF.
amergin
1
Czy ktoś wie, dlaczego miałoby to generować dla mnie puste pliki PDF?
bozon
11

Oto proste rozwiązanie wykorzystujące QT. Znalazłem to jako część odpowiedzi na inne pytanie w StackOverFlow. Przetestowałem to na Windowsie.

from PyQt4.QtGui import QTextDocument, QPrinter, QApplication

import sys
app = QApplication(sys.argv)

doc = QTextDocument()
location = "c://apython//Jim//html//notes.html"
html = open(location).read()
doc.setHtml(html)

printer = QPrinter()
printer.setOutputFileName("foo.pdf")
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setPageSize(QPrinter.A4);
printer.setPageMargins (15,15,15,15,QPrinter.Millimeter);

doc.print_(printer)
print "done!"
Jim Paul
źródło
4

Wypróbowałem odpowiedź @NorthCat używając pdfkit.

Wymagało zainstalowania wkhtmltopdf. Instalację można pobrać stąd. https://wkhtmltopdf.org/downloads.html

Zainstaluj plik wykonywalny. Następnie napisz wiersz, aby wskazać, gdzie jest wkhtmltopdf, jak poniżej. (odwołuje się do Nie można utworzyć pliku PDF przy użyciu Pythona PDFKIT Błąd: „Nie znaleziono pliku wykonywalnego wkhtmltopdf:”

import pdfkit


path_wkthmltopdf = "C:\\Folder\\where\\wkhtmltopdf.exe"
config = pdfkit.configuration(wkhtmltopdf = path_wkthmltopdf)

pdfkit.from_url("http://google.com", "out.pdf", configuration=config)
Mark K.
źródło
gdzie to poszło po kliknięciu .deb i zainstalowaniu w centrum oprogramowania?
webNoob13
2

To rozwiązanie działało dla mnie przy użyciu PyQt5 w wersji 5.15.0

import sys
from PyQt5 import QtWidgets, QtWebEngineWidgets
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QPageLayout, QPageSize
from PyQt5.QtWidgets import QApplication

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    loader = QtWebEngineWidgets.QWebEngineView()
    loader.setZoomFactor(1)
    layout = QPageLayout()
    layout.setPageSize(QPageSize(QPageSize.A4Extra))
    layout.setOrientation(QPageLayout.Portrait)
    loader.load(QUrl('/programming/23359083/how-to-convert-webpage-into-pdf-by-using-python'))
    loader.page().pdfPrintingFinished.connect(lambda *args: QApplication.exit())

    def emit_pdf(finished):
        loader.page().printToPdf("test.pdf", pageLayout=layout)

    loader.loadFinished.connect(emit_pdf)
    sys.exit(app.exec_())
Y.kh
źródło
1

Jeśli używasz selenu i chromu, nie musisz samodzielnie zarządzać plikami cookie i możesz wygenerować stronę PDF z wydruku chromu jako PDF. Możesz polecić ten projekt, aby go zrealizować. https://github.com/maxvst/python-selenium-chrome-html-to-pdf-converter

zmodyfikowana baza> https://github.com/maxvst/python-selenium-chrome-html-to-pdf-converter/blob/master/sample/html_to_pdf_converter.py

import sys
import json, base64


def send_devtools(driver, cmd, params={}):
    resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id
    url = driver.command_executor._url + resource
    body = json.dumps({'cmd': cmd, 'params': params})
    response = driver.command_executor._request('POST', url, body)
    return response.get('value')


def get_pdf_from_html(driver, url, print_options={}, output_file_path="example.pdf"):
    driver.get(url)

    calculated_print_options = {
        'landscape': False,
        'displayHeaderFooter': False,
        'printBackground': True,
        'preferCSSPageSize': True,
    }
    calculated_print_options.update(print_options)
    result = send_devtools(driver, "Page.printToPDF", calculated_print_options)
    data = base64.b64decode(result['data'])
    with open(output_file_path, "wb") as f:
        f.write(data)



# example
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

url = "/programming/23359083/how-to-convert-webpage-into-pdf-by-using-python#"
webdriver_options = Options()
webdriver_options.add_argument("--no-sandbox")
webdriver_options.add_argument('--headless')
webdriver_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chromedriver, options=webdriver_options)
get_pdf_from_html(driver, url)
driver.quit()
Yuanmeng Xiao
źródło
1
Najpierw używam weasyprint, ale nie obsługuje on plików cookie, nawet możesz napisać własne default_url_fetcherdo obsługi plików cookie, ale później pojawia się problem podczas instalowania go w Ubuntu16. Następnie używam wkhtmltopdf, który obsługuje ustawienia plików cookie, ale spowodował wiele OSERROR, takich jak -15-11 podczas obsługi jakaś strona.
Yuanmeng Xiao
Dziękuję za udostępnienie pana @Yuanmeng Xiao.
Mark K