- 内容提要
- 作者简介
- 技术评审者简介
- 致谢
- 译者序 会编程的人不一样
- 前言
- 本书的读者对象
- 编码规范
- 什么是编程
- 本书简介
- 下载和安装 Python
- 启动 IDLE
- 如何寻求帮助
- 聪明地提出编程问题
- 小结
- 第一部分 Python 编程基础
- 第1章 Python 基础
- 第2章 控制流
- 第3章 函数
- 第4章 列表
- 第5章 字典和结构化数据
- 第6章 字符串操作
- 第二部分 自动化任务
- 第7章 模式匹配与正则表达式
- 第8章 读写文件
- 第9章 组织文件
- 第10章 调试
- 第11章 从 Web 抓取信息
- 第12章 处理 Excel 电子表格
- 第13章 处理 PDF 和 Word 文档
- 第14章 处理 CSV 文件和 JSON 数据
- 第15章 保持时间、计划任务和启动程序
- 第16章 发送电子邮件和短信
- 第17章 操作图像
- 第18章 用 GUI 自动化控制键盘和鼠标
- 附录A 安装第三方模块
- 附录B 运行程序
- 附录C 习题答案
18.11 项目:自动填表程序
在所有无聊的任务中,填表是最烦人的。到了现在,在最后一章的项目中,你将搞定它。假设你在电子表格中有大量的数据,必须重复将它输入到另一个应用的表单界面中,没有实习生帮你完成。尽管有些应用有导入功能,让你上传包含信息的电子表格,但有时候似乎没有其他方法,只好不动脑子地点击和输入几个小时。读到了本书的这一章,你“当然”知道会有其他方法。
本项目的表单是 Google Docs 表单,你可以在 http://nostarch.com/automatestuff找到,如图18-4所示。
图18-4 本项目用到的表单
总的来说,你的程序应该做到:
· 点击表单的第一个文本字段。
· 遍历表单,在每个输入栏键入信息。
· 点击Submit按钮。
· 用下一组数据重复这个过程。
这意味着代码需要做下列事情:
· 调用pyautogui.click() 函数,点击表单和Submit按钮。
· 调用pyautogui.typewrite() 函数,在输入栏输入文本。
· 处理KeyboardInterrupt异常,这样用户能按Ctrl-C键退出。
打开一个新的文件编辑器窗口,将它保存为formFiller.py。
第1步:弄清楚步骤
在编写代码之前,你需要弄清楚填写一次表格时,需要的准确击键和鼠标点击。18.4节中的mouseNow.py脚本可以帮助你弄清楚确切的鼠标坐标。你只需要知道第一个文本输入栏的坐标。在点击第一个输入栏之后,你可以Tab键,将焦点移到下一个输入栏。这让你不必弄清楚每一个输入栏的x、y坐标。
下面是在表单中输入数据的步骤:
1.点击Name输入栏(在将浏览器窗口最大化后,用mouseNow.py程序来确定坐标。在OS X上,可能需要点击两次:一次让浏览器获得焦点,第二次让Name输入栏获得焦点)。
2.键入名称,然后按Tab键。
3.键入最大的恐惧(greatest fear),然后按Tab键。
4.按向下键适当的次数,选择魔力源(wizard power source):一次是Wand,两次是Amulet,三次是Crystal ball,四次是money。然后按Tab键(请注意,在OS X中,你必须为每次选择多按一次向下键。对于某些浏览器,你也需要按回车键)。
5.按向右键,选择RoboCop问题的答案。按一次是2,两次是3,三次是4,四次是5,或按空格键选择1(它是默认加亮的)。然后按Tab键。
6.键入附加的备注,然后按Tab键。
7.按回车键,点击“Submit”按钮。
8.在提交表单后,浏览器将转到一个页面。然后你需要点击一个链接,返回到表单页面。
请注意,如果你稍后再次运行这个程序,可能需要更新鼠标点击的坐标,因为浏览器窗口可能已经改变了位置。要避免这一点,请一直确保浏览器窗口最大化,然后再寻找第一个表单输入框的坐标。而且,不同操作系统上的不同浏览器,工作起来可能与这里的步骤稍有不同,所以在运行程序之前,要确保这些击键组合适合你的计算机。
第2步:建立坐标
在浏览器中载入示例表单(图18-4),并将浏览器窗口最大化。打开一个新的终端窗口或命令行窗口,来运行mouseNow.py脚本,然后将鼠标放在输入框上,弄清楚它的x、y坐标。这些数字将赋给程序中的变量。同时,找出蓝色Submit按钮的x、y坐标和RBG值。这些值将分别赋给变量submitButton和submitButtonColor。
接下来,在表单中填入一些假的数据,点击Submit。你需要看到下一个页面的样子,以便使用程序mouseNow.py寻找这个页面中Submit another response链接的坐标。
让你的源代码看起来像下面的样子。确保用自己测试得到的坐标代替斜体的值:
#! python3 # formFiller.py - Automatically fills in the form. import pyautogui, time # Set these to the correct coordinates for your computer. nameField = (648, 319) submitButton = (651, 817) submitButtonColor = (75, 141, 249) submitAnotherLink = (760, 224) # TODO: Give the user a chance to kill the script. # TODO: Wait until the form page has loaded. # TODO: Fill out the Name Field. # TODO: Fill out the Greatest Fear(s) field. # TODO: Fill out the Source of Wizard Powers field. # TODO: Fill out the RoboCop field. # TODO: Fill out the Additional Comments field. # TODO: Click Submit. # TODO: Wait until form page has loaded. # TODO: Click the Submit another response link.
现在你需要实际想要输入这张表格的数据。在真实世界中,这些数据可能来自电子表格、纯文本文件或某个网站。可能需要额外的代码,将数据加载到程序中。但对于这个项目,只需要将这些数据硬编码给一个变量。在程序中加入以下代码:
#! python3 # formFiller.py - Automatically fills in the form. --snip-- formData = [{'name': 'Alice', 'fear': 'eavesdroppers', 'source': 'wand', 'robocop': 4, 'comments': 'Tell Bob I said hi.'}, {'name': 'Bob', 'fear': 'bees', 'source': 'amulet', 'robocop': 4, 'comments': 'n/a'}, {'name': 'Carol', 'fear': 'puppets', 'source': 'crystal ball', 'robocop': 1, 'comments': 'Please take the puppets out of the break room.'}, {'name': 'Alex Murphy', 'fear': 'ED-209', 'source': 'money', 'robocop': 5, 'comments': 'Protect the innocent. Serve the public trust. Uphold the law.'}, ] --snip--
formData列表包含4个字典,针对4个不同的名字。每个字典都有文本字段的名字作为键,响应作为值。最后一点准备是设置pyautogui的PAUSE变量,在每次函数调用后等待半秒钟。在程序的formData赋值语句后,添加下面的代码:
pyautogui.PAUSE = 0.5
第3步:开始键入数据
for循环将迭代formData列表中的每个字典,将字典中的值传递给pyautogui函数,最后在文本输入区输入。
在程序中添加以下代码:
#! python3 # formFiller.py - Automatically fills in the form. --snip-- for person in formData: # Give the user a chance to kill the script. print('>>> 5 SECOND PAUSE TO LET USER PRESS CTRL-C <<<') ❶ time.sleep(5) # Wait until the form page has loaded. ❷ while not pyautogui.pixelMatchesColor(submitButton[0], submitButton[1], submitButtonColor): time.sleep(0.5) --snip--
作为一个小的安全功能,该脚本有 5 秒暂停❶。如果发现程序在做一些预期之外的事,这让用户有机会按 Ctrl-C(或将鼠标移到屏幕的左上角,触发FailSafeException异常),从而关闭程序。然后程序等待,直到Submit按钮的颜色可见❷,这让程序知道,表单页面已经加载了。回忆一下,你在第2步中已经弄清楚了坐标和颜色信息,并将它们保存在submitButton和submitButtonColor变量中。要调用pixelMatchesColor(),就传递坐标submitButton[0] 和submitButton[1],以及颜色submitButtonColor。
在等待Submit按钮颜色可见的代码之后,添加以下代码:
#! python3 # formFiller.py - Automatically fills in the form. - -snip-- ❶ print('Entering %s info...' % (person['name'])) ❷ pyautogui.click(nameField[0], nameField[1]) # Fill out the Name field. ❸ pyautogui.typewrite(person['name'] + '\t') # Fill out the Greatest Fear(s) field. ❹ pyautogui.typewrite(person['fear'] + '\t') --snip--
我们添加了偶尔的print() 调用,在终端窗口中显示程序的状态,让用户知道进展。❶
既然程序知道表格已经加载,就可以调用click(),点击Name输入框❷,并调用typewrite(),输入person['name'] 中的字符串❸。字符串末尾加上了 '\t' 字符,模拟按下Tab键,它将输入焦点转向下一个输入框,Greatest Fear(s)。另一次typewrite() 调用,将在这个输入框中输入person['fear'] 中的字符串,然后用Tab跳到表格的下一个输入框❹。
第4步:处理选择列表和单选按钮
“wizard powers”问题的下拉菜单和RoboCop字段的单选按钮,处理起来比文本输入框需要更多技巧。要用鼠标点选这些选项,你必须搞清楚每个可能选项的x、y坐标。然而,用箭头键来选择会比较容易。
在程序中加入以下代码:
#! python3 # formFiller.py - Automatically fills in the form. --snip-- # Fill out the Source of Wizard Powers field. ❶ if person['source'] == 'wand': ❷ pyautogui.typewrite(['down', '\t']) elif person['source'] == 'amulet': pyautogui.typewrite(['down', 'down', '\t']) elif person['source'] == 'crystal ball': pyautogui.typewrite(['down', 'down', 'down', '\t']) elif person['source'] == 'money': pyautogui.typewrite(['down', 'down', 'down', 'down', '\t']) # Fill out the RoboCop field. ❸ if person['robocop'] == 1: ❹ pyautogui.typewrite([' ', '\t']) elif person['robocop'] == 2: pyautogui.typewrite(['right', '\t']) elif person['robocop'] == 3: pyautogui.typewrite(['right', 'right', '\t']) elif person['robocop'] == 4: pyautogui.typewrite(['right', 'right', 'right', '\t']) elif person['robocop'] == 5: pyautogui.typewrite(['right', 'right', 'right', 'right', '\t']) --snip--
在下拉菜单获得焦点后(回忆一下,你写了代码,在填充Greatest Fear(s)输入框后模拟了按 Tab 键),按下向下箭头,就会移动到选择列表的下一项。根据person['source'] 中的值,你的程序应该发出几次向下按键,然后再切换到下一个输入区。如果这个用户词典中的 'source' 值是 'wand' ❶,我们模拟按向下键一次(选择Wand),并按Tab键❷。如果 'source' 键的值是 'amulet',模拟按向下键两次,并按Tab键。对其他可能的值也是类似。
RoboCop问题的单选按钮,可以用向右键来选择。或者,如果你想选择第一个选项❸,就按空格键❹。
第5步:提交表单并等待
可以用函数typewrite() 填写备注输入框,将person['comments'] 作为参数。你可以另外输入 '\t',将焦点移到下一个输入框或Submit按钮。当Submit按钮获得焦点后,调用pyautogui.press('enter'),模拟按下回车键,提交表单。在提交表单之后,程序将等待5秒,等下一页加载。
在新页面加载之后,它会有一个Submit another response链接,让浏览器转向一个新的、全空的表单页面。在第二步,你已将这个链接的坐标作为元组保存在submitAnotherLink中,所以将这些坐标传递给pyautogui.click(),点击这个链接。
新的表单准备好后,脚本的外层for循环将继续下一次迭代,在表单中输入下一个人的信息。
添加以下代码,完成你的程序:
#! python3 # formFiller.py - Automatically fills in the form. --snip-- # Fill out the Additional Comments field. pyautogui.typewrite(person['comments'] + '\t') # Click Submit. pyautogui.press('enter') # Wait until form page has loaded. print('Clicked Submit.') time.sleep(5) # Click the Submit another response link. pyautogui.click(submitAnotherLink[0], submitAnotherLink[1])
在主for循环完成后,程序应该已经插入了每个人的信息。在这个例子中,只有4个人要输入。但如果有4000个人,那么编程来完成这个任务将节省大量的输入时间。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论