【发布时间】:2017-04-19 20:47:05
【问题描述】:
我正在编写一个 python CGI 脚本,它逐行解析 csv 文件并使用 jinja2 创建一个 HTML 表。理想情况下,每个单独的 HTML 实例(每行一个)都将保存为 PDF 报告。
我进行了很多搜索,但我一直无法找到使用 python 从 HTML 转到 PDF 的好方法。是否可以将 CGI 渲染为 PDF?你会推荐什么方法来完成这项任务?
【问题讨论】:
我正在编写一个 python CGI 脚本,它逐行解析 csv 文件并使用 jinja2 创建一个 HTML 表。理想情况下,每个单独的 HTML 实例(每行一个)都将保存为 PDF 报告。
我进行了很多搜索,但我一直无法找到使用 python 从 HTML 转到 PDF 的好方法。是否可以将 CGI 渲染为 PDF?你会推荐什么方法来完成这项任务?
【问题讨论】:
如果您进行了大量搜索,那么我相信您已经看到了将 html 转换为 pdf 的所有非常复杂的选项:ReportLab、weasyprint、pdfkit 等:如本文所述:How to convert webpage into pdf using Python。
然而,我实际上只是在上个月研究了 Jinja2 -> HTML -> PDF 工作流程,所以希望我的解决方案能对您有所帮助。我发现下载 wkhtmltopdf(一个用 C 编写的小型命令行程序 - 它非常棒)并从 subprocess 使用它是到目前为止完成这项任务的最简单方法。我的示例如下:
import os
import jinja2
import subprocess
def render(template_path, context):
# Context = jinja context dictionary
path, filename = os.path.split(template_path)
return jinja2.Environment(loader=jinja2.FileSystemLoader(path or './')
).get_template(filename
).render(context)
def create_pdf(custom_data, template_path, out_dir, context, keep_html=False):
# Custom data = the part of my workflow that won't matter to you
report_name = os.path.join(out_dir, custom_data + "_report")
html_name = report_name + ".html"
pdf_name = report_name + ".pdf"
def write_html():
with open(html_name, 'w') as f:
html = render(template_path, context)
f.write(html)
write_html()
args = '"C:\\Program Files\\wkhtmltopdf\\bin\\wkhtmltopdf.exe" --zoom 0.75 -B 0 -L 0 -R 0 -T 0 {} {}'.format(html_name, pdf_name)
child = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE)
# Wait for the sub-process to terminate (communicate) then find out the
# status code
output, errors = child.communicate()
if child.returncode or errors:
# Change this to a log message
print "ERROR: PDF conversion failed. Subprocess exit status {}".format(
child.returncode)
if not keep_html:
# Try block only to avoid raising an error if you've already moved
# or deleted the html
try:
os.remove(html_name)
except OSError:
pass
大部分代码在jinja2 和subprocess 的文档中都有很好的解释,所以我不会在这里费力地复习。 wkhtmltopdf 中的 arg 标志转换为 Zoom = 75% 和 0 宽度边距(-B、-L 等是底部、左侧等的简写)。 wkhtmltopdf documention也不错。
已编辑:render 函数的功劳归于Matthias Eisen。用法:
假设一个模板位于 /some/path/my_tpl.html,包含:
你好 {{ 名字 }} {{ 姓氏 }}!
context = {
'firstname': 'John',
'lastname': 'Doe'
}
result = render('/some/path/my_tpl.html', context)
print(result)
你好约翰·多伊!
【讨论】:
jinja2 的截然不同的策略
context["DATE"] = datetime.datetime.now() 等