如何使用Python将网页转换为PDF


92

我正在寻找使用Python将网页打印为本地文件PDF的解决方案。很好的解决方案之一是使用Qt,请参见https://bharatikunal.wordpress.com/2010/01/

由于我在安装PyQt4时遇到问题,因此一开始它不起作用,因为它给出了错误消息,例如“ ImportError: No module named PyQt4.QtCore”和“ ImportError: No module named PyQt4.QtCore”。

这是因为PyQt4没有正确安装。我以前的库位于C:\ Python27 \ Lib,但是它不适用于PyQt4。

实际上,它只需要从http://www.riverbankcomputing.com/software/pyqt/download下载(注意所使用的正确Python版本),然后将其安装到C:\ Python27(我的情况)。而已。

现在脚本运行良好,所以我想分享一下。有关使用Qprinter的更多选项,请参考http://qt-project.org/doc/qt-4.8/qprinter.html#Orientation-enum

Answers:


155

您也可以使用pdfkit

用法

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

安装

苹果系统: brew install Caskroom/cask/wkhtmltopdf

Debian / Ubuntu: apt-get install wkhtmltopdf

视窗: choco install wkhtmltopdf

请参阅MacOS / Ubuntu /其他操作系统的官方文档:https : //github.com/JazzCore/python-pdfkit/wiki/Installing-wkhtmltopdf


4
这真是太棒了,比使用reportlab或使用打印驱动器进行转换要容易得多。非常感谢。
勒斯2015年

@NorthCat您能举一个使用pdfkit转换html表的例子吗?
巴别塔

1
Windows似乎不支持pdfkit。真的吗?
凯恩·周

2
完美!即使下载嵌入的图像,也不要使用它!您将必须apt-get install wkhtmltopdf
Tinmarino

4
pdfkit取决于非python软件包wkhtmltopdf,而后者又需要运行中的X服务器。因此,尽管在某些环境中很好,但这并不是在python中通常有效的答案。
Rasmus Kaj '18

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)

5
我可以提供文件路径而不是网址吗?
Piyush S. Wanare

11
我想我更喜欢这个项目,因为它的依赖项是python软件包而不是系统软件包。截至2018年1月,它似乎有更频繁的更新和更好的文档。
stv

3
有太多东西要安装。我在libpango停下来,去了pdfkit。对于整个系统的wkhtmltopdf来说很讨厌,但是weasyprint也需要在整个系统范围内进行安装。
visoft

1
我认为该选项应该是'wb',而不是'w',因为它pdf是一个bytes对象。
阿纳托利·谢尔巴科夫

1
对我来说,只下载的第一页,而忽略休息
法比奥

24

感谢下面的帖子,无论页面有多少页,我都能添加要打印的网页链接地址并在生成的PDF上显示时间。

使用Python将文本添加到现有PDF

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

要共享脚本,如下所示:

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.'

感谢您分享您的代码!有什么建议可以使本地pdf文件工作吗?还是像在URL前面加上“ file:///”一样容易?我对这些库不是很熟悉...谢谢
user2426679 2014年

@ user2426679,您的意思是将在线PDF转换为本地PDF文件?
Mark K

谢谢您的回复。我最终使用了wkhtmltopdf,因为它能够处理我要扔给它的东西。但是我在问如何加载本地硬盘上的pdf文件。欢呼声
user2426679 2014年

@ user2426679对不起,我仍然不明白你的意思。也许是因为我也是Python的新手。您的意思是使用Python读取本地PDF文件?
Mark K

与存在一些问题html5lib,xhtml2pdf使用了。这个解决方案解决了这个问题:github.com/xhtml2pdf/xhtml2pdf/issues/318
Blairg23 '16

14

这是一个工作正常的方法:

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_())

有趣的是,网页链接是作为文本生成的,而不是生成的PDF中的链接。
2014年

有人知道为什么这会为我生成空白pdf吗?
玻色子

11

这是使用QT的简单解决方案。我发现这是对StackOverFlow上另一个问题的答案的一部分。我在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!"

2

我尝试使用pdfkit @NorthCat答案。

它需要安装wkhtmltopdf。可以从这里下载安装。https://wkhtmltopdf.org/downloads.html

安装可执行文件。然后写一行以表明wkhtmltopdf的位置,如下所示。(引用自无法使用python PDFKIT创建pdf错误:“未找到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)

1

如果您使用硒和铬,则无需自己管理cookie,并且可以从铬的印刷品生成pdf页面。您可以参考这个项目来实现它。 https://github.com/maxvst/python-selenium-chrome-html-to-pdf-converter

修改后的基础> 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()

1
首先我使用weasyprint但它不支持cookie,即使您可以编写自己的 default_url_fetchercookie来处理它,但后来我在Ubuntu16中安装它时出现了问题。然后我使用wkhtmltopdf它支持cookie设置,但是处理时导致了很多OSERROR像-15 -11一些页面。
肖元梦

感谢您分享@Yuanmeng Xiao先生。
Mark K

1

该解决方案使用PyQt5版本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_())
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.