Python win32com.client.Dispatch循环遍历Word文档并导出为PDF;在下一个循环发生时失败

6
基于这里的脚本:使用Python将.doc转换为.pdf,我已经得到了一个半工作的脚本,可以将.C:\Export_to_pdf中的.docx文件导出到一个新文件夹中的pdf文件。

问题是它可以处理前几个文档,然后就会失败并显示以下错误:

(-2147352567, 'Exception occurred.', (0, u'Microsoft Word', u'Command failed', u'wdmain11.chm', 36966, -2146824090), None)

显然,这是一条不太有用的错误提示。如果我使用pdb慢慢调试它,我可以循环遍历所有文件并成功导出。如果我还在Windows任务管理器中观察进程,我可以看到WINWORD在应该开始和结束时启动,但对于较大的文件,需要更长时间才能稳定内存使用情况。这使我认为当WINWORD没有时间初始化或在客户机调度对象上调用下一个方法之前退出时,脚本会被绊倒。

是否有win32com或comtypes的方式来识别和等待进程启动或完成?

我的脚本:

import os
from win32com import client

folder = "C:\\Export_to_pdf"
file_type = 'docx'
out_folder = folder + "\\PDF"

os.chdir(folder)

if not os.path.exists(out_folder):
    print 'Creating output folder...'
    os.makedirs(out_folder)
    print out_folder, 'created.'
else:
    print out_folder, 'already exists.\n'

for files in os.listdir("."):
    if files.endswith(".docx"):
        print files

print '\n\n'

try:
    for files in os.listdir("."):
        if files.endswith(".docx"):
            out_name = files.replace(file_type, r"pdf")
            in_file = os.path.abspath(folder + "\\" + files)
            out_file = os.path.abspath(out_folder + "\\" + out_name)
            word = client.Dispatch("Word.Application")
            doc = word.Documents.Open(in_file)
            print 'Exporting', out_file
            doc.SaveAs(out_file, FileFormat=17)
            doc.Close()
            word.Quit()
except Exception, e:
    print e

工作代码-只需将try块替换为此内容。注意将DispatchEx语句移动到for循环外部,并将word.Quit()移到finally语句中以确保它关闭。
try:
    word = client.DispatchEx("Word.Application")
    for files in os.listdir("."):
        if files.endswith(".docx") or files.endswith('doc'):
            out_name = files.replace(file_type, r"pdf")
            in_file = os.path.abspath(folder + "\\" + files)
            out_file = os.path.abspath(out_folder + "\\" + out_name)
            doc = word.Documents.Open(in_file)
            print 'Exporting', out_file
            doc.SaveAs(out_file, FileFormat=17)
            doc.Close()
except Exception, e:
    print e
finally:
    word.Quit()
1个回答

12
可能不是问题的根源,而是在每次迭代中调度一个单独的Word实例并在其中关闭它是不必要的,可能是您看到的占用内存变大的原因。您只需要打开一次实例,在该实例中您可以打开和关闭所有需要的文档。像下面这样:
try:
    word = client.DispatchEx("Word.Application") # Using DispatchEx for an entirely new Word instance
    word.Visible = True # Added this in here so you can see what I'm talking about with the movement of the dispatch and Quit lines. 
    for files in os.listdir("."):
        if files.endswith(".docx"):
            out_name = files.replace(file_type, r"pdf")
            in_file = os.path.abspath(folder + "\\" + files)
            out_file = os.path.abspath(out_folder + "\\" + out_name)
            doc = word.Documents.Open(in_file)
            print 'Exporting', out_file
            doc.SaveAs(out_file, FileFormat=17)
            doc.Close()

    word.Quit()

except Exception, e:

注意:在打开win32com实例和文件时使用try/except要小心,如果在关闭之前出现错误,它将不会关闭(因为它还没有达到那个命令)。
此外,您可能希望考虑使用DispatchEx而不仅仅是Dispatch。DispatchEx打开一个新实例(一个全新的.exe),而我相信只使用Dispatch将尝试查找一个打开的实例来依附,但是这方面的文档很模糊。如果确实需要多个实例(例如在一个文件中打开一个文件,在另一个文件中打开另一个文件),请使用DispatchEx。
至于等待,程序应该在需要更多时间时等待那一行,但我不知道。
哦!还可以使用word.Visible = True,如果您想看到实例和文件实际打开(可能有助于直观地看到问题,但在修复后请关闭它,因为它肯定会减慢速度;-))。

搞定了,非常感谢 - 已经在 OP 中添加了代码以反映这些更改。 - James N
嗨 - 我正在尝试做类似的事情 - 当我到达我的 {doc.SaveAs} 版本时,我收到一个“无法访问文件”的异常。 - Hatt
文件路径对于Windows来说太长了吗?https://dev59.com/WHI-5IYBdhLWcg3wZ3UR - Radical Edward
FileFormat 规范在哪里? - Lei Yang
1
@LeiYang 这是有关Word的内容:https://learn.microsoft.com/zh-cn/office/vba/api/word.wdsaveformat - Radical Edward

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