使用纯Python(在Linux上,不需要LibreOffice)将docx转换为pdf

29

我正在开发一个 Web 应用程序,其中一部分将上传的 docx 文件转换为 PDF 文件(经过一些处理后)。使用 python-docx 等方法,大多数处理都不需要 Windows 机器上安装 Word,甚至不需要在 Linux 上安装 LibreOffice (我的 Web 服务器是 PythonAnywhere - Linux,但没有 LibreOffice 和 sudoapt install 权限)。但是似乎将其转换为 PDF 需要其中之一。从这里和其他地方探索问题,到目前为止我有:

import subprocess

try:
    from comtypes import client
except ImportError:
    client = None

def doc2pdf(doc):
    """
    convert a doc/docx document to pdf format
    :param doc: path to document
    """
    doc = os.path.abspath(doc) # bugfix - searching files in windows/system32
    if client is None:
        return doc2pdf_linux(doc)
    name, ext = os.path.splitext(doc)
    try:
        word = client.CreateObject('Word.Application')
        worddoc = word.Documents.Open(doc)
        worddoc.SaveAs(name + '.pdf', FileFormat=17)
    except Exception:
        raise
    finally:
        worddoc.Close()
        word.Quit()


def doc2pdf_linux(doc):
    """
    convert a doc/docx document to pdf format (linux only, requires libreoffice)
    :param doc: path to document
    """
    cmd = 'libreoffice --convert-to pdf'.split() + [doc]
    p = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    p.wait(timeout=10)
    stdout, stderr = p.communicate()
    if stderr:
        raise subprocess.SubprocessError(stderr)

正如您所见,一种方法需要comtypes,另一种方法则需要将libreoffice作为子进程。除了切换到更复杂的托管服务器外,是否有其他解决方案?


2
Python-docx不需要Word(也不需要Windows),因为它几乎所有的工作都在其源代码中完成。(“几乎全部”,除了一些外部标准模块,如XML、ZIP等和图像处理。)由于Python是一个图灵完备的语言,你可以做同样的事情,从无到有地创建一个PDF,而不需要任何外部软件。阅读官方规范并且你会知道为什么使用外部程序要容易得多。 - Jongware
3
当然,这样做更容易,但如果不更换服务器,这对我来说并不是一个选择。 - Ofer Sadan
5
然后,找到一个纯Python实现的PDF创建工具(虽然推荐一个违反了Stack Overflow的指南,但你可以使用搜索引擎找到适合你编程水平和目的的工具),或者自己动手制作。但要注意,使用外部工具有很好的理由 - 请阅读上述规范以了解原因。 - Jongware
2
为什么不使用一个可以通过Python触发的API,例如https://www.convertapi.com/docx-to-pdf?还可以查看这个问题https://stackoverflow.com/questions/3815983/whats-the-best-program-api-for-converting-word-docs-to-pdf-that-does-not-requ。 - Rick
请尝试使用 pandoc - pylang
6个回答

25

PythonAnywhere的帮助页面提供了关于处理PDF文件的信息,您可以在此处查看:https://help.pythonanywhere.com/pages/PDF

总结:PythonAnywhere安装了许多用于PDF操作的Python包,其中一个可能可以满足您的需求。然而,对我来说似乎最简单的方法是使用abiword。命令行命令abiword --to=pdf filetoconvert.docx会将docx文件转换为PDF,并在与docx文件相同的目录中生成一个名为filetoconvert.pdf的文件。请注意,该命令会输出一个错误消息到标准错误流,报告有关XDG_RUNTIME_DIR的问题(或者至少对我来说是这样),但它仍然可以工作,可以忽略错误消息。


1
我需要进行一些测试,以查看它是否可以在不弄乱文件的情况下正常工作,但这正是我想听到的答案 :) 我会报告结果。 - Ofer Sadan
2
这对我也起作用。它确实创建了一个PDF文件(具有相同的文件名),但我也收到了“XDG_RUNTIME_DIR”错误。为了避免这个错误,我在bash控制台中使用了“export XDG_RUNTIME_DIR=/tmp/”,第二次尝试时错误消失了。最后,为了检查转换是否成功,我从Pythonanywhere下载了PDF文件到我的本地计算机,并打开文件查看内容。所有内容都成功显示。 - amanb
2
回报告:这个方案运行得相当不错(在从右到左的语言上有一些问题),但目前来说这是我最好的解决方案(我可能最终会迁移到谷歌云)。谢谢! - Ofer Sadan
从Abiword的网站上可以看到:“请注意Windows用户:由于项目中缺乏Windows开发人员,因此不再提供可下载版本。” - Thom Ives
1
@ThomIves 虽然这可能是真的,但这是关于通过PythonAnywhere使用Linux,因此Windows版本在这里不相关。 - jcgoble3
显示剩余3条评论

3

