环境
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.27</version>
</dependency>
基本使用
Htmlunit就相当于一个由Java写的一个无界面的浏览器,可以完成浏览器的部分操作。
WebClient webClient = new WebClient();//创建对象
webClient.getOptions().setJavaScriptEnabled(true);// 取消 JS 支持
webClient.getOptions().setCssEnabled(false);// 取消 CSS 支持
webClient.getOptions().setThrowExceptionOnScriptError(false);//运行错误时,不抛出异常
webClient.setAjaxController(new NicelyResynchronizingAjaxController());// 设置Ajax异步
webClient.getOptions().setRedirectEnabled(true);//重定向
webClient.getOptions().setUseInsecureSSL(true);//证书认证
webClient.getCookieManager().setCookiesEnabled(true);//开启cookie管理
以上代码相当于打开了一个浏览器并对它进行一些设置
抓取页面
HtmlPage page = (HtmlPage)webClient.getPage("URL");
System.out.println(page.asXml());
执行js脚本
HtmlPage page = (HtmlPage) webClient.getPage("URL");
ScriptResult result = page.executeJavaScript("myJs()");
page = (HtmlPage) result.getNewPage();
System.out.println(page.asXml());
这样可以获得js执行后的页面。
账号登陆
HtmlElement usernameEle = page.getHtmlElementById("userName");
usernameEle.focus();// 设置输入焦点
usernameEle.type("123");// 填写值
HtmlElement passwordEle = page.getHtmlElementById("passWord");
passwordEle.focus();// 设置输入焦点
passwordEle.type("123");// 填写值
HtmlImage firstByXPath = page.getFirstByXPath("//*[@test='test2']");
firstByXPath.saveAs(new File("test.jpg"));
//百度云验证码识别
String code = Sample.imageToText();
HtmlElement picEle = page.getHtmlElementById("captchCode");
picEle.focus();// 设置输入焦点
picEle.type(code);// 填写值
有些网站登陆会需求验证码,验证码指向了一个地址,但是访问这个地址,对应的验证码图片每次都不同,所以需要在获取到页面后把图片保存下来。一般图片的样式不会有id这些属性,所以需要xpath来完成图片的下载,下发的test指的就是属性名,不如id,class这些,test2就是属性对应的值。
识别验证码可以使用Tesseract或者直接调用百度云的api来识别。第一种对于文字比较规整的验证码识别率还是可以的,百度云的话又几种不同的收费方式,对应的识别效率也不相同,百度云每天都有免费试用次数,可以自行尝试。
HtmlButton btn = page.getFirstByXPath("//*[@class='mybtn']");
page = btn.click();
webClient.waitForBackgroundJavaScript(10000);
System.out.println(page.asXml());
获取按钮,在调用click()方法,即可获取登陆后的页面。但是有时,发现获取到的页面和登陆后的页面不同,并且有“正在加载中”之类的文字,可以设置一下等待js加载的时间。还有一些情况,设置js加载时间也没有办法获取登陆后的页面。那么可以尝试直接用getPage()方法获取登陆后的页面地址,webClient在发送请求时会带上cookie,一般也能获取到登陆后的页面。