漫谈如何通过Python自动调用Pdg2Pic?

老马的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]
', '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]
', '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('33[92m' + f'{basename(horse[1])} 转换成功,保存路径为: {pdf_save_path}' + '33[0m
')
app.kill()

这样操作Pdg2Pic软件,还是太复杂、太累了。

真心希望老马,能够出个可以批量操作的Pdg2Pic软件。

但更为便利的方法是出个命令行工具之类的,即使不开源,有个命令行工具的话,调用起来也会简单很多~

以上就是“漫谈如何通过Python自动调用Pdg2Pic?”的全部内容,希望对你有所帮助。
?
?关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

在这里插入图片描述

二、Python必备开发工具

img

三、Python视频合集

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

五、Python练习题

检查学习结果。

img

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

img

最后祝大家天天进步!!

上面这份完整版的Python全套学习资料已经上传至CSDN官方,朋友如果需要可以直接微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】。