根据官方给出的示例我们书写的爬虫大概流程如下:
1,引入依赖到pom:
net.sourceforge.htmlunit
htmlunit
2.35.0
2,创建爬虫内容:
@Test public void homePage() throws Exception { try (final WebClient webClient = new WebClient()) { final HtmlPage page = webClient.getPage("http://htmlunit.sourceforge.net"); Assert.assertEquals("HtmlUnit - Welcome to HtmlUnit", page.getTitleText()); final String pageAsXml = page.asXml(); Assert.assertTrue(pageAsXml.contains("")); final String pageAsText = page.asText(); Assert.assertTrue(pageAsText.contains("Support for the HTTP and HTTPS protocols")); } }
或者:
@Test public void submittingForm() throws Exception { try (final WebClient webClient = new WebClient()) { // Get the first page final HtmlPage page1 = webClient.getPage("http://some_url"); // Get the form that we are dealing with and within that form, // find the submit button and the field that we want to change. final HtmlForm form = page1.getFormByName("myform"); final HtmlSubmitInput button = form.getInputByName("submitbutton"); final HtmlTextInput textField = form.getInputByName("userid"); // Change the value of the text field textField.type("root"); // Now submit the form by clicking the button and get back the second page. final HtmlPage page2 = button.click(); } }
例子内容见:http://htmlunit.sourceforge.net/gettingStarted.html
但是当我按照上述方式只是替换了getPage页的连接的时候,发现执行webClient.getPage()始终返回null,根本没有数据。
3,因为也没有任何报错,也没有返回,所以怀疑是新版本做了异步?通过源码追溯查看,发现也没有;
getPage方法调用的是:
webClient类对象中的方法,方法内部执行
if ("javascript".equals(protocol)) { webResponse = makeWebResponseForJavaScriptUrl(webWindow, webRequest.getUrl(), webRequest.getCharset()); if (webWindow.getEnclosedPage() != null && webWindow.getEnclosedPage().getWebResponse() == webResponse) { // a javascript:... url with result of type undefined didn't changed the page return (P) webWindow.getEnclosedPage(); } } else { webResponse = loadWebResponse(webRequest); }
可见通过loadWebResponse来获取返回值。
然后继续跟进发现执行的default分支的代码:
最后通过
webResponse = getWebConnection().getResponse(webRequest);来获取真实的返回对象。
getResponse的真实执行方法来自HttpWebConnection类对象中的getResponse方法最后的返回值是:
makeWebResponse(httpResponse, request, downloadedBody, endTime - startTime);
我们继续跟进makeWebResponse方法的返回是
newWebResponseInstance(responseData, loadTime, request);
从名字看来,应该是初始化了一个WebResponse的实例返回,但是执行之后就没有然后了。那一定是这个实例初始化失败了。
点进去对象看看发现引入了commons-io包中的一些对象,但是jar依赖本身没有引入导致的报错:
于是我手动将common-io包引入,再次执行,成功返回。
4.通过上述排查过程,我们可以看出,阅读项目源码可以快速定位问题,但有些项目的源码比较复杂,读起来不容易,则需要花费更多的时间。另外说明一下,htmlunit最新git上master分支已经引入了common-io的包,所以这个问题应该能够解决。或者你项目中本来就已经引入了common包,则你使用过程中也不会有问题。