如何克服HTMLUnit ScriptException?

我遇到了一个代码行,可能会触发一些JS函数的问题,我怎么能解决这个问题?

box.setText(link.toString()); client.waitForBackgroundJavaScriptStartingBefore(10000); box.dblClick(); //this line cause the exception Exception in thread "main" ======= EXCEPTION START ======== EcmaError: lineNumber=[0] column=[0] lineSource=[function () {] name=[ReferenceError] sourceName=[onclick event for HtmlDivision[<div class="_119 stat_elem focus_target mtm mbl _5bsm _6dh _51z6" id="u_0_k" data-location="maincolumn" onclick="Bootloader.loadComponents(&quot;ComposerXControllerBootload&quot;, emptyFunction);">] in https://www.facebook.com/?_fb_noscript=1] message=[ReferenceError: "Bootloader" is not defined.] com.gargoylesoftware.htmlunit.ScriptException: ReferenceError: "Bootloader" is not defined. at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:684) at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:602) at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:507) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.callFunction(JavaScriptEngine.java:616) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.callFunction(JavaScriptEngine.java:591) at com.gargoylesoftware.htmlunit.html.HtmlPage.executeJavaScriptFunctionIfPossible(HtmlPage.java:985) at com.gargoylesoftware.htmlunit.javascript.host.EventListenersContainer.executeEventHandler(EventListenersContainer.java:210) at com.gargoylesoftware.htmlunit.javascript.host.EventListenersContainer.executeBubblingListeners(EventListenersContainer.java:230) at com.gargoylesoftware.htmlunit.javascript.host.Node.fireEvent(Node.java:804) at com.gargoylesoftware.htmlunit.javascript.host.Node.fireEvent(Node.java:738) at com.gargoylesoftware.htmlunit.html.HtmlElement$1.run(HtmlElement.java:869) at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:602) at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:507) at com.gargoylesoftware.htmlunit.html.HtmlElement.fireEvent(HtmlElement.java:874) at com.gargoylesoftware.htmlunit.html.HtmlElement.doClickFireClickEvent(HtmlElement.java:1311) at com.gargoylesoftware.htmlunit.html.HtmlElement.click(HtmlElement.java:1253) at com.gargoylesoftware.htmlunit.html.HtmlElement.click(HtmlElement.java:1205) at com.gargoylesoftware.htmlunit.html.HtmlElement.dblClick(HtmlElement.java:1351) at com.gargoylesoftware.htmlunit.html.HtmlElement.dblClick(HtmlElement.java:1326) at prototype.Profile.postLinkOnWall(Profile.java:225) at html.Log.findNext(Log.java:150) at prototype.Prtp.main(Prtp.java:49) Caused by: net.sourceforge.htmlunit.corejs.javascript.EcmaError: ReferenceError: "Bootloader" is not defined. at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3603) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3587) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.notFoundError(ScriptRuntime.java:3657) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.nameOrFunction(ScriptRuntime.java:1749) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.name(ScriptRuntime.java:1690) at net.sourceforge.htmlunit.corejs.javascript.Interpreter.interpretLoop(Interpreter.java:1622) at net.sourceforge.htmlunit.corejs.javascript.Interpreter.interpret(Interpreter.java:798) at net.sourceforge.htmlunit.corejs.javascript.InterpretedFunction.call(InterpretedFunction.java:105) at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.doTopCall(ContextFactory.java:405) at com.gargoylesoftware.htmlunit.javascript.HtmlUnitContextFactory.doTopCall(HtmlUnitContextFactory.java:309) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3031) at net.sourceforge.htmlunit.corejs.javascript.InterpretedFunction.call(InterpretedFunction.java:103) at com.gargoylesoftware.htmlunit.javascript.host.EventHandler.call(EventHandler.java:81) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$4.doRun(JavaScriptEngine.java:609) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:669) ... 21 more Enclosed exception: net.sourceforge.htmlunit.corejs.javascript.EcmaError: ReferenceError: "Bootloader" is not defined. at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3603) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3587) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.notFoundError(ScriptRuntime.java:3657) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.nameOrFunction(ScriptRuntime.java:1749) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.name(ScriptRuntime.java:1690) at net.sourceforge.htmlunit.corejs.javascript.Interpreter.interpretLoop(Interpreter.java:1622) at script.onclick(onclick event for HtmlDivision[<div class="_119 stat_elem focus_target mtm mbl _5bsm _6dh _51z6" id="u_0_k" data-location="maincolumn" onclick="Bootloader.loadComponents(&quot;ComposerXControllerBootload&quot;, emptyFunction);">] in https://www.facebook.com/?_fb_noscript=1) at net.sourceforge.htmlunit.corejs.javascript.Interpreter.interpret(Interpreter.java:798) at net.sourceforge.htmlunit.corejs.javascript.InterpretedFunction.call(InterpretedFunction.java:105) at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.doTopCall(ContextFactory.java:405) at com.gargoylesoftware.htmlunit.javascript.HtmlUnitContextFactory.doTopCall(HtmlUnitContextFactory.java:309) at net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3031) at net.sourceforge.htmlunit.corejs.javascript.InterpretedFunction.call(InterpretedFunction.java:103) at com.gargoylesoftware.htmlunit.javascript.host.EventHandler.call(EventHandler.java:81) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$4.doRun(JavaScriptEngine.java:609) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$HtmlUnitContextAction.run(JavaScriptEngine.java:669) at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:602) at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:507) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.callFunction(JavaScriptEngine.java:616) at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.callFunction(JavaScriptEngine.java:591) at com.gargoylesoftware.htmlunit.html.HtmlPage.executeJavaScriptFunctionIfPossible(HtmlPage.java:985) at com.gargoylesoftware.htmlunit.javascript.host.EventListenersContainer.executeEventHandler(EventListenersContainer.java:210) at com.gargoylesoftware.htmlunit.javascript.host.EventListenersContainer.executeBubblingListeners(EventListenersContainer.java:230) at com.gargoylesoftware.htmlunit.javascript.host.Node.fireEvent(Node.java:804) at com.gargoylesoftware.htmlunit.javascript.host.Node.fireEvent(Node.java:738) at com.gargoylesoftware.htmlunit.html.HtmlElement$1.run(HtmlElement.java:869) at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:602) at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:507) at com.gargoylesoftware.htmlunit.html.HtmlElement.fireEvent(HtmlElement.java:874) at com.gargoylesoftware.htmlunit.html.HtmlElement.doClickFireClickEvent(HtmlElement.java:1311) at com.gargoylesoftware.htmlunit.html.HtmlElement.click(HtmlElement.java:1253) at com.gargoylesoftware.htmlunit.html.HtmlElement.click(HtmlElement.java:1205) at com.gargoylesoftware.htmlunit.html.HtmlElement.dblClick(HtmlElement.java:1351) at com.gargoylesoftware.htmlunit.html.HtmlElement.dblClick(HtmlElement.java:1326) at prototype.Profile.postLinkOnWall(Profile.java:225) at html.Log.findNext(Log.java:150) at prototype.Prtp.main(Prtp.java:49) == CALLING JAVASCRIPT == function () { [native code, arity=0] } ======= EXCEPTION END ======== 

