3

我在问一个与这个非常相似的问题。我在 Django 的 Ubuntu 服务器上使用 wkhtmltopdf 创建一个 pdf。

from tempfile import *
from subprocess import Popen, PIPE

tempfile = gettempdir()+"/results.pdf"
papersize = 'Tabloid'
orientation = 'Landscape'
command_args = "wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl %s" %(orientation, papersize, tempfile)
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout().read()
popen.terminate()
popen.wait()
response = HttpResponse(pdf_contents, mimetype='application/pdf')
return response

这给了我在 popen = Popen... 行上的“没有这样的文件或目录”错误。所以我把那条线改成

popen = Popen(["sh", "-c", command_args], stdout=PIPE, stderr=PIPE)

现在我在 pdf_contents =... 行上收到“'file' object is not callable”错误。

我也尝试将 .communicate() 添加到 popen =... 行,但我似乎无法以这种方式找到 pdf 输出。我应该补充一点,在命令行中输入 command_args 行会创建一个 pdf 就好了。谁能指出我正确的方向?

4

4 回答 4

3

wkhtmltopdf没有输出 PDF 的内容以供Popen阅读。 pdf_contents正确包含命令的输出(无)。如果要将输出文件的内容返回给客户端(见下文),则需要读取输出文件的内容,或者跳过输出文件并wkhtmltopdf直接输出pdf的内容,

from tempfile import *
from subprocess import Popen, PIPE

tempfile = gettempdir()+"/results.pdf"
command_args = "/path/to/wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl %s" % ('Landscape', 'Tabloid', tempfile)
popen = Popen(["sh", "-c", command_args])
popen.wait()
f = open(tempfile, 'r')
pdf_contents = f.read()
f.close()

return HttpResponse(pdf_contents, mimetype='application/pdf')
于 2011-03-24T19:43:39.500 回答
2

您的第一个版本失败,因为 python 不知道 wkhtmltopdf 的位置。Python 不会为此检查您的路径。您的第二个版本将命令传递给处理该问题的 shell。您可以通过传递一个 shell=True 参数来达到相同的效果。

第二个问题(正如其他人所指出的)是您在不应该调用 stdout() 时调用。

第三个问题是你的 wkhtmltopdf 命令是错误的。你正在做:

wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl tempfile/results.pdf

相反,您应该通过

wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl -

这样 wkhtmltopdf 会将输出写入标准输出,您可以阅读它。如果您传递另一个 - 作为源,您可以通过标准输入发送 html。

于 2011-03-24T19:47:26.673 回答
1

你得到的原因'file' object is not callable是因为一旦你有了你的popen对象,stdout它就是一个文件句柄,而不是一个方法。不要调用它,只需使用它:

popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout.read()
于 2011-03-24T18:58:41.393 回答
0

您可能需要考虑更改

popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout().read()
# ...
response = ...

pdf_contents = subprocess.check_output(command_args.split())
response = ...

或在旧版本中:

process = Popen(command_args.split(), stdout=PIPE, stderr=PIPE)
pdf_contents = process.stdout.read()
response = ...

我建议你看看check_output函数。

编辑:另外,不要调用 terminate(),因为它会在不等待它完成的情况下终止进程,可能导致 PDF 损坏。您几乎只需要使用 wait(),因为它将等待该过程完成(并因此输出它必须输出的所有内容)。使用 check_output() 函数时,您不必担心它,因为它“默认”等待进程完成。

除此之外,命名一个与模块同名的变量(我说的是临时文件)是一个主意。我建议您将其更改为 tmpfile 并检查NamedTemporaryFile,因为它比您现在正在做的更安全。

于 2011-03-24T18:57:26.203 回答