使用htmlunit方式模拟页面点击操作
1、准备:高德地图key申请,参考高德地图KEY申请。在高德地图官网找到需要实现的功能代码。这里测试的是“逆向地理编码方法”;
2、pom.xml文件导入相关包:
1 <dependency> 2 <groupId>net.sourceforge.htmlunit</groupId> 3 <artifactId>htmlunit</artifactId> 4 <version>2.23</version> 5 </dependency> 6 <dependency> 7 <groupId>net.sourceforge.htmlunit</groupId> 8 <artifactId>htmlunit-core-js</artifactId> 9 <version>2.23</version> 10 </dependency>
3、因为使用Java调用,只需要实现将经纬度转换成地址的功能,所以我们新建一个简单的html页面,不需要地图加载。
代码如下:(其中 <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=xxxxxxxxxxxxxx&plugin=AMap.Geocoder"></script> 中的key为您自己申请的key)
1 <!doctype html> 2 <html lang="en"> 3 <html> 4 <head> 5 <meta charset="UTF-8"> 6 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width"> 8 <title>逆地理编码(经纬度->地址)</title> 9 <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/> 10 <style> 11 .btn{ 12 width:10rem; 13 margin-left:6.8rem; 14 } 15 </style> 16 </head> 17 <body> 18 <div class="input-card" style='width:28rem;position: absolute;left: 40%;bottom: auto;top: 40%;'> 19 <label style='color:grey'>逆地理编码,根据经纬度获取地址信息</label> 20 <div class="input-item"> 21 <div class="input-item-prepend"><span class="input-item-text">经纬度</span></div> 22 <input id='lnglat' type="text" value='116.39,39.9'> 23 </div> 24 <div class="input-item"> 25 <div class="input-item-prepend"><span class="input-item-text" >地址</span></div> 26 <input id='address' type="text" value="" > 27 </div> 28 <input id="regeo" type="button" class="btn" value="经纬度 -> 地址" > 29 </div> 30 <script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"></script> 31 <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=xxxxxxxxxxxxxx&plugin=AMap.Geocoder"></script> 32 <script type="text/javascript"> 33 var geocoder = new AMap.Geocoder(); 34 function regeoCode() { 35 var lnglat = document.getElementById('lnglat').value.split(','); 36 geocoder.getAddress(lnglat, function(status, result) { 37 if (status === 'complete'&&result.regeocode) { 38 var address = result.regeocode.formattedAddress; 39 document.getElementById('address').value = address; 40 }else{ 41 log.error('根据经纬度查询地址失败') 42 } 43 }); 44 } 45 document.getElementById("regeo").onclick = regeoCode; 46 document.getElementById('lnglat').onkeydown = function(e) { 47 if (e.keyCode === 13) { 48 regeoCode(); 49 return false; 50 } 51 return true; 52 }; 53 </script> 54 </body> 55 </html>
4、页面测试成功后,使用htmlunit模拟页面点击。我自己封装了工具类,代码如下:
import com.gargoylesoftware.htmlunit.BrowserVersion; import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController; import com.gargoylesoftware.htmlunit.SilentCssErrorHandler; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlButtonInput; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlTextInput; import java.io.IOException; public class AmapUtil { private static String url = "上面html的地址"; private static WebClient webClient = new WebClient(BrowserVersion.CHROME); private static HtmlPage page; private static HtmlTextInput textField; private static HtmlButtonInput button; static { /* *****配置webClient******/ //ajax webClient.setAjaxController(new NicelyResynchronizingAjaxController()); //支持js webClient.getOptions().setJavaScriptEnabled(true); //忽略js错误 webClient.getOptions().setThrowExceptionOnScriptError(false); //忽略css错误 webClient.setCssErrorHandler(new SilentCssErrorHandler()); //不执行CSS渲染 webClient.getOptions().setCssEnabled(false); //超时时间 webClient.getOptions().setTimeout(3000); //允许重定向 webClient.getOptions().setRedirectEnabled(true); //允许cookie webClient.getCookieManager().setCookiesEnabled(true); //自定义JavaScript解析器(目的是为了不打印js存在的错误到日志) webClient.setJavaScriptEngine(new MyJavaScriptEngine(webClient)); //开始请求网站 try { page = webClient.getPage(url); textField = (HtmlTextInput) page.getElementById("lnglat"); button = (HtmlButtonInput) page.getElementById("regeo"); } catch (IOException e) { e.printStackTrace(); } } public static String getAddress(String lnglat){ try { textField.setText(lnglat); button.click(); return ((HtmlTextInput)page.getElementById("address")).getText(); } catch (Exception e) { e.printStackTrace(); } return ""; } }
自定义JavaScript解析器:

import com.gargoylesoftware.htmlunit.InteractivePage; import com.gargoylesoftware.htmlunit.ScriptException; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebWindow; import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine; import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener; import com.gargoylesoftware.htmlunit.javascript.host.Window; /** * 自定义JavaScript解析器(目的是为了不打印js存在的错误到日志) */ public class MyJavaScriptEngine extends JavaScriptEngine{ public MyJavaScriptEngine(WebClient webClient) { super(webClient); } @Override protected void handleJavaScriptException(final ScriptException scriptException, final boolean triggerOnError) { // Trigger window.onerror, if it has been set. final InteractivePage page = scriptException.getPage(); if (triggerOnError && page != null) { final WebWindow window = page.getEnclosingWindow(); if (window != null) { final Window w = (Window) window.getScriptableObject(); if (w != null) { try { w.triggerOnError(scriptException); } catch (final Exception e) { handleJavaScriptException(new ScriptException(page, e, null), false); } } } } final JavaScriptErrorListener javaScriptErrorListener = getWebClient().getJavaScriptErrorListener(); if (javaScriptErrorListener != null) { javaScriptErrorListener.scriptException(page, scriptException); } if (getWebClient().getOptions().isThrowExceptionOnScriptError()) { throw scriptException; } } }
5、编写测试类测试:
@Test public void test22(){ System.out.println(AmapUtil.getAddress("116.39,36.9")); System.out.println(AmapUtil.getAddress("115.39,36.9")); System.out.println(AmapUtil.getAddress("116.39,35.9")); System.out.println(AmapUtil.getAddress("116.39,37.9")); System.out.println(AmapUtil.getAddress("116.93,37.9")); }
结果如下:
测试成功。HtmlUnit是用Java写的无界面的浏览器,因为没有界面,因此执行的速度还可以,它提供了一系列的API,如表单的填充,表单的提交,模仿点击链接等。操作起来还是比较方便的。