.doc 到 pdf 使用 python

Posted

技术标签:

【中文标题】.doc 到 pdf 使用 python【英文标题】:.doc to pdf using python 【发布时间】:2011-08-26 01:11:34 【问题描述】:

我的任务是将大量 .doc 文件转换为 .pdf。我的主管希望我这样做的唯一方法是通过 MSWord 2010。我知道我应该能够使用 python COM 自动化来自动化它。唯一的问题是我不知道如何以及从哪里开始。我尝试搜索一些教程,但找不到任何教程(也许我可能有,但我不知道我在寻找什么)。

现在我正在阅读this。不知道这会有多大用处。

【问题讨论】:

【参考方案1】:

一个使用comtypes的简单示例,转换单个文件,输入和输出文件名作为命令行参数给出:

import sys
import os
import comtypes.client

wdFormatPDF = 17

in_file = os.path.abspath(sys.argv[1])
out_file = os.path.abspath(sys.argv[2])

word = comtypes.client.CreateObject('Word.Application')
doc = word.Documents.Open(in_file)
doc.SaveAs(out_file, FileFormat=wdFormatPDF)
doc.Close()
word.Quit()

您也可以使用pywin32,除了:

import win32com.client

然后:

word = win32com.client.Dispatch('Word.Application')

【讨论】:

对于许多文件,考虑设置:word.Visible = False 以节省时间和处理word文件(MS word不会这样显示,代码基本上会在后台运行) 我已经设法让它适用于 powerpoint 文档。使用Powerpoint.ApplicationPresentations.OpenFileFormat=32 我使用的是 linux 服务器,而这些库不能在 linux 中运行。有没有其他方法可以让它在 linux 中运行 开发 8 年,正是这个答案让我感觉很糟糕,因为我不在 Windows 上! 有没有办法只使用文件对象并避免这些文件保存?【参考方案2】:

您可以使用docx2pdf python 包将 docx 批量转换为 pdf。它可以用作 CLI 和 python 库。它需要安装 Microsoft Office,并在 Windows 上使用 COM,在 macOS 上使用 AppleScript (JXA)。

from docx2pdf import convert

convert("input.docx")
convert("input.docx", "output.pdf")
convert("my_docx_folder/")
pip install docx2pdf
docx2pdf input.docx output.pdf

免责声明:我编写了 docx2pdf 包。 https://github.com/AlJohri/docx2pdf

【讨论】:

刚刚用你的包打印了我的 .docx 文件。它就像一个魅力!使用起来再简单不过了。干得好! 谢谢@Todd!如果有机会,请给 repo 打一颗星。 @Abdelhedihlel 不幸的是,它需要安装 Microsoft Office,因此只能在 Windows 和 macOS 上运行。 @AlJohri 看看这里michalzalecki.com/converting-docx-to-pdf-using-python 这个解决方案适用于 windows 和 linux。在 linux 上运行这是必须的,因为大多数部署服务器都使用 linux 你的模块中有没有将word文件对象转换为pdf的方法?【参考方案3】:

我在这个问题上工作了半天,所以我想我应该分享一下我在这个问题上的一些经验。史蒂文的回答是正确的,但它会在我的电脑上失败。这里有两个关键点来解决它:

(1)。当我第一次创建“Word.Application”对象时,我应该在打开任何文档之前让它(单词 app)可见。 (实际上,我自己也无法解释为什么会这样。如果我不在我的电脑上这样做,当我试图在隐形模型中打开一个文档时程序会崩溃,然后'Word.Application'对象将被删除操作系统。)

(2)。做(1)后,程序有时会运行良好,但可能会经常失败。崩溃错误"COMError: (-2147418111, 'Call was rejected by callee.', (None, None, None, 0, None))" 表示 COM 服务器可能无法快速响应。因此,我在尝试打开文档之前添加了延迟。

完成这两个步骤后,程序将完美运行,不再出现故障。演示代码如下。如果您遇到同样的问题,请尝试按照以下两个步骤操作。希望对您有所帮助。

    import os
    import comtypes.client
    import time


    wdFormatPDF = 17


    # absolute path is needed
    # be careful about the slash '\', use '\\' or '/' or raw string r"..."
    in_file=r'absolute path of input docx file 1'
    out_file=r'absolute path of output pdf file 1'

    in_file2=r'absolute path of input docx file 2'
    out_file2=r'absolute path of outputpdf file 2'

    # print out filenames
    print in_file
    print out_file
    print in_file2
    print out_file2


    # create COM object
    word = comtypes.client.CreateObject('Word.Application')
    # key point 1: make word visible before open a new document
    word.Visible = True
    # key point 2: wait for the COM Server to prepare well.
    time.sleep(3)

    # convert docx file 1 to pdf file 1
    doc=word.Documents.Open(in_file) # open docx file 1
    doc.SaveAs(out_file, FileFormat=wdFormatPDF) # conversion
    doc.Close() # close docx file 1
    word.Visible = False
    # convert docx file 2 to pdf file 2
    doc = word.Documents.Open(in_file2) # open docx file 2
    doc.SaveAs(out_file2, FileFormat=wdFormatPDF) # conversion
    doc.Close() # close docx file 2   
    word.Quit() # close Word Application 

