前几天收到客户3万多个word文件要印刷,为了能拼版,需要先将文件批量转化为PDF,人工肯定是不行,需要写一个自动转化脚本。
原理很简单,就是通过Word.Application接口打开word文件,另存为PDF。我实验一个20页的A4黑白文件转化需要20秒,效率低了一些,所以加入多进程加快速度。
首先,docx2pdf函数负责将docx格式文件转化为PDF:
def docx2pdf(input_file):
"""docx转pdf"""
word = Dispatch('Word.Application')
doc = word.Documents.Open(input_file)
doc.SaveAs(input_file.replace(".docx", ".pdf"), FileFormat=17)
doc.Close()
word.Quit()
源文件中可能混杂有doc和docx两种文件格式,所以有必要先将doc转化为docx:
def doc2docx(doc_name,docx_name):
"""doc转docx"""
try:
# 首先将doc转换成docx
word = client.Dispatch("Word.Application")
doc = word.Documents.Open(doc_name)
#使用参数16表示将doc转换成docx
doc.SaveAs(docx_name,16)
doc.Close()
word.Quit()
except:
pass
遍历文件夹docx文件,由函数find_docs负责:
def find_docs(path):
"""获取文件夹下所有docx文件列表"""
docs= []
for root, dirs, filenames in walk(path):
for file in filenames:
if file.endswith(".doc"):
doc2docx(f"{root}\\{file}",f"{root}\\{file}x")
docs.append(f"{root}\\{file}x")
elif file.endswith(".docx"):
docs.append(f"{root}\\{file}")
docs = list(set(docs)) #去重
# print(docs)
return docs
将这3块代码合并就可以实现多word转PDF了。下面是加入多进程,先看看CPU数量:
from multiprocessing import cpu_count
print("cpu个数:",cpu_count()) #获取CPU个数
多进程要在主函数中完成,为了减少耦合,专门为多进程加了一个worker函数,来调用docx2pdf,实际上可以让多进程直接调用docx2pdf。我电脑是8核的,开了5个进程:
def worker(input_file):
print("{} 开始转化...\n".format(input_file))
docx2pdf(input_file)
print("{} 【转化完成】".format(input_file))
def main(): #多进程必须放在主程序中设置
directory = r"C:\Users\31209\Desktop\新建文件夹"
from multiprocessing import cpu_count
print("cpu个数:",cpu_count()) #获取CPU个数
ps = Pool(5) #设置线程池
docs = find_docs(directory)
if docs !=[]:
print("主进程开始执行:")
for i in docs:
# ps.apply(worker,args=(i,)) # 同步执行
ps.apply_async(worker,args=(i,)) # 异步执行
ps.close() # 关闭进程池,停止接受其它进程
ps.join()# 阻塞进程
print("主进程终止!")
完整代码:
from win32com.client import Dispatch
from os import walk
import os,time
from win32com import client
def doc2docx(doc_name,docx_name):
"""doc转docx"""
try:
# 首先将doc转换成docx
word = client.Dispatch("Word.Application")
doc = word.Documents.Open(doc_name)
#使用参数16表示将doc转换成docx
doc.SaveAs(docx_name,16)
doc.Close()
word.Quit()
except:
pass
def docx2pdf(input_file):
"""docx转pdf"""
word = Dispatch('Word.Application')
doc = word.Documents.Open(input_file)
doc.SaveAs(input_file.replace(".docx", ".pdf"), FileFormat=17)
doc.Close()
word.Quit()
def find_docs(path):
"""获取文件夹下所有docx文件列表"""
docs= []
for root, dirs, filenames in walk(path):
for file in filenames:
if file.endswith(".doc"):
doc2docx(f"{root}\\{file}",f"{root}\\{file}x")
docs.append(f"{root}\\{file}x")
elif file.endswith(".docx"):
docs.append(f"{root}\\{file}")
docs = list(set(docs)) #去重
# print(docs)
return docs
from multiprocessing import Pool
def worker(input_file):
print("{} 开始转化...\n".format(input_file))
docx2pdf(input_file)
print("{} 【转化完成】".format(input_file))
def main(): #多进程必须放在主程序中设置
directory = r"C:\Users\31209\Desktop\新建文件夹"
from multiprocessing import cpu_count
print("cpu个数:",cpu_count()) #获取CPU个数
ps = Pool(5) #设置线程池
docs = find_docs(directory)
if docs !=[]:
print("主进程开始执行:")
for i in docs:
# ps.apply(worker,args=(i,)) # 同步执行
ps.apply_async(worker,args=(i,)) # 异步执行
ps.close() # 关闭进程池,停止接受其它进程
ps.join()# 阻塞进程
print("主进程终止!")
if __name__ == "__main__":
main()
执行效果 :5个文件同时开始,转化完一个自动加入一个新任务