暑假的第二个月初正好去打了2天的暑假工。
说是暑假工,其实是打字员。
看文件,然后录入文件的信息,太多重复的东西。
正常一套录入需要大概一分钟。
选择关键字过滤。 填写,下拉框吧啦吧啦。
还要找到图片上传。真的麻烦。
实在是受不了了。
于是打算写个自动化填写。
仔细看了一下url: 省略/super/Framework_checkLogin.jspx
jsp…嘻嘻。
很早的时候尝试过layui来写过某个项目,但是大概是啥忘了。
前端也是或多或少的了解。
毕竟是gov的东西。不是太敢做一些骚操作。
但是自动化填写。觉得不会太容易实现。第一个想法便是ocr加servlet。
思路很明确。ocr扫描图片,获取每一个关键字。通过servlet请求,登陆,输入等一系列黑框处理。
但是。
不是很应景,这个这么潦草的字(这个图不算潦草,潦草的比比皆是)
,
通过,阿里云,百度,腾讯的ocr api。
什么都没扫出来,但是还是得夸夸腾讯,百度的写了,高精度文字api,通用文字api。等等
腾讯只要文字扫描。
叮,腾讯还能识别出建成时间。房屋地点。百度凉凉。
其实也不是不可以扫描出来。可以自己弄个机器学习一波,从零开始根据开源案例。让机器学会潦草的字。只是不是太想了。
还是选择浏览器自动处理把。
通过查找。最后找到我想要的。
进入本文的话题。
用java还是python的选择,我最后选了java
虽然python写得短实现是真的快。
但是那总方式的写法依旧不习惯。但是如果拿来爬url的数据还是分析下载东西是真真的方便!这个必须力荐python。
老样子,这个玩意应该不需要任何框架。
就算不需要任何框架,还是需要maven的。毕竟如果要让我打lib dependencies?累了
先创建一个空的maven工程。
加入seleniumhq的 dependency
org.seleniumhq.selenium
selenium-api
3.141.59
org.seleniumhq.selenium
selenium-chrome-driver
3.141.59
commons-httpclient
commons-httpclient
3.1
再加一个httpclient 万一会用到
src-main-java 创建一个java文件
以下是我的整个工程。(已经完成后的)
我用的是chrome浏览器。
seleniumhq,需要对应浏览器的driver来运行。
所以需要下载相应的driver
chromedriver与chrome的对应表
chromedriver版本 | 支持的Chrome版本 |
---|---|
v2.46 | v71-73 |
v2.44 | v70-72 |
v2.43 | v69-71 |
v2.42 | v69-70 |
v2.41 | v67-69 |
v2.40 | v66-68 |
v2.39 | v66-68 |
v2.38 | v65-67 |
v2.37 | v64-66 |
v2.36 | v63-65 |
v2.35 | v62-64 |
v2.34 | v61-63 |
v2.33 | v60-62 |
v2.32 | v59-61 |
v2.31 | v58-60 |
v2.30 | v58-60 |
v2.29 | v56-58 |
v2.28 | v55-57 |
v2.27 | v54-56 |
v2.26 | v53-55 |
v2.25 | v53-55 |
v2.24 | v52-54 |
v2.23 | v51-53 |
v2.22 | v49-52 |
v2.21 | v46-50 |
driver可以去下面选择下载
Google
阿里
(谷歌进不去就阿里的)
先import
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
这是目前可以用到的
开始。
System.setProperty("webdriver.chrome.driver","E:\\webDriver\\chromedriver.exe");
WebDriver driver =new ChromeDriver();
driver.get("http://220.160.52.164:9085");
这个只是我当时工作用的地址,后期这个地址应该会被dns反向解析。
输入密码和账号
driver.findElement(By.id("loginname")).sendKeys("------");
driver.findElement(By.id("loginpwd")).sendKeys("-----");
这里账号密码用—代替了哈。
findElement()是seleniumhq常用的函数。
里面By.id是通过id来找到元素
findElement里面的参数有如下
场景简单我建议用id。
id嘛,很容易找打的。
何为场景简单呢?我们来分析一下这个网站。
按F12
里面的元素标签很少对不对。
单纯看网站也能感觉到。
chrome有一个很方便的方法找到元素
点击这个箭头。接着用鼠标去点你想要定位的元素。
如此,我们得到了“输入用户名”这个元素的定位。
id为"loginname"
于是
driver.findElement(By.id(“loginname”)).sendKeys("------");
sendkeys便是我们想要在输入框中填入的参数。
它便会自动填入 -----
处理验证码和点击登陆按钮
System.out.println("请输入验证码");
Scanner sc=new Scanner(System.in);
String code=sc.nextLine();
driver.findElement(By.id("checkCode")).sendKeys(code);
driver.findElement(By.id("login")).click();
验证码的处理很简单。
可以使用ocr,来处理验证码的图片转化成,然后我们写入。
可以使用使用Tess4J进行ocr识别。
github有很多开源代码。下载编译即用。
但是Tess4j的使用麻烦,需要下好它的自带部件。详细可以去查。
而且Tess4j对中文的识别并不是太优秀。
但是针对纯ascii验证码就够了。
不过出于场景。我们的目的是为了让他里面填写的实现自动化。
验证码自己输入就够了。
我没有太多时间去测试和写这个ocr实现。
driver.findElement(By.xpath("//span[text()=\"房屋登记\"]")).click();
driver.findElement(By.xpath("//span[text()=\"登记管理\"]")).click();
这里使用了By.xpath
xpath特别特别好用。对应复杂场景用xpath。
这里的场景,是十分的复杂的。
分析:
他的前端基于layui。
标签使用 另一个页面
正好目前还在测试的项目没关掉。
这个项目基于thymeleaf模板
所以写法是如此。
引用了另一个标签页
也就是会出现标签。
里面可能会出现多个id重复。
如此。需要xpath定位。
xpath很简单。理解dom结果大致就随意能看懂。
“//span[text()=“登记管理”]”
这个意思是找到 标签里的text值未“登记管理”的元素
.click为点击
如此,seleniumhq帮我们完成了这两个按钮的点击。
内嵌标签的寻找
这里是一个重点,我找了半个小时的bug
//点击frame
driver.findElement(By.xpath("//*[@id=\"mainFrameBody\"]/div/div[2]/ul/li[2]/span")).click();
//定位frame,
driver.switchTo().frame(driver.findElement(By.xpath("//*[@id=\"mainFrameBody\"]/div/div[2]/div/div[2]/iframe")));
因为我们点击了登记管理后。
frame出现了新的标签页
所以。
-第一句
driver.findElement(By.xpath("//*[@id=“mainFrameBody”]/div/div[2]/ul/li[2]/span")).click();
我们先点击我们需要的标签页“登记管理"也就是上图没有写数字的框。
那xpath的路径是怎么获得的呢?
我肯定不是手打的。
如此,需要借助chrome了。
定位
按右键
copy->copy Xpath
得到
//*[@id=“mainFrameBody”]/div/div[2]/ul/li[2]/span
贴贴到By.xpath中便可。
- 第二句
定位frame
seleniumhq毕竟是一个库,编程并不会太聪明。所以需要让他自己定位到“登记管理”的frame中
使用
driver.switchTo().frame()
找到frame标签。
如果不知道怎么找,可以再到用chrome的那个小箭头点击“登记管理”
自行找到带frame的标签
这个标签教做iframe
移到那个标签上,全局显示了我们想要让他进入的元素。
对了就是他。
copy xpath
driver.switchTo().frame(driver.findElement(By.xpath("//*[@id=“mainFrameBody”]/div/div[2]/div/div[2]/iframe")));
需要让他找到元素的定位才能真正的switch到frame
大功告成
输入关键字
System.out.println("请输入关键字");
String key = sc.nextLine();
String TrueKey = Constant.keyValue + key + Constant.prefix;
//传入关键字
driver.findElement(By.xpath("//*[@id=\"keywords\"]")).sendKeys(TrueKey);
//点击查询
driver.findElement(By.xpath("//*[@id=\"infoform\"]/div/input[5]")).click();
这里的Constant.keyValue 和 Constant.prefix;
是我自己设定的字符串常量。基于写代码的规范。嘻嘻
点击编辑
//回到默认frame再重新回去
driver.switchTo().defaultContent();
Thread.sleep(2);
driver.findElement(By.xpath("//*[@id=\"mainFrameBody\"]/div/div[2]/ul/li[2]/span")).click();
Thread.sleep(2);
driver.switchTo().frame(driver.findElement(By.xpath("//*[@id=\"mainFrameBody\"]/div/div[2]/div/div[2]/iframe")));
Thread.sleep(1000);
//进入编辑,默认第一个
driver.findElement(By.xpath("//*[@id=\"grid\"]/tbody/tr/td[2]/div")).click();
seleniumhq帮我们点击了查询后又会默默的变傻掉。
丢失了自己的位置,所以需要回到默认的全局页面。
使用driver.switchTo().defaultContent();
开个玩笑。
其实是点击后页面会重新请求,毕竟这个是重定向了。
如果只是简单的javascript事件就不需要。
重新使用
driver.findElement(By.xpath("//*[@id=\"mainFrameBody\"]/div/div[2]/ul/li[2]/span")).click();
driver.switchTo().frame(driver.findElement(By.xpath("//*[@id=\"mainFrameBody\"]/div/div[2]/div/div[2]/iframe")));
这两个步骤回到“登记管理”
中间穿插的Thread.sleep(2),
控制它不会因为光速点击导致自己请求失败。
注意:
driver.findElement(By.xpath("//[@id=“grid”]/tbody/tr/td[2]/div")).click();
这里的编辑按钮我们使用点击div来寻找的。
自行分析一下。
如果我们用的是
//[@id=“grid”]/tbody/tr/td[2]/div/a
这里的a标签里面的地址是动态变化的。
所以正常定位不到,但是我们点击了div标签同理能点击到“编辑”按钮
如此,我们点击了“编辑”这个按钮。
填写信息
这里的代码就不怎么详细贴出来了
但是我贴一下处理选项框的代码
System.out.print("排查人:");
String paiName = sc.nextLine();
System.out.print("排查日期:");
String paiTime = sc.nextLine();
//开始默认处理
//房屋类别
driver.findElement(By.xpath("//*[@id=\"fwlb\"]")).click();
driver.findElement(By.xpath("//*[@id=\"fwlb\"]/option[3]")).click();
自动点击选项框,并且点击选项框内嵌标签的option[?]
图片导入
WebElement webElement = driver.findElement(By.cssSelector("body"));
webElement.click(); // 有的时候必须点击一下,下拉才能生效(有的网站是这样,原因未找到)
webElement.sendKeys(Keys.END);
//传送文件
driver.findElement(By.xpath("//*[@id=\"pcbg_upload\"]/div[2]/input")).sendKeys(Constant.arrayList.get(flag));
webElement.click(); // 有的时候必须点击一下,下拉才能生效(有的网站是这样,原因未找到)
webElement.sendKeys(Keys.UP);
代码注释已经很清除了。
这里用到了WebElement
能帮我们做出一些鼠标键盘的动作。
看一下图片的元素
div id=“”此处为动态生成的id
如果直接copy xpath会出现如下
//*[@id=“rt_rt_1dhbadv8ggdulh4af71prl1t561”]/input
ummmmmm,自己写xpath咯
pcbg_upload"]/div[2]/input 没毛病。
Constant.arrayList.get(flag)这个是我图片的路径传入的ArrayList。
随便写个循环遍历目录里的图片就行
重新填写一遍
再次回到上个登记管理的页面
写个循环,没有难度。
这里有个重点。
driver.navigate().refresh();
我们刷新了页面一遍。
有session,不怕重新再登陆一次。
然后再次从最开始的
driver.findElement(By.xpath("//span[text()=\"房屋登记\"]")).click();
driver.findElement(By.xpath("//span[text()=\"登记管理\"]")).click();
开始一遍。
小结
那时候从下午6点开始写到晚上1点才写完这个自动化处理。
最后这个离开这个暑假工了。
毕竟还是得敲文档得字,对照。
其实如果我自己写个机器学习让他辨认那个文件的字应该就好多了。可是没时间学习了。
但是或多或少的学会了selenium的用法
可以运用再大学时的挂课上,还是一些烦琐的录入情况。
当然,配合ocr api无敌。
源码
Github
后续
我辞职后第2天被他们hr叫去帮忙做网站。(挠头)