文件夹中获取需要转换的文件数,将其全部转换或可单独转换单个文件,并获取转成PDF的文件页数,具体实现如下:
用到的库:os,sys,pdfplumber,client22,pythoncom
库的安装方法:pip install pythoncom
代码:
# import pdfplumber
import os
import sys
import pdfplumber
from client22 import dynamic
import pythoncom
def __WrapDispatch(dispatch, userName = None, resultCLSID = None, typeinfo = None, \
UnicodeToString=None, clsctx = pythoncom.CLSCTX_SERVER,
WrapperClass = None):
"""
Helper函数返回CLSID的makepy生成类(如果存在的话),否则使用CDispatch进行处理。
"""
assert UnicodeToString is None, "this is deprecated and will go away"
if resultCLSID is None:
try:
typeinfo = dispatch.GetTypeInfo()
if typeinfo is not None: # 有些对象返回空值,有些引发异常。。。
resultCLSID = str(typeinfo.GetTypeAttr()[0])
except (pythoncom.com_error, AttributeError):
pass
if WrapperClass is None: WrapperClass = CDispatch
return dynamic.Dispatch(dispatch, userName, WrapperClass, typeinfo, clsctx=clsctx)
def Dispatch(dispatch, userName = None, resultCLSID = None, typeinfo = None, UnicodeToString=None, clsctx = pythoncom.CLSCTX_SERVER):
"""创建基于调度的COM对象。
"""
assert UnicodeToString is None, "这是不赞成的,将消失"
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
return __WrapDispatch(dispatch, userName, resultCLSID, typeinfo, clsctx=clsctx)
class CDispatch(dynamic.CDispatch):
"""
作为最后手段使用的动态类。重写dynamic.CDispatch的目的是使策略永久化
使用makepy生成的包装器Python类而不是dynamic.CDispatch如果可能的话。
"""
def _wrap_dispatch_(self, ob, userName = None, returnCLSID = None, UnicodeToString=None):
assert UnicodeToString is None, "this is deprecated and will go away"
return Dispatch(ob, userName, returnCLSID,None)
class Constants:
"""生成的COM常量的容器。
"""
def __init__(self):
self.__dicts__ = [] # A list of dictionaries
def __getattr__(self, a):
for d in self.__dicts__:
if a in d:
return d[a]
raise AttributeError(a)
# And create an instance.
constants = Constants()
class PDFConverter: #在类中,将word,excel,ppt文件路径、pdf文件路径和word,excel,ppt后台进程实例作为类的属性。
def __init__(self, pathname, export='.'):
self._handle_postfix = ['doc','docx','xls','xlsx','pptx','ppt'] #处理文件后缀的list
self._filename_list = list() #list()是将元组转换成list,元组的元素值不能修改
self._export_folder = os.path.join(os.path.abspath('.'), 'pdfconver') #将转换成pdf的文件放到这个路径中,.os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略。
if not os.path.exists(self._export_folder): #如果文件夹存在,返回True;如果path不存在,返回False。
os.mkdir(self._export_folder) #创建目录的路径,自动创建C:\xxx\xxx\pdfconver的文件夹
self._enumerate_filename(pathname) #调用函数
def _enumerate_filename(self, pathname):
'''
读取所有文件名
'''
full_pathname = os.path.abspath(pathname) #返回path规范化的绝对路径
if os.path.isfile(full_pathname): #如果full_pathname是一个存在的文件,返回True。否则返回False。
if self._is_legal_postfix(full_pathname): #如果是合法的后缀
self._filename_list.append(full_pathname) #将文件添加到文件名list中
else:
raise TypeError('文件 {} 后缀名不合法!仅支持如下文件类型:{}。'.format(pathname, '、'.join(self._handle_postfix)))
elif os.path.isdir(full_pathname): #如果full_pathname是一个存在的目录,则返回True。否则返回False。
for relpath, _, files in os.walk(full_pathname): #遍历文件、目录
for name in files:
filename = os.path.join(full_pathname, relpath, name) #将目录、文件、名字组合成一个路径
if self._is_legal_postfix(filename): #判断文件名的后缀是否合法
self._filename_list.append(os.path.join(filename))
else:
raise TypeError('文件/文件夹 {} 不存在或不合法!'.format(pathname))
def _is_legal_postfix(self, filename):
return filename.split('.')[-1].lower() in self._handle_postfix and not os.path.basename(filename).startswith('~')
def run_conver(self):
'''
进行批量处理,根据后缀名调用函数执行转换
'''
print('需要转换的文件数:', len(self._filename_list))
for filename in self._filename_list:
postfix = filename.split('.')[-1].lower() #split()分隔符对字符串进行切片,分割次数,默认为 -1, 即分隔所有,lower() 将所有大写都转换成小写
funcCall = getattr(self, postfix) #返回对象的属性值
print('原文件:', filename)
funcCall(filename)
print('转换完成!')
def doc(self, filename):
'''
doc 和 docx 文件转换
'''
try:
name = os.path.basename(filename).split('.')[0] + '.pdf' # 返回filename最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素。
exportfile = os.path.join(self._export_folder, name) #将多个路径组合在一起
print('保存 PDF 文件:', exportfile)
w = Dispatch("Word.Application") #首先使用dispatch函数创建一个word程序的后台进程,默认是不显示,只在后台处理。
doc = w.Documents.Open(filename) #Documents.Open函数打开word文件,返回一个文件对象
doc.ExportAsFixedFormat(exportfile, 17)
except Exception as e:
print("转换异常,异常1为:{}".format(e))
finally: #关闭打开的word后台进程。
w.Quit()
def docx(self, filename):
self.doc(filename)
def xls(self, filename):
'''
xls 和 xlsx 文件转换
'''
try:
name = os.path.basename(filename).split('.')[0] + '.pdf'
exportfile = os.path.join(self._export_folder, name)
# xlApp = DispatchEx("Excel.Application") #创建一个新的Excel进程
xlApp = Dispatch("Excel.Application") #,初始化,试图寻找并复用一个已有的Excel进程(比如你已经在运行着的Excel程序)
xlApp.Visible = True #excel可编辑的窗口不可见
xlApp.DisplayAlerts = False #属性关闭,Excel就不会弹出确认窗,而是直接覆盖同名文件。
books = xlApp.Workbooks.Open(filename,False)
books.ExportAsFixedFormat(0, exportfile) #调用文件对象的ExportAsFixedFormat函数将文件内容输出
books.Close(False)
print('保存 PDF 文件:', exportfile)
f = pdfplumber.open(exportfile) #打开pdf文件
page = len(f.pages) #pdf的页数
print("文件",filename,"的页数为:",page)
except Exception as e:
print("转换异常,异常2为:{}".format(e))
finally: #关闭打开excel的后台进程。
xlApp.Quit()
def xlsx(self, filename):
self.xls(filename)
def ppt(self, filename):
'''
ppt 和 pptx 文件转换
'''
try:
name = os.path.basename(filename).split('.')[0] + '.pdf'
exportfile = os.path.join(self._export_folder, name)
p = Dispatch("PowerPoint.Application") #创建一个ppt程序的后台进程,默认是不显示,只在后台处理。
ppt = p.Presentations.Open(filename, False, False, False)
ppt.ExportAsFixedFormat(exportfile, 2, PrintRange=None) #导出固定格式
print('保存 PDF 文件:', exportfile)
f = pdfplumber.open(exportfile) #打开pdf文件
page = len(f.pages) #pdf的页数
print("文件",filename,"的页数为:",page)
except Exception as e:
print("转换异常,异常3为:{}".format(e))
finally: #关闭打开的ppt后台进程。
p.Quit()
def pptx(self, filename):
self.ppt(filename)
if __name__ == "__main__":
# 文件夹批量导入转换
# folder = 'Desktop\py\office'
# pathname = os.path.join(os.path.abspath('.'), folder)
# 单个文件的转换
pathname = "C:/Users/Weibo/Desktop/12.pptx"
pdfConverter = PDFConverter(pathname)
pdfConverter.run_conver()
实现效果:
参考文献:https://blog.csdn.net/XnCSD/article/details/85208303?depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1&utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1