老马的Pdg2Pic好用是好用,但至今也没法批量操作。
如果要一个文件夹一个文件夹的处理,
搞起来也相当麻烦。
于是便萌生了借助Python自动操作Pdg2Pic,以实现批量转换的效果。
相关的代码及思路,可供各位小伙伴们酌情参考~
模块选用:
Python中能够实现自动操作exe模块有很多。
最底层的有pywin32。
高一层的封装模块有winGuiAuto、PyAutoGui、Pywinauto等。
我最终选择的是Pywinauto,理由也很简单。
正如Pywinauto手册中的问答写道:
已经有那么多自动操作exe软件的模块和工具了,为什么还要再创造一个类似的模块呢?
作者答道,其他模块写出来的代码都太复杂了,
我只想创造出一个新的模块,把这些复杂操作过程,尽可能变得简单一些。
如果简单的工具就能满足需求的话,又何必去碰那些更复杂、更底层的模块呢?
经过测试以后,我发现,pywinauto完全能够满足自动操作Pdg2Pic的需求。
禁用格式检查:
Pdg2Pic默认允许格式检查。
这意味这每次选择好输入的PDG文件夹后,都会自动弹出一个窗口,汇报格式检查的结果。
如果保持允许的话,又要添加额外的代码处理这个窗口;而且还会增加整个调用过程的不稳定性。
所以干脆就把它给禁了。
关闭格式检查的方式我发现有两种:
其一,不勾选软件窗口中的自动统计:
其二,修改Pdg2Pic.ini文件中的参数:
只要将PARA_AUTO_CHK的值修改为0,软件启动后,自动统计就不会被勾选选上。
为了保持整个调用过程的稳定性,我选择了第二种方式,
在软件启动前就先修改PARA_AUTO_CHK参数:
# 修改ini文件,不需要确认格式
with open('.\\Pdg2Pic\\Pdg2Pic.ini', 'a', encoding='UTF-16') as f: # 防止ini文件缺失
pass
contents = ['[ParaBlock]\n', 'PARA_AUTO_CHK=0']
with open('.\\Pdg2Pic\\Pdg2Pic.ini', 'w', encoding='UTF-16') as f: # 禁用格式检查
for i in contents:
f.write(i)
软件启动:
软件启动的代码很简单。
如果是64位python的话,还可以选择忽略pywinauto32位Python要求的警告。
还可以选择添加相应的等待代码,等到窗口达到相应要求后,再进行操作。
from warnings import filterwarnings
from pywinauto.application import Application
# 忽略32位python的警告
filterwarnings('ignore')
# 启动软件并设置焦点
app = Application().start('.\\Pdg2Pic\\Pdg2Pic.exe')
win = app.window(title='Pdg2Pic', class_name='#32770')
win.wait("ready", timeout=40, retry_interval=0.1)
win.set_focus()
转换成PDF:
如果是需要直接将PDG文件夹转换成PDF,
也可以添加相应的代码,提前把“或转换出来的PDF文件”选项先勾选上:
button2pdf = win.child_window(title='或转换出来的PDF文件:', class_name="Button")
button2pdf.wait("enabled", timeout=10, retry_interval=0.1) # 确认按钮可点击
button2pdf.click()
选择PDG文件夹:
要想将PDG文件夹的路径传入老马的软件中,根据我的观察,主要有三种方式:
其一,将文件夹直接拖入Pdg2Pic中。
其二,点击打开“选择存放PDG文件的文件夹”新窗口,然后赶在确定按钮锁定前,完成填充路径并点击确定的步骤。
其三,通过选择源文件夹窗口选择:
第一种方法要模拟整个拖入过程,殊为不易。
第三种方法要通过选择选择源文件夹窗口选择,因为每个人的窗口内的文件夹布局不同,保存PDG文件夹的位置也不同,具体要实现起来,非常非常复杂,可以说几无可能。
所以只能兵行险招,选择第二种方法,赶在确定按钮锁定之前完成相应操作。
但是这仅仅只有1s,甚至还不到1s的时间!
还好是机器,如果是手动操作的话,绝对无法完成。
最终的成果就是这样一段,为了修补各种bug,长得奇怪又复杂的代码:
# 输入路径
for j in range(1, 10):
win.set_focus()
button_input = win.child_window(title='', class_name="Button", found_index=0)
button_input.wait("enabled", timeout=10, retry_interval=0.1) # 确认按钮可点击
button_input.click()
win_temp = app.window(title="选择存放PDG文件的文件夹", class_name="#32770")
judge = win_temp.exists(timeout=15, retry_interval=0.5) # 等待目标窗口出现,每0.5s检查一次,等待15s后则报超时
if judge is False:
# 有可能会出现点击失效,导致窗口没有出现,进而导致窗口超时的bug,所以超时后要重新尝试
print('"选择存放PDG文件的文件夹窗口",超时不存在!')
else:
for i in range(1, 4): # 采用 wait 方法速度太慢, 所以直接用 for 循环了
try:
win_temp_edit = win_temp.child_window(class_name='Edit')
win_temp_edit.set_edit_text(dirpath)
break
except:
pass
click_check = 0
win_temp_button = win_temp.child_window(title="确定", class_name="Button")
if win_temp_button.is_enabled():
try: # 如果检测的时候可以点击,但检测完以后就不能点击了,就会报错
win_temp_button.click()
click_check = 1
except:
win_temp.close()
else:
win_temp.close() # 如果确定按钮因窗口弹出速度太慢而被锁定,则关闭“选择存放PDG文件的文件夹”窗口,重新循环。
# 预防一些极其特殊的bug
input_path = ''
if click_check == 1:
for i in range(1, 5):
Edit_input = win.child_window(class_name="Edit", found_index=0)
if (Edit_input.window_text()).strip() != '':
input_path = 'OK'
break
if input_path == 'OK':
break
else:
judge = win_temp.exists(timeout=1, retry_interval=0.5)
if judge:
win_temp.close()
老马最初,选择PDG文件夹下面的框框是没法输入内容的,所以只能点击旁边的文件夹输入路径。
结果点击旁边的按钮,打开新窗口以后,确定按钮又会极短的时间内自动锁定。
即使输入了正确的PDG文件夹路径,也不会解锁。
从自动调用的角度看,这无疑是Pdg2Pic软件设计上的两大败笔!
PDF保存路径:
传入PDG文件夹路径后,Pdg2Pic软件会自动生成PDF保存路径。
如果对PDF保存路径没什么要求的话,那么默认即可,自然不会有太多问题。
如果需要自定义PDF文件保存路径,那就又需要与很多Bug斗智斗勇了。
然后又是一段长得非常奇怪的代码:
# 输出路径
eidt_check = 0
for i in range(1, 10):
try:
Edit_output = win.child_window(class_name="Edit", found_index=1)
Edit_output.set_focus()
Edit_output.set_text(pdf_save_path)
eidt_check = 1
break
except:
judge = win_temp.exists(timeout=0.2, retry_interval=0.1) # 检查“选择存放PDG文件的文件夹”窗口是否仍然存在, 如果存在的话,应该前面就已经打开了,所以等待时间不宜设置太长,以免影响程序运行效率
if judge == True:
windows = Desktop().windows()
count = []
for window in windows:
task = (window.window_text()).strip()
count.append(task)
count = count.count('Pdg2Pic') # 检查一下 “Pdg2Pic窗口”是否存在
if count == 2: # 说明弹出了报错窗口
print('检测出报错窗口')
for window in windows:
task = (window.window_text()).strip()
if task == 'Pdg2Pic':
# 关于有错误的窗口,还得想办法捕捉错误
if len(window.children()) <= 4: # 3是不出错的窗口,4是有错误的窗口
window.close() # 关闭报错窗口
break
win_temp.close() # 关闭“选择存放PDG文件的文件夹”窗口窗口
break
开始转换:
设置完输入、输出路径后,开始转换的步骤就比较简单了
只需点击“开始转换”按钮即可。
# 点击开始转换按钮
button_start = win.child_window(title='&4、开始转换', class_name="Button")
button_start.wait("enabled", timeout=10, retry_interval=0.5) # 确认按钮可点击
button_start.click()
监测是否完成:
要谈及监测PDF文档是否转换完成的方法,思路可能就比较开放了。
Github上zip2pdf项目的作者,曾尝试通过不断检测能否修改PDF文件夹的文件名,来监测转换是否完成。
如果能够修改的话,说明PDF文件已经转换完成了。
后来作者又说要改用,监测PDF大小是否增加的方法。
如果持续增加,说明转换过程还在持续;如果没有增加,说明转换已完成。
我以前曾经尝试过的一个思路是检测PDF文档,是否有EOF标记。
如果有EOF标记,说明PDF文档已经结尾,即转换完成了。
以上种种方法,都要反复对PDF执行相应操作,监测的准确性、即时性也不强。
后来发现Pdg2Pic会实时显示转换完成的页面,所以干脆就跳出了PDF思路的限制,
采用捕捉窗口中显示的已经完成的页面数值,并将其与页面总数进行对比。
如果两值相等,则说明转换完成。
这种方法判断的精确性较高,速度也很快,所以就得出了这样的代码:
# 监测是否完成
while True:
Static_check = win.child_window(class_name="Static", found_index=7)
Static_text = (Static_check.window_text()).split('/')
try: # 防止速度太快而报错,因为有可能会捕捉到变化的间隙,此时值为None
task = Static_text[0]
done = Static_text[1]
if task == done: # 两值相等也就意味着转换完成
break
except:
pass
等待转换完成或报错窗口:
PDF转换完成后,还需要等待一小会儿才会弹出转换完成的窗口。
如果PDG图片存在相应错误的话,还有可能会弹出报错窗口。
因为转换完成与窗口出现存在一定的时间间隔,所以必须要有一段代码来衔接。
因为主窗口名字叫Pdg2Pic,转换完成或报错窗口的名字也叫做Pdg2Pic。
所以只要监测到有两个名字叫做Pdg2Pic的窗口,就意味着窗口已弹出。
# 等待转换完成或报错窗口
for i in range(1, 1000):
windows = Desktop().windows()
count = []
for window in windows:
task = (window.window_text()).strip()
count.append(task)
count = count.count('Pdg2Pic')
if count == 2:
break
关闭转换完成或报错窗口:
如果不关闭转换完成或报错窗口的话,是没办法再进行其他操作的,
也就没办法再继续转换其他文件夹,实现批量操作了。
为了关闭这两种类型的不同窗口,又要继续处理各种bug:
# 关闭转换完成或报错窗口
for i in range(1, 10):
try:
# 关闭窗口
windows = Desktop().windows() # 刷新窗口
for window in windows:
task = (window.window_text()).strip()
if task == 'Pdg2Pic':
children = window.children()
if len(children) == 3: # 正常窗口是3
window.close()
break
elif len(children) == 4: # 报错窗口是4, 同样采用close的话,会报超时,一直检测不出来
for child in children:
if (child.window_text()).strip() == "否(&N)": # 所以采取了点击否的方式来关闭
child.click()
break
break
# 再次检测
windows = Desktop().windows() # 刷新窗口
count = []
for window in windows:
task = (window.window_text()).strip()
count.append(task)
count = count.count('Pdg2Pic')
if count == 1: # 只有一个窗口的时候,放行
break
except Exception as e:
print(e)
完整Python代码:
from pywinauto import Desktop
from pywinauto.application import Application
# 修改ini文件,不需要确认格式
with open('.\\Pdg2Pic\\Pdg2Pic.ini', 'a', encoding='UTF-16') as f: # 防止ini文件缺失
pass
contents = ['[ParaBlock]\n', 'PARA_AUTO_CHK=0']
with open('.\\Pdg2Pic\\Pdg2Pic.ini', 'w', encoding='UTF-16') as f: # 禁用格式检查
for i in contents:
f.write(i)
# 忽略32位python的警告
filterwarnings('ignore')
# 启动软件并设置焦点
app = Application().start('.\\Pdg2Pic\\Pdg2Pic.exe')
win = app.window(title='Pdg2Pic', class_name='#32770')
win.wait("ready", timeout=40, retry_interval=0.1) # 等待句柄出现
win.set_focus()
# 点击转成PDF按钮
button2pdf = win.child_window(title='或转换出来的PDF文件:', class_name="Button")
button2pdf.wait("enabled", timeout=10, retry_interval=0.1) # 确认按钮可点击
button2pdf.click()
# 开始逐个处理加密PDG文件夹
for horse in horses:
dirpath = horse[0]
pdf_save_path = horse[2]
# 输入、输出路径
for x in range(1, 5):
# 输入路径
for j in range(1, 10):
win.set_focus()
button_input = win.child_window(title='', class_name="Button", found_index=0)
button_input.wait("enabled", timeout=10, retry_interval=0.1) # 确认按钮可点击
button_input.click()
win_temp = app.window(title="选择存放PDG文件的文件夹", class_name="#32770")
judge = win_temp.exists(timeout=15, retry_interval=0.5) # 等待目标窗口出现,每0.5s检查一次,等待15s后则报超时
if judge is False:
# 有可能会出现点击失效,导致窗口没有出现,进而导致窗口超时的bug,所以超时后要重新尝试
print('"选择存放PDG文件的文件夹窗口",超时不存在!')
else:
for i in range(1, 4): # 采用 wait 方法速度太慢, 所以直接用 for 循环了
try:
win_temp_edit = win_temp.child_window(class_name='Edit')
win_temp_edit.set_edit_text(dirpath)
break
except:
pass
click_check = 0
win_temp_button = win_temp.child_window(title="确定", class_name="Button")
if win_temp_button.is_enabled():
try: # 如果检测的时候可以点击,但检测完以后就不能点击了,就会报错
win_temp_button.click()
click_check = 1
except:
win_temp.close()
else:
win_temp.close() # 如果确定按钮因窗口弹出速度太慢而被锁定,则关闭“选择存放PDG文件的文件夹”窗口,重新循环。
# 预防一些极其特殊的bug
input_path = ''
if click_check == 1:
for i in range(1, 5):
Edit_input = win.child_window(class_name="Edit", found_index=0)
if (Edit_input.window_text()).strip() != '':
input_path = 'OK'
break
if input_path == 'OK':
break
else:
judge = win_temp.exists(timeout=1, retry_interval=0.5)
if judge:
win_temp.close()
# 输出路径
eidt_check = 0
for i in range(1, 10): # 这个控件因为速度太快,老是存在问题,所以要多设一些
try:
Edit_output = win.child_window(class_name="Edit", found_index=1)
Edit_output.set_focus()
Edit_output.set_text(pdf_save_path)
eidt_check = 1
break
except:
judge = win_temp.exists(timeout=0.2,
retry_interval=0.1) # 检查“选择存放PDG文件的文件夹”窗口是否仍然存在, 如果存在的话,应该前面就已经打开了,所以等待时间不宜设置太长,以免影响程序运行效率
if judge == True:
windows = Desktop().windows()
count = []
for window in windows:
task = (window.window_text()).strip()
count.append(task)
count = count.count('Pdg2Pic') # 检查一下 “Pdg2Pic窗口”是否存在
if count == 2: # 说明弹出了报错窗口
print('检测出报错窗口')
for window in windows:
task = (window.window_text()).strip()
if task == 'Pdg2Pic':
# 关于有错误的窗口,还得想办法捕捉错误
if len(window.children()) <= 4: # 3是不出错的窗口,4是有错误的窗口
window.close() # 关闭报错窗口
break
win_temp.close() # 关闭“选择存放PDG文件的文件夹”窗口窗口
break
if eidt_check == 1:
break
# 点击开始转换
button_start = win.child_window(title='&4、开始转换', class_name="Button")
button_start.wait("enabled", timeout=10, retry_interval=0.5) # 确认按钮可点击
button_start.click()
# 监测是否完成
while True:
Static_check = win.child_window(class_name="Static", found_index=7)
Static_text = (Static_check.window_text()).split('/')
try: # 防止速度太快而报错,因为有可能会捕捉到变化的间隙,此时值为0
task = Static_text[0]
done = Static_text[1]
if task == done: # 两值相等也就意味着转换完成
break
except:
pass
# 等待转换完成或报错窗口
for i in range(1, 1000):
windows = Desktop().windows()
count = []
for window in windows:
task = (window.window_text()).strip()
count.append(task)
count = count.count('Pdg2Pic')
if count == 2:
break
# 关闭转换完成或报错窗口
for i in range(1, 10):
try:
# 关闭窗口
windows = Desktop().windows() # 刷新窗口
for window in windows:
task = (window.window_text()).strip()
if task == 'Pdg2Pic':
children = window.children()
if len(children) == 3: # 正常窗口是3
window.close()
break
elif len(children) == 4: # 报错窗口是4, 同样采用close的话,会报超时,一直检测不出来
for child in children:
if (child.window_text()).strip() == "否(&N)": # 所以采取了点击否的方式来关闭
child.click()
break
break
# 再次检测
windows = Desktop().windows() # 刷新窗口
count = []
for window in windows:
task = (window.window_text()).strip()
count.append(task)
count = count.count('Pdg2Pic')
if count == 1: # 只有一个窗口的时候,放行
break
except Exception as e:
print(e)
print('\033[92m' + f'{basename(horse[1])} 转换成功,保存路径为: {pdf_save_path}' + '\033[0m\n')
app.kill()
这样操作Pdg2Pic软件,还是太复杂、太累了。
真心希望老马,能够出个可以批量操作的Pdg2Pic软件。
但更为便利的方法是出个命令行工具之类的,即使不开源,有个命令行工具的话,调用起来也会简单很多~
以上就是“漫谈如何通过Python自动调用Pdg2Pic?”的全部内容,希望对你有所帮助。
关于Python技术储备
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
三、Python视频合集
观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
四、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
五、Python练习题
检查学习结果。
六、面试资料
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
最后祝大家天天进步!!
上面这份完整版的Python全套学习资料已经上传至CSDN官方,朋友如果需要可以直接微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】。