今天下载了一个英文pdf书籍,但书签全是大写英文字母,看上去有点别扭,于是想办法用自动化重命名pdf书签,
使书签全部变成首字母大写。
pdf原始书签如下图:
重命名后的pdf书签
自动化动态效果图,两三分钟完成重命名工作。
下面介绍下自动化过程。
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右键菜单获取有问题。