以下是 Linux 上将 docx 转换为 pdf 的代码(对于 Windows,只需下载 LibreOffice 并将 soffice 路径替换为 soffice)

import subprocess

def generate_pdf(doc_path, path):

    subprocess.call(['soffice',
                 # '--headless',
                 '--convert-to',
                 'pdf',
                 '--outdir',
                 path,
                 doc_path])
    return doc_path
generate_pdf("docx_path.docx", "output_path")

1
它在已安装LibreOffice的Ubuntu(20.04 LTS)上运行良好。 - SimoX

2
另外一个你可以使用的是 libreoffice,然而正如第一位回答者所说,使用实际的 comtypes 质量永远不会像使用它那么好。无论如何,在安装了 libreoffice 之后,这里是进行操作的代码。
from subprocess import  Popen
LIBRE_OFFICE = r"C:\Program Files\LibreOffice\program\soffice.exe"

def convert_to_pdf(input_docx, out_folder):
    p = Popen([LIBRE_OFFICE, '--headless', '--convert-to', 'pdf', '--outdir',
               out_folder, input_docx])
    print([LIBRE_OFFICE, '--convert-to', 'pdf', input_docx])
    p.communicate()


sample_doc = 'file.docx'
out_folder = 'some_folder'
convert_to_pdf(sample_doc, out_folder)

1
这似乎在并行处理中不起作用。我创建了10个Popen实例来转换10个docx文件,但只得到了5个pdf,并且没有任何错误输出。 - Z fp
有趣,我之前做过这个,但是也许你可以发一下你的代码? - dfresh22
1
我发布了一个带有我的代码的问题:https://dev59.com/Ub_qa4cB1Zd3GeqPTPeQ @dfresh22 - Z fp
2
标题为:“使用纯Python(在Linux上,无需LibreOffice)将docx转换为pdf” 无需LibreOffice。 - victorkolis
这个翻译引擎只能翻译文本内容,无法保留格式、表格、图片等。 - mike01010
这个翻译会保留所有的格式、表格、图片等吗? - undefined

1
你可以使用Aspose.Words for Python将DOCX和其他文档格式转换为PDF。代码很简单 - 加载一个文档并将其保存为PDF:
import aspose.words as aw

doc = aw.Document("in.docx")
doc.save("out.pdf")

可以使用PdfSaveOptions指定其他转换选项,例如PDF兼容性: https://docs.aspose.com/words/python-net/convert-a-document-to-pdf/ 但是在Linux下使用Aspose.Words for Python还有其他要求: https://docs.aspose.com/words/python-net/system-requirements/#system-requirements-for-target-linux-platform

注意:Aspose.Words是一款商业产品,在评估模式下有两个主要限制:

  • 它会在文档中添加一个评估水印
  • 它限制文档的最大大小为几百段落。

如果您想测试没有评估版本限制的Aspose.Words,您可以申请一个免费的30天临时许可证

许可证应通过代码应用:

lic = aw.License()
lic.set_license("C:\\Temp\\Aspose.Word.Python.NET.lic")

更多信息请点击这里: https://docs.aspose.com/words/python-net/licensing/

请注意,此软件不支持MacOS。 - bieboebap
请注意,此软件不支持MacOS。 - undefined
是的,你说得对。目前Aspose.Words不支持MacOS。但是有计划支持MacOS。 - Alexey Noskov

-1

我已经尝试了Alexey的建议:aspose.words工具非常适合转换,但生成的PDF文件有水印,并且其中包含红色的声明(用于评估目的)。

def download_approval(request, project_id):
    project = get_object_or_404(Project, pk=project_id)
    doc = DocxTemplate('letter.docx')
    context = {
        'ref_num': project.ref_num,
        'author_name': project.author.get_full_name,
        'approval_date': project.approved_date.date(),
        'project_title': project.title_en
    }
    doc.render(context)
    file_path = project.ref_num + '_' + 'approval_letter.docx'
    full_path = os.path.join(MEDIA_URL, 'approval/') + file_path
    doc.save(full_path)
    doc_final = aw.Document(full_path)
    response = HttpResponse(doc_final.save('research_permission_request.pdf'), content_type='application/pdf')
    response['Content-Disposition'] = 'inline; filename=' + os.path.basename(full_path)
    return response

1
是的,Aspose.Words是一款商业产品,在评估模式下有两个主要限制:Aspose.Words会在文档中添加评估水印,并将文档的最大大小限制在几百段落以内。如果您想测试没有评估版本限制的Aspose.Words,您可以申请一个免费的30天临时许可证:https://purchase.aspose.com/temporary-license/。我已更新答案。 - Alexey Noskov

-6
我发现在Linux环境下有一种最简单的方法来做到这一点...
导入os
os.system("lowriter --convert-to pdf" +str(" ") + str(file_path))

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community
4
确实非常容易,但是这个问题特别要求不使用LibreOffice,而我理解lowriter是LibreOffice的一部分。 - Ofer Sadan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接