zoukankan      html  css  js  c++  java
  • 使用uiautomation自动化重命名pdf书签,使全大写字母变成首字母大写

    今天下载了一个英文pdf书籍,但书签全是大写英文字母,看上去有点别扭,于是想办法用自动化重命名pdf书签,

    使书签全部变成首字母大写。

    pdf原始书签如下图:

    pdf原始书签

    重命名后的pdf书签

    重命名后pdf书签

    自动化动态效果图,两三分钟完成重命名工作。

    gif动画

    下面介绍下自动化过程。

    uiautomation是我封装的python调用UIAutomation的module,参考 http://www.cnblogs.com/Yinkaisheng/p/3444132.html

    运行automation.py -h查看帮助

    先使用automation.py -a 获取pdf书签树控件的层次结构,-a参数 是获取光标下的控件,并一直获取父控件直到顶层窗口

    在cmd里输入automation.py -a回车后,马上把鼠标移到pdf书签上,3秒后,将打印出控件树

    再用此方法获取右键pdf书签右键菜单的控件树层次结构。

    最后代码如下:

    #!python3
    # -*- coding: utf-8 -*-
    # rename pdf bookmarks with FoxitReader 6.2.3
    import time
    import string
    import automation
    
    TreeDepth = 2 #书签树只有前两层需要重命名
    UpperWords = {
        'amd': 'AMD',
        'arp': 'ARP',
        'dhcp': 'DHCP',
        'dns': 'DNS',
        'ip': 'IP',
        'mac': 'MAC',
        'unix': 'UNIX',
        'pc': 'PC',
        'pcs': 'PCs',
        'tcp': 'TCP',
        'tcp/ip': 'TCP/IP',
        'vs': 'VS',
        }
    LowerWords = ['a', 'an', 'and', 'at', 'for', 'in', 'of', 'the', 'to']
    
    
    class BookMark():
        def __init__(self, name, newName):
            self.name = name
            self.newName = newName
            self.children = []
    
    def main():
        window = automation.WindowControl(searchDepth= 1, ClassName= 'classFoxitReader')
        window.SetActive()
        time.sleep(1)
        tree = automation.TreeControl(searchFromControl= window, ClassName= 'SysTreeView32')
        childItems = tree.GetChildren()
        bookMarks = []
        depth = 1
        for treeItem in childItems:
            if treeItem.ControlType == automation.ControlType.TreeItemControl:
                RenameTreeItem(tree, treeItem, bookMarks, depth)
        fout = open('rename_pdf_bookmark.txt', 'wt', encoding= 'utf-8')
        depth = 1
        for bookMark in bookMarks:
            DumpBookMark(fout, bookMark, depth)
        fout.close()
    
    def DumpBookMark(fout, bookMark, depth):
        fout.write(' ' * (depth - 1) * 4 + bookMark.newName + '\n')
        for child in bookMark.children:
            DumpBookMark(fout, child, depth + 1)
    
    def RenameTreeItem(tree, treeItem, bookMarks, depth):
        treeItem.ScrollIntoView()
        if depth > TreeDepth:
            return
        name = treeItem.Name
        newName = Rename(name)
        bookMark = BookMark(name, newName)
        bookMarks.append(bookMark)
        if newName != name:
            treeItem.RightClick()
            # FoxitReader书签右键菜单(BCGPToolBar,非Windows菜单)弹出后,枚举不到菜单,但从屏幕点上ControlFromPoint能获取到菜单, todo
            # 采用特殊处理获取重命名菜单
            time.sleep(0.2)
            x, y = automation.Win32API.GetCursorPos()
            menuItem = automation.ControlFromPoint(x + 2, y + 2)
            if menuItem.ControlType == automation.ControlType.MenuItemControl:
                #鼠标右下方弹出菜单
                while not (menuItem.Name == '重命名(R)' or menuItem.Name == 'Rename'):
                    y += 20
                    menuItem = automation.ControlFromPoint(x + 2, y)
            else:
                #鼠标右上方弹出菜单
                menuItem = automation.ControlFromPoint(x + 2, y - 2)
                while not (menuItem.Name == '重命名(R)' or menuItem.Name == 'Rename'):
                    y -= 20
                    menuItem = automation.ControlFromPoint(x + 2, y)
            menuItem.Click()
            edit = automation.EditControl(searchFromControl= tree, searchDepth= 1)
            edit.SetValue(newName)
            automation.Win32API.SendKeys('{Enter}')
            print('rename "{0}" to "{1}"'.format(name, newName))
        if depth + 1 > TreeDepth:
            return
        treeItem.Expand()
        childItems = treeItem.GetChildren()
        if childItems:
            treeItem.Expand()
            for child in childItems:
                RenameTreeItem(tree, child, bookMark.children, depth + 1)
    
    def Rename(name):
        newName = name.strip().replace('\n', ' ')
        #将CHAPTER 10变成10,删除前置CHAPTER
        if newName.startswith('CHAPTER '):
            newName = newName[len('CHAPTER '):]
        newName = newName.title()
        words = newName.split()
        skipIndex = 1 if words[0][-1].isdigit() else 0
        for i in range(len(words)):
            lowerWord = words[i].lower()
            start_punctuation = ''
            end_punctuation = ''
            if lowerWord[0] in string.punctuation:
                start_punctuation = lowerWord[0]
                lowerWord = lowerWord[1:]
            if lowerWord[-1] in string.punctuation:
                end_punctuation = lowerWord[-1]
                lowerWord = lowerWord[:-1]
            if lowerWord in UpperWords:
                words[i] = start_punctuation + UpperWords[lowerWord] + end_punctuation
                continue
            if i > skipIndex and lowerWord in LowerWords:
                if words[i-1][-1] != ':':
                    words[i] = lowerWord
        newName = ' '.join(words)
        return newName
    
    if __name__ == '__main__':
        main()
        input('\npress enter to exit')
    

      代码可在https://git.oschina.net/yinkaisheng/PythonUIAutomation4Windows 或 GitHub下载

    另外此代码是根据FoxReader6.2.3实现的,其它版本不一定支持。

    还有运行此程序时要关闭迅雷,在测试时发现如果运行了迅雷,会使pdf右键菜单获取有问题。

  • 相关阅读:
    构建工具
    Ajax跨域问题
    Flex 布局教程:语法篇
    Linux常用命令
    JavaScript正则表达式
    jQuery基础(四)动画
    前端面试问题汇总(一)
    jQuery基础(三)事件
    JavaScript中的基本数据类型
    Django积木块二——邮箱
  • 原文地址:https://www.cnblogs.com/Yinkaisheng/p/4820954.html
Copyright © 2011-2022 走看看