Como converter uma página da web em PDF usando Python

92

Eu estava encontrando solução para imprimir página da web em arquivo local PDF, usando Python. uma das boas soluções é usar o Qt, encontrado aqui, https://bharatikunal.wordpress.com/2010/01/ .

Não funcionou no início porque tive problemas com a instalação do PyQt4 porque apresentava mensagens de erro como ' ImportError: No module named PyQt4.QtCore' e ' ImportError: No module named PyQt4.QtCore'.

Foi porque o PyQt4 não foi instalado corretamente. Eu costumava ter as bibliotecas localizadas em C: \ Python27 \ Lib, mas não é para PyQt4.

Na verdade, ele simplesmente precisa fazer o download de http://www.riverbankcomputing.com/software/pyqt/download (lembre-se da versão correta do Python que você está usando) e instalá-lo em C: \ Python27 (meu caso). É isso aí.

Agora os scripts funcionam bem, então quero compartilhá-los. para obter mais opções de uso do Qprinter, consulte http://qt-project.org/doc/qt-4.8/qprinter.html#Orientation-enum .

Mark K
fonte

Respostas:

155

Você também pode usar o pdfkit :

Uso

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

Instalar

Mac OS: brew install Caskroom/cask/wkhtmltopdf

Debian / Ubuntu: apt-get install wkhtmltopdf

Janelas: choco install wkhtmltopdf

Consulte a documentação oficial para MacOS / Ubuntu / outro sistema operacional: https://github.com/JazzCore/python-pdfkit/wiki/Installing-wkhtmltopdf

NorthCat
fonte
4
Isso é incrível, muito mais fácil do que mexer com o reportlab ou usar uma unidade de impressão para converter. Muito obrigado.
Dowlers de
@NorthCat, você pode dar outro exemplo sobre a conversão de tabelas html com o pdfkit?
Babel
1
Parece que o Windows não suporta pdfkit. Isso é verdade?
Kane Chew
2
Perfeito !! Mesmo baixe as imagens incorporadas, não se preocupe em usar isso! Você terá queapt-get install wkhtmltopdf
Tinmarino
4
O pdfkit depende do pacote não-python wkhtmltopdf, que por sua vez requer um servidor X em execução. Portanto, embora seja agradável em alguns ambientes, essa não é uma resposta que funciona geralmente em python.
Rasmus Kaj
45

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
fonte
5
Posso fornecer o caminho do arquivo em vez do url?
Piyush S. Wanare
11
Acho que vou preferir este projeto, pois suas dependências são pacotes python em vez de um pacote de sistema. Em janeiro de 2018, parece ter atualizações mais frequentes e melhor documentação.
stv
3
Existem muitas coisas para instalar. Parei na libpango e fui para o pdfkit. Desagradável para wkhtmltopdf em todo o sistema, mas weasyprint também requer algumas instalações em todo o sistema.
visoft
1
Eu acredito que a opção deve ser 'wb', não 'w', porque pdfé um bytesobjeto.
Anatoly Scherbakov
1
para mim ele só baixa a primeira página e ignora o resto
Fábio
24

graças aos posts abaixo, e posso adicionar no endereço do link da página da web a ser impresso e apresentar a hora no PDF gerado, não importa quantas páginas tenha.

Adicionar texto a PDF existente usando Python

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

Para compartilhar o script conforme abaixo:

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
fonte
Obrigado por compartilhar seu código! Algum conselho para fazer isso funcionar para arquivos PDF locais? Ou é tão fácil quanto adicionar "file: ///" ao url? Não estou muito familiarizado com essas bibliotecas ... obrigado
user2426679
@ user2426679, você quer dizer converter PDF online em arquivos PDF locais?
Mark K
obrigado pela sua resposta ... desculpe pelo meu atraso. Acabei usando wkhtmltopdf, pois ele era capaz de lidar com o que eu estava jogando. Mas eu estava perguntando como carregar um pdf local para o meu disco rígido. Saudações
user2426679
@ user2426679 desculpe, mas ainda não entendi. talvez porque eu também seja um novato em Python. Você quis dizer ler arquivos PDF locais em Python?
Mark K
Houve alguns problemas com html5lib, que é usado por xhtml2pdf. Esta solução corrigiu o problema: github.com/xhtml2pdf/xhtml2pdf/issues/318
Blairg23
14

aqui está o que está funcionando bem:

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
fonte
Curiosamente, os links das páginas da web são gerados como texto, e não como links no PDF gerado.
amergin
Alguém sabe por que isso estaria gerando pdfs em branco para mim?
bóson de
11

Aqui está uma solução simples usando QT. Descobri isso como parte de uma resposta a uma pergunta diferente no StackOverFlow. Eu testei no Windows.

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
fonte
2

Tentei responder @NorthCat usando o pdfkit.

É necessário instalar o wkhtmltopdf. A instalação pode ser baixada aqui. https://wkhtmltopdf.org/downloads.html

Instale o arquivo executável. Em seguida, escreva uma linha para indicar onde wkhtmltopdf está, como abaixo. (referenciado em Não é possível criar pdf usando python PDFKIT Erro: "Nenhum executável wkhtmltopdf encontrado:"

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
fonte
1

Se você usa selênio e cromo, não precisa gerenciar os cookies por conta própria e pode gerar uma página em pdf a partir da impressão de cromo em pdf. Você pode consultar este projeto para realizá-lo. https://github.com/maxvst/python-selenium-chrome-html-to-pdf-converter

base modificada> 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
fonte
1
Em primeiro lugar, eu uso o weasyprint, mas ele não suporta cookies, mesmo você pode escrever seus próprios default_url_fetcherpara lidar com cookies, mas depois ocorre um problema ao instalá-lo no Ubuntu16. Em seguida, eu uso wkhtmltopdf, ele suporta a configuração de cookies, mas causou muitos OSERROR como -15 -11 ao manipular alguma página.
Yuanmeng Xiao
Obrigado por compartilhar o Sr. @Yuanmeng Xiao.
Mark K
1

Esta solução funcionou para mim usando PyQt5 versão 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
fonte