【问题标题】:Converting HTML to PDF works only when conversion command is given in separate file仅当在单独的文件中给出转换命令时,才能将 HTML 转换为 PDF
【发布时间】:2021-06-06 15:33:43
【问题描述】:

我想用我编写的一个 Python 小程序生成发票。我希望它首先将发票输出为 HTML 文件,然后将其转换为 PDF。目前我的代码正在根据需要创建 HTML 文档,但它正在输出一个空白 PDF 文件:

import pdfkit 
import time 

name = input('Enter business name: ')
date = input('Enter the date: ')
invoice = input('Enter invoice number: ')
total = 1000 # Fixed number for now just for testing purposes

f = open('invoice.html','w')
message = f"""<html>
<head>
<link rel='stylesheet' href='style.css')>
</head>
<body>
<h1>INVOICE<span id="invoice-number"> {invoice}</h1>
<h3>{date} </h3> 
<h3>{name} </h3>
<h3>Total: ${total}</h3>
</body>
</html>"""

f.write(message)
time.sleep(2)

options = {
    'enable-local-file-access': None
}
pdfkit.from_file('invoice.html', 'out.pdf', options = options)

当我运行上面的代码时,它输出的 HTML 文档看起来不错,但它创建的 PDF 是空白的。我根本没有收到任何错误消息。终端中的输出是:

Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done  

但是,我在同一目录中有另一个名为 test.py 的文件。该文件包含导入语句,最后四行与第一行代码完全相同,仅此而已:

import pdfkit 

options = {
    'enable-local-file-access': None
}
pdfkit.from_file('invoice.html', 'out.pdf', options = options)

如果我在前一个文件之后运行此文件,它会正确输出 PDF,使其看起来像 HTML 版本。为什么这段代码在单独的文件中运行时有效,但在包含在原始文件中时无效?如何让它在同一个文件中运行,这样我就不必执行两个命令来获取发票?

【问题讨论】:

  • 顺便说一句,当您创建minimal reproducible example 时,您应该修复所有输入。您对total 的想法是正确的。在这种情况下不是问题,但我看到了完全不可重现的代码,因为 OP 没有正确指定它们的输入。

标签: python file-io pdfkit


【解决方案1】:

您永远不会关闭正在写入的文件,也不会显式刷新它。由于它是一个小文本 sn-p,并且默认情况下启用了缓冲,因此在您的进程终止之前它不会被写入磁盘。您不会看到错误,因为文件在打开时会立即创建。问题并不像您想象的那样是时间问题。

这个问题有很多解决方案。最简单和最正确的方法是在完成写入后立即关闭文件。这是您在 python 中惯用地打开文件的方式:

name = input('Enter business name: ')
date = input('Enter the date: ')
total = 1000 # Fixed number for now just for testing purposes

message = ...
options = {
    'enable-local-file-access': None
}

with open('invoice.html','w') as f:
    f.write(message)

pdfkit.from_file('invoice.html', 'out.pdf', options = options)

请注意,您无需等待任何事情:退出with 块将关闭文件并在进程中刷新它即使发生错误。您应该养成在完成文件处理后立即关闭文件的习惯:大多数操作系统支持每个进程有限数量的文件句柄。这意味着在 with 块之后调用 pdfkit.from_file 可以保证它有一个完全刷新的文件可供使用。

这里有一些其他的方法,不是惯用的,在实践中不推荐。我提供它们只是为了让您了解不同步骤的工作原理:

  1. 在尝试读取之前刷新文件。而不是sleep,调用

    f.flush()
    

    这将使文件对象保持打开状态并且不一定正确处理错误,但它会确保在您尝试读取之前写出它们的 HTML 内容。

  2. 关闭缓冲。缓冲意味着在您写入 4kb 左右的数据之前(无论您的磁盘块大小是多少),在您刷新之前不会将其写入磁盘。您可以禁用此行为,以便通过像这样调用open 立即写出字节

    open('invoice.html', 'w', buffering=0)
    

【讨论】:

  • @Z4-tier。谢谢!我发誓我知道其中的区别。它是自动更正的。
猜你喜欢
  • 2018-06-03
  • 2013-07-10
  • 2012-02-22
  • 2019-07-14
  • 1970-01-01
  • 2012-02-11
  • 2011-07-11
相关资源
最近更新 更多