【讨论】:

【参考方案4】:

我已经测试了许多解决方案,但没有一个能在 Linux 发行版上高效运行。

我推荐这个解决方案:

import sys
import subprocess
import re


def convert_to(folder, source, timeout=None):
    args = [libreoffice_exec(), '--headless', '--convert-to', 'pdf', '--outdir', folder, source]

    process = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)
    filename = re.search('-> (.*?) using filter', process.stdout.decode())

    return filename.group(1)


def libreoffice_exec():
    # TODO: Provide support for more platforms
    if sys.platform == 'darwin':
        return '/Applications/LibreOffice.app/Contents/MacOS/soffice'
    return 'libreoffice'

然后你调用你的函数:

result = convert_to('TEMP Directory',  'Your File', timeout=15)

所有资源:

https://michalzalecki.com/converting-docx-to-pdf-using-python/

【讨论】:

【参考方案5】:

unoconv(用 python 编写)和 openoffice 作为无头守护程序运行。 http://dag.wiee.rs/home-made/unoconv/

非常适合用于 doc、docx、ppt、pptx、xls、xlsx。 如果您需要在服务器上转换文档或保存/转换为某些格式,这非常有用

【讨论】:

你能否包含一个示例代码来展示如何从 python 脚本 (import unoconv unoconv.dosomething(...)) 执行此操作?该文档仅显示如何从命令行执行此操作。【参考方案6】:

作为 SaveAs 功能的替代方法,您还可以使用 ExportAsFixedFormat,它使您可以访问通常在 Word 中看到的 PDF 选项对话框。有了它,您可以指定书签和其他文档属性。

doc.ExportAsFixedFormat(OutputFileName=pdf_file,
    ExportFormat=17, #17 = PDF output, 18=XPS output
    OpenAfterExport=False,
    OptimizeFor=0,  #0=Print (higher res), 1=Screen (lower res)
    CreateBookmarks=1, #0=No bookmarks, 1=Heading bookmarks only, 2=bookmarks match word bookmarks
    DocStructureTags=True
    );

函数参数的完整列表是:'OutputFileName'、'ExportFormat'、'OpenAfterExport'、'OptimizeFor'、'Range'、'From'、'To'、'Item'、'IncludeDocProps'、'KeepIRM' , 'CreateBookmarks', 'DocStructureTags', 'BitmapMissingFonts', 'UseISO19005_1', 'FixedFormatExtClassPtr'

【讨论】:

【参考方案7】:

值得注意的是,史蒂文斯的回答有效,但请确保是否使用 for 循环导出多个文件以在循环之前放置 ClientObject 或 Dispatch 语句 - 它只需要创建一次 - 请参阅我的问题:Python win32com.client.Dispatch looping through Word documents and export to PDF; fails when next loop occurs

【讨论】:

【参考方案8】:

如果您不介意使用PowerShell,请查看此Hey, Scripting Guy! article。提供的代码可用于使用WdSaveFormatwdFormatPDF 枚举值(参见here)。 This blog article 提出了同一想法的不同实现。

【讨论】:

我是 linux/Unix 用户,更倾向于 python。但是 ps 脚本看起来很简单,正是我想要的。谢谢:)【参考方案9】:

我尝试了接受的答案,但并不特别热衷于 Word 生成的臃肿 PDF,这些 PDF 通常比预期大一个数量级。在查看了如何在使用虚拟 PDF 打印机时禁用对话框后,我遇到了 Bullzip PDF 打印机,它的功能给我留下了深刻的印象。它现在取代了我之前使用的其他虚拟打印机。您会在他们的下载页面上找到“免费社区版”。

COM API 可以在here 找到,可用设置的列表可以在here 找到。这些设置被写入一个“runonce”文件,该文件仅用于一个打印作业,然后自动删除。打印多个 PDF 时,我们需要确保在开始另一个打印作业之前完成一个打印作业,以确保为每个文件正确使用设置。

import os, re, time, datetime, win32com.client

