今天继续来说昨天的话题——htmlunit扒取JS加载之后的网页源码
首先纠正昨天的一个错误:
原文:“而htmlunit只能返回URL对应的页面,所以我无法将htmlunit的URL指向SpringMVC的controller”
这是错误的,htmlunit可以模拟浏览器运行,也就是说它可以按controller返回的view经试图解析到达对应的页面并返回页面信息。
昨天代码导致这个问题的原因在controller的使用上,我把test这个controller作为入口,在其中调用htmlunit的方法去加载对应的url,而又愚蠢的把url之向了test这个controller,这似乎成了一个循环吧。
今天,纠正了这个错误。
解决方法,使用了两个controller,一个作为入口调用htmlunit方法,另一个作为htmlunit指向的url,其返回试图为需要扒取的工程内jsp。
这样就很好的解决了这个问题。
之前也尝试了一个controller,作为入口调用htmlunit方法,而直接把url指向了页面,这样做固然不会报错,但是不符合我的使用场景。同时无法取到该controller赋给session的值。
另外,今天解决了html带参传递的方法。
具体如下:
WebClient wc = new WebClient(BrowserVersion.INTERNET_EXPLORER_8);
wc.getOptions().setUseInsecureSSL(true);
wc.getOptions().setJavaScriptEnabled(true); // 启用JS解释器,默认为true
wc.getOptions().setCssEnabled(false); // 禁用css支持
wc.getOptions().setThrowExceptionOnScriptError(false); // js运行错误时,是否抛出异常
wc.getOptions().setTimeout(100000); // 设置连接超时时间 ,这里是10S。如果为0,则无限期等待
wc.getOptions().setDoNotTrackEnabled(false);
// wc.getOptions().setActiveXNative(true);
HtmlPage page;
try {
byte[] responseContent = null;
URL url = new URL(path);
WebRequest webRequest = new WebRequest(url, HttpMethod.POST);
List<NameValuePair> reqParam = new ArrayList<NameValuePair>();
reqParam.add(new NameValuePair("username", templateContent));
webRequest.setCharset("utf-8");
webRequest.setRequestParameters(reqParam);
page = wc.getPage(webRequest);
WebResponse webResponse = page.getWebResponse();
int status = webResponse.getStatusCode();
System.out.println("Charset : " + webResponse.getContentCharset());
System.out.println("ContentType : " + webResponse.getContentType());
// 读取数据内容
if (status==200) {
if (page.isHtmlPage()) {
System.out.println("htmlPage");
// 等待JS执行完成,包括远程JS文件请求,Dom处理
wc.waitForBackgroundJavaScript(10000);
responseContent = ((HtmlPage) page).asXml().getBytes();
} else {
System.out.println("不是htmlPage");
InputStream bodyStream = webResponse.getContentAsStream();
responseContent = ByteStreams.toByteArray(bodyStream);
bodyStream.close();
}
}
// 关闭响应流
webResponse.cleanUp();
String strToHtml = strToHtml(new String(responseContent));
//保存为本地html文档
File file = new File("D:/zzc.html");
FileWriter fileWriter = new FileWriter(file);
BufferedWriter writer = new BufferedWriter(fileWriter);
fileWriter.write(strToHtml);
writer.close();
System.out.println("GET : " + strToHtml);
} catch (FailingHttpStatusCodeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
通过post传的值在页面可以直接使用EL表达式得到。
需要注意的是:
1、转义字符:在返回xml、html等格式文件时,其中的部分字符会被转义,出现类似<、>等形式的符号,这不是乱码,是字符转义了。
解决方法:
1- 所有在标签中的文本都不会被转义。
2- 获得转义之后的文本,在对转译字符进行替换。
public String strToHtml(String s){
if (s==null||s.equals(""))
return "";
s = s.replaceAll("&","&");
s = s.replaceAll("<","<");
s = s.replaceAll(">",">");
s = s.replaceAll(" "," ");
s = s.replaceAll("<br/>","\n");
s = s.replaceAll("'","'");
s = s.replaceAll(""", "'");
return s;
}
2、htmlunit通过带参POST出现参数中文乱码的
只需要在POST之前设置他的request请求字符编码即可。如:
webRequest.setCharset("utf-8");
亲测,直接webclient.getpage(URL)得到的HTMLPAGE不会乱码,但是不能传参。