我写的那个盒子,在一个普通的浏览器上执行一个不能用HtmlUnit执行的重新格式化函数,所以我试着用dbclick()强制它。

HtmlUnit不能很好的使用JavaScript。 它会经常抛出抱怨未定义的variables或函数的错误。

从这个意义上说, 现实生活中的浏览器(FireFox,Internet Explorer,Chrome等)更加灵活。 这意味着他们将允许语法不正确的HTML和JavaScript片断(例如:不定义函数或不结束HTML标记)。

HtmlUnit期望一切(几乎)完美。 虽然,它会修复一些缺less的结束HTML标签,一般来说,它期望页面中的代码不包含任何types的错误。 此外,即使一切看起来正确,HtmlUnit甚至可能会抱怨。

有些项目供您思考:

  • 最重要的是在不同的BrowserVersions之间切换。 您可以在创buildWebClient对象时设置它们。 Internet Explorer(具有讽刺意味的是)在解释JavaScript时已经certificate给我带来了最好的结果
  • 确保你的HTML和JavaScript代码都是正确的
  • 避免使用复杂的库(jQuery似乎得到了适当的支持)
  • 尝试使用非最小化版本的库
  • 如果碰巧使用jQuery(或其他类似的库),避免复杂的jQuery方法(例如:dynamic添加事件到元素)

当然,如果您能控制从服务器获取的源代码,那么这些评论就会适用。 有时候,事实并非如此。 在这种情况下,你的手甚至更多。

一种select是用下面的方法来抑制exception:

 webClient.getOptions().setThrowExceptionOnScriptError(false); 

虽然,这会让你通过例外不会纠正任何JavaScript错误。 这意味着如果引发这个exception的JS代码碰巧在你的逻辑中是至关重要的,那么你完全依赖于代码执行的结果,那么你不能让HtmlUnit处理你的JS。 如果这恰好是AJAX请求的结果,那么您可以手动发出请求,而不是让HtmlUnit这样做。

另一方面,如果给你麻烦的JS代码在你的逻辑中并不重要,我的意思是,它可能只是隐藏一个元素或者改变一个你不关心的颜色,然后抑制exception就是要走的路。

剩下的选项不多。

尝试设置您的Web客户端不要抛出exception:

 client.getOptions().setThrowExceptionOnScriptError(false); 

当我用方法得到一些网站时,我也遇到了同样的问题:

 webClient.getPage("http://somepage.com"); 

如果你不需要使用JavaScript来处理网站,你可以写:

 webClient.getOptions().setJavaScriptEnabled(false); 

在我的情况下,它运作良好,脚本是立即执行(当我只使用webClient.getOptions().setThrowExceptionOnScriptError(false)然后脚本allways尝试执行糟糕的JavaScript代码,并在控制台写出exception消息约10秒,所以我不build议使用它)。