def print_to_Bullzip(file):
    util = win32com.client.Dispatch("Bullzip.PDFUtil")
    settings = win32com.client.Dispatch("Bullzip.PDFSettings")
    settings.PrinterName = util.DefaultPrinterName      # make sure we're controlling the right PDF printer

    outputFile = re.sub("\.[^.]+$", ".pdf", file)
    statusFile = re.sub("\.[^.]+$", ".status", file)

    settings.SetValue("Output", outputFile)
    settings.SetValue("ConfirmOverwrite", "no")
    settings.SetValue("ShowSaveAS", "never")
    settings.SetValue("ShowSettings", "never")
    settings.SetValue("ShowPDF", "no")
    settings.SetValue("ShowProgress", "no")
    settings.SetValue("ShowProgressFinished", "no")     # disable balloon tip
    settings.SetValue("StatusFile", statusFile)         # created after print job
    settings.WriteSettings(True)                        # write settings to the runonce.ini
    util.PrintFile(file, util.DefaultPrinterName)       # send to Bullzip virtual printer

    # wait until print job completes before continuing
    # otherwise settings for the next job may not be used
    timestamp = datetime.datetime.now()
    while( (datetime.datetime.now() - timestamp).seconds < 10):
        if os.path.exists(statusFile) and os.path.isfile(statusFile):
            error = util.ReadIniString(statusFile, "Status", "Errors", '')
            if error != "0":
                raise IOError("PDF was created with errors")
            os.remove(statusFile)
            return
        time.sleep(0.1)
    raise IOError("PDF creation timed out")

【讨论】:

【参考方案10】:

您应该从研究所谓的虚拟 PDF 打印驱动程序开始。 一旦您找到一个,您应该能够编写将您的 DOC 文件打印成 PDF 文件的批处理文件。您可能也可以在 Python 中执行此操作(设置打印机驱动程序输出并在 MSWord 中发出文档/打印命令,稍后可以使用命令行 AFAIR 完成)。

【讨论】:

【参考方案11】:

我正在使用此解决方案,但我需要搜索所有 .docx、.dotm、.docm、.odt、.doc 或 .rtf,然后将它们全部转换为 .pdf (python 3.7.5)。希望它有效...

import os
import win32com.client

wdFormatPDF = 17

for root, dirs, files in os.walk(r'your directory here'):
    for f in files:

        if  f.endswith(".doc")  or f.endswith(".odt") or f.endswith(".rtf"):
            try:
                print(f)
                in_file=os.path.join(root,f)
                word = win32com.client.Dispatch('Word.Application')
                word.Visible = False
                doc = word.Documents.Open(in_file)
                doc.SaveAs(os.path.join(root,f[:-4]), FileFormat=wdFormatPDF)
                doc.Close()
                word.Quit()
                word.Visible = True
                print ('done')
                os.remove(os.path.join(root,f))
                pass
            except:
                print('could not open')
                # os.remove(os.path.join(root,f))
        elif f.endswith(".docx") or f.endswith(".dotm") or f.endswith(".docm"):
            try:
                print(f)
                in_file=os.path.join(root,f)
                word = win32com.client.Dispatch('Word.Application')
                word.Visible = False
                doc = word.Documents.Open(in_file)
                doc.SaveAs(os.path.join(root,f[:-5]), FileFormat=wdFormatPDF)
                doc.Close()
                word.Quit()
                word.Visible = True
                print ('done')
                os.remove(os.path.join(root,f))
                pass
            except:
                print('could not open')
                # os.remove(os.path.join(root,f))
        else:
            pass

尝试和例外是针对那些我无法阅读并且直到最后一个文档才会退出代码的文档。

【讨论】:

【参考方案12】:

我也修改了它以支持 ppt。我的解决方案支持所有以下指定的扩展。

word_extensions = [".doc", ".odt", ".rtf", ".docx", ".dotm", ".docm"]
ppt_extensions = [".ppt", ".pptx"]

我的解决方案:Github Link

我修改了Docx2PDF的代码

【讨论】:

【参考方案13】:

我建议忽略你的主管并使用具有 Python api 的 OpenOffice。 OpenOffice 内置了对 Python 的支持,有人为此目的创建了一个库 (PyODConverter)。

如果他对输出不满意,请告诉他您可能需要数周时间才能完成。

【讨论】:

以上是关于.doc 到 pdf 使用 python的主要内容,如果未能解决你的问题,请参考以下文章

python 使用LibreOffice的命令行界面将PDF文件转换为与Microsoft Office Word兼容的doc / docx文件。

使用 Spring Boot 显示从 MySQL 到 Thymeleaf 的文件(pdf、doc、ppt)

使用 Zoho Forms 使用 Docs 模板生成 PDF

Python 将pdf转换成txt(不处理图片)

如何用Python实现doc文件批量转换为docx

从Txt,PDf,Google云端硬盘中的Doc文件中提取电子邮件地址