htmlunit 执行 javascript 时,不下载整个页面只返回url
来源:互联网 发布:mac怎么用校园网 编辑:程序博客网 时间:2024/06/07 07:06
htmlunit 是一款开源的 java 页面分析工具,启动 htmlunit 之后,底层会启动一个无界面浏览器,用户可以指定浏览器类型:firefox、ie 等,如果不指定,默认采用 INTERNET_EXPLORER_7:
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
通过简单的调用:
HtmlPage page = webClient.getPage(url);
即可得到页面的 HtmlPage 表示,然后通过:
InputStream is = targetPage.getWebResponse().getContentAsStream()
即可得到页面的输入流,从而得到页面的源码,这对做网络爬虫的项目来说,很有用。
当然,也可以从 page 中得更多的页面元素。
很重要的一点是,HtmlUnit 提供对执行 javascript 的支持:
page.executeJavaScript(javascript)
执行 js 之后,返回一个 ScriptResult 对象,通过该对象可以拿到执行 js 之后的页面等信息。默认情况下,内部浏览器在执行 js 之后,将做页面跳转,跳转到执行 js 之后生成的新页面,如果执行 js 失败,将不执行页面跳转。
htmlunit 执行 js 的大致过程如下:
从图中可以看出,htmlunit 执行js时,会将整个页面 download 下来,而很多时候,我们执行 js,只是因为需要执行后后生成的 url,不必要的频繁页面 download 不但会增加程序运行时长,也会加重网络负载。有下面两种方案可以完成这个需求:
1). 第一种方法是拿到这个 url 之后,将其返回,但代码的调用层次较深,如果修改源码的话,需要修改的地方可能较多,实现起来可能有一定的复杂性和难度。
2). 第二种方法是,生成一个伪 response,而不是去真正获取页面的 response,用来构造所有的新 page。该方法具有代码改动小,实现方便的特点。
因第一种方法对源码的修改大,实现起来也比较困难,这里给出第二种方法的实现:
查看源码可以发现,在:
com.gargoylesoftware.htmlunit.javascript.host.location.java 类中,有这样一个方法:
- public void jsxSet_href(final String newLocation) throws IOException {
- final HtmlPage page = (HtmlPage) getWindow(getStartingScope()).getWebWindow().getEnclosedPage();
- if (newLocation.startsWith(JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
- final String script = newLocation.substring(11);
- page.executeJavaScriptIfPossible(script, "new location value", 1);
- return;
- }
- try {
- final URL url = page.getFullyQualifiedUrl(newLocation);
- final URL oldUrl = page.getWebResponse().getWebRequest().getUrl();
- if (url.sameFile(oldUrl) && !StringUtils.equals(url.getRef(), oldUrl.getRef())) {
- // If we're just setting or modifying the hash, avoid a server hit.
- jsxSet_hash(newLocation);
- return;
- }
- final WebWindow webWindow = getWindow().getWebWindow();
- webWindow.getWebClient().download(webWindow, "", new WebRequest(url), "JS set location");
- }
- catch (final MalformedURLException e) {
- LOG.error("jsxSet_location('" + newLocation + "') Got MalformedURLException", e);
- throw e;
- }
- }
- public void download(final WebWindow requestingWindow, final String target,
- final WebRequest request, final String description) {
- final WebWindow win = resolveWindow(requestingWindow, target);
- final URL url = request.getUrl();
- boolean justHashJump = false;
- if (win != null) {
- final Page page = win.getEnclosedPage();
- if (page instanceof HtmlPage && !((HtmlPage) page).isOnbeforeunloadAccepted()) {
- return;
- }
- <strong> final URL current = page.getWebResponse().getWebRequest().getUrl();</strong>
- if (url.sameFile(current) && !StringUtils.equals(current.getRef(), url.getRef())) {
- justHashJump = true;
- }
- }
- // verify if this load job doesn't already exist
- for (final LoadJob loadJob : loadQueue_) {
- if (loadJob.response_ == null) {
- continue;
- }
- final WebRequest otherRequest = loadJob.response_.getWebRequest();
- final URL otherUrl = otherRequest.getUrl();
- // TODO: investigate but it seems that IE considers query string too but not FF
- if (url.getPath().equals(otherUrl.getPath())
- && url.getHost().equals(otherUrl.getHost())
- && url.getProtocol().equals(otherUrl.getProtocol())
- && url.getPort() == otherUrl.getPort()
- && request.getHttpMethod() == otherRequest.getHttpMethod()) {
- return; // skip it;
- }
- }
- final LoadJob loadJob;
- if (justHashJump) {
- loadJob = new LoadJob(win, target, url);
- }
- else {
- try {
- final WebResponse response = loadWebResponse(request);
- loadJob = new LoadJob(requestingWindow, target, response);
- }
- catch (final IOException e) {
- throw new RuntimeException(e);
- }
- }
- loadQueue_.add(loadJob);
- }
如果当前线程是第一次执行该 download 方法,就不对代码做修改,让其生成一个真正的 response,然后,将该 response 对象保存起来,待该线程后续再执行 js 进入该方法,不再生成 response 对象,而是将之前保存起来的 response 拿出来直接使用,并修改对应的 url 为执行 js 之后生成的 url 即可:
response.getWebRequest().setUrl(request.getUrl());
js 执行完成之后,返回的 ScriptResult 对应的 url ,就是执行 js 之后生成的 url 了,但如果去拿页面的源码的话,会得到 ”错误“ 的数据,这是因为我们每次都用了同一个 response,而不是 url 页面对应的 url 。因为我们的初衷就是得到正确的 url ,而不去 download 整个页面,所以这种 ”错误“ 不会影响我们的程序。
- 如何让 htmlunit 执行 javascript 时,不下载整个页面,而只返回url
- htmlunit 执行 javascript 时,不下载整个页面只返回url
- ajax返回javascript给页面执行
- ajax返回javascript给页面执行
- ajax返回javascript给页面执行
- JavaScript的onunload()方法在关闭页面时不执行
- Jquery只请求一个url,页面不刷新
- Spring MVC中只返回数据不跳转页面
- mysql执行preparedStatement.executeUpdate时,只返回changedRows的行数,不返回涉及到的行数的办法
- asp.net 点击刷新按钮,只刷新验证码,不刷新整个页面
- HtmlUnit+Jsoup 解决爬虫无法解析执行javascript的问题
- jquery ajax 返回整个html页面
- 不刷新整个页面实现后退功能
- Struts2 只执行Action 页面不跳转 AJAX请求 序列化
- 返回当前页面得url
- PageHelper只执行count,不执行查询
- [javascript]用子页的div遮盖整个页面
- javascript返回页面顶部
- 万万没想到:彻底毁掉硬盘数据原来这么难
- valuestack,stackContext,ActionContext.之间的关系
- UIMenuController 在UIView 上的 显示
- android ImageView加载动画
- Ueditor后端配置项没有正常加载,上传插件不能正常使用!
- htmlunit 执行 javascript 时,不下载整个页面只返回url
- springmvc之json数据交互controller方法返回值为简单类型
- equal_range
- Android界面——LinearLayout和RelativeLayout 属性对比
- MyEclipse2014破解小记
- 欧拉函数
- 用python解决你的实际问题,忘记语言吧
- Java面向对象个人学习和理解
- Mac上SSH的生成