某天,张三接到一个任务需求,将一个Excel表格里面的员工信息,录入到员工系统里面,由于数据量非常大,操作起来巨慢。经过一段时间的操作和观察,他发现这种操作,非常有规律,基本就是一些固定操作,无非换一下数据,于是他打算编写一段小程序实现这个功能,这样就能让程序干活,自己轻松一点,而且程序不知道累,只要电脑有电就行。
在手动上传了上百条员工信息后,累的头昏眼花,张三开始了编码实现自动化操作,折腾了半天后,张三实现了Excel数据读取,每一行数据都可以成功读出来,接着程序切换窗口到已经登录的员工系统浏览器页面,准备将读取到的数据,逐个填写到表单里面。
工号 | 姓名 | 性别 | 部门 | 邮箱 | 头像 |
---|---|---|---|---|---|
1001 | 赵一 | 男 | 侍卫 | 1001@m.com | 😃 |
前面手动录入数据的操作,张三总结出了这套操作的规律,按tab键可以在各个输入框和单选框中移动,姓名等文本数据很快就确定好了解决方案,测试代码跑了几次,将读取到的数据顺利的填写到相应的输入框内,或选择合适的单选框。
但是在选择头像的时候遇到了问题,因为要操作选择文件按钮,在本地硬盘选择对应的头像图片文件,选择完成头像图片之后,一系列数据和头像都准备好,提交按钮才会变成可点击状态,按钮颜色由灰色变为蓝色。
找色
通过调用JDK提供的Robot类,填充完所有信息后,获取提交按钮在屏幕坐标的位置的颜色
,判断是否可以点击,如果可以点击,点击提交就可以了。
于是张三编码如下:
void inputEmployee(){
//......
Robot robot = new Robot();
//......
//......填写各种信息
//获取按钮坐标位置的颜色
Color color = robot.getPixelColor(812, 670);
int getColor = color.getRGB() & 0x00ffffff;
int btnColor = 0x007bff;
if (getColor == btnColor) {
System.out.println("按钮可点击");
robot.delay(300);
//点击提交按钮
robot.mouseMove(812, 670);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
} else {
System.out.println("按钮不可点击");
}
}
运行后测试了几次,效果不错。现在程序读取数据后自己逐个填写员工信息,最后点击提交,2秒后开始下一条数据的填写和提交。
找图
程序运行了一段时间,张三发现在提交数据出现异常的情况,程序还在孜孜不倦的工作,这种情况问题很严重,容易遗漏数据。
目前由于失败的情况比较复杂,临时人工处理一下,程序遇到提交失败先暂停,人工处理后再开始下一条。接下来得让程序判断提交结果是否成功,如果成功自动开始填写下一条员工信息。
经过观察,提交成功会显示一个绿色小图标的成功提示,失败会显示一个红色小图标的错误提示。张三于是截取了一个包含成功提示的小图片,用微软画图mspaint简单去除了一下边缘空白,保存为一张png图片。接下来编写程序,在屏幕截图中查找这张小图片
,如果查找到,就认为提交数据成功了,接着开始下一条数据的填写提交。
接下来,张三编码如下
boolean findSuccess(){
boolean found = false;
try {
// 加载小图
BufferedImage smallImage = javax.imageio.ImageIO.read(new java.io.File("toast_ok.png"));
Robot robot = new Robot();
for (int i = 0; i < 8; i++) {
robot.delay(200);
Rectangle screenRect = new Rectangle(java.awt.Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage screenShot = robot.createScreenCapture(screenRect);
// 这里将屏幕截图保存为文件,方便查看结果
//javax.imageio.ImageIO.write(screenShot, "png", new java.io.File("screenshot6.png"));
found = searchForImage(screenShot, smallImage);
}
} catch (AWTException | java.io.IOException e) {
e.printStackTrace();
}
return found;
}
private static void searchForImage(BufferedImage bigImage, BufferedImage smallImage) {
int bigWidth = bigImage.getWidth();
int bigHeight = bigImage.getHeight();
int smallWidth = smallImage.getWidth();
int smallHeight = smallImage.getHeight();
for (int y = 0; y <= bigHeight - smallHeight; y++) {
for (int x = 0; x <= bigWidth - smallWidth; x++) {
if (isSubImageAt(bigImage, smallImage, x, y)) {
System.out.println("小图在大图中的位置:(" + x + ", " + y + ")");
return;
}
}
}
System.out.println("小图未在大图中找到。");
}
private static boolean isSubImageAt(BufferedImage bigImage, BufferedImage smallImage, int x, int y) {
for (int smallY = 0; smallY < smallImage.getHeight(); smallY++) {
for (int smallX = 0; smallX < smallImage.getWidth(); smallX++) {
int bigRGB = bigImage.getRGB(x + smallX, y + smallY);
int smallRGB = smallImage.getRGB(smallX, smallY);
if (bigRGB!= smallRGB) {
return false;
}
}
}
return true;
}
运行测试后接过如下,看来没什么问题
小图未在大图中找到。
小图未在大图中找到。
小图未在大图中找到。
小图未在大图中找到。
小图未在大图中找到。
小图在大图中的位置:(937, 1017)
小图在大图中的位置:(937, 1017)
小图在大图中的位置:(937, 1017)
接下来张三将程序完善了一下,把一些不变的对象提前创建好,避免不必要的对象创建,重新测试后功能正常,将这个逻辑加入后,程序就更稳定了,而且提交出现异常的情况不算多,这样一来,张三就基本实现了程序全自动读取提交员工信息,他自己接了杯茶,一边喝一边看着程序干活,偶尔处理一下失败的异常,非常惬意。
晚上快下班的时候,10000条员工信息终于传完了,还好编写了个程序,不然,这一万条数据得把自己累死,而且今天还干不完。
晚上张三和李四、周五聚餐,说了自己白天编写的程序上传信息的事情,李四询问了下他的实现过程,说:“其实,有一种更为激进的方法,分析一下信息提交的http通信过程,分析几次就能看出所有交互细节,然后直接调用Http相关API进行进行数据提交,协议级别要比操作UI更快。”
周五:“四哥说的对,不过我觉得三哥在模拟UI操作实现的情况下,一天完成这么多数据填写也是难能可贵了。”
李四:“没毛病,服务器那边的吴六请假了,要不然这个功能找他直接读取入库,还要快得多。”
周五:“不过三哥,你为什么不用按键精灵
呢?用它编写这种脚本要方便快捷的多。”
张三:“主要是咱们有要求,软件库没有这种软件,不能使用”
周五:“也对,在条件有限的情况下也只能这样了,不过我听说调用OpenCV进行识图更加准确可靠,还有比如说一些文本识别可以调用一些成熟的OCR库来进行判断,也会更加可靠。”
李四:“你说的对”
三个人又交流了半天技术,李四说:“连上五天班太累了,周末咱们爬山去,锻炼锻炼”,其他两人纷纷同意,相约周末去爬山。