Java 如何克服 HTMLUnit ScriptException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20315330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to overcome an HTMLUnit ScriptException?
提问by user3054975
I got a problem with a line of code that probably triggers some js function e couse an exception, how can i fix this?
我的一行代码出现问题,可能会触发某些 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("ComposerXControllerBootload", 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.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.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("ComposerXControllerBootload", 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.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.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 ========
The box where I write, acts on a normal browser a reformatting function which is not performed using HtmlUnit so I tried to force it with a dbclick().
我写的盒子,作用于普通浏览器的重新格式化功能,它不是使用 HtmlUnit 执行的,所以我试图用 dbclick() 强制它。
回答by Gokul Nath KP
Try setting your web client not to throw exception:
尝试将您的 Web 客户端设置为不抛出异常:
client.getOptions().setThrowExceptionOnScriptError(false);
回答by Mosty Mostacho
HtmlUnit does not play well with JavaScript. It will frequently throw errors complaining about variables or functions not defined.
HtmlUnit 不能很好地与 JavaScript 配合使用。它会经常抛出错误,抱怨变量或函数未定义。
In that sense, real lifebrowsers (FireFox, Internet Explorer, Chrome, etc) are much more flexible. That means that they will allow syntactically incorrect pieces of HTML and JavaScript (eg: not defining functions or not ending HTML tags).
从这个意义上说,现实生活中的浏览器(FireFox、Internet Explorer、Chrome 等)要灵活得多。这意味着它们将允许语法错误的 HTML 和 JavaScript 片段(例如:不定义函数或不结束 HTML 标签)。
HtmlUnit expects everything to be (almost) perfect. Although, it will fix some missing ending HTML tags, in general, it expects the code in the pages not to contain any kind of error. Furthermore, even if everything looks correct HtmlUnit might even complain.
HtmlUnit 期望一切都(几乎)完美。虽然,它会修复一些丢失的结束 HTML 标签,但一般来说,它希望页面中的代码不包含任何类型的错误。此外,即使一切看起来都正确,HtmlUnit 甚至可能会抱怨。
Some items for you to think about are:
您需要考虑的一些项目是:
- The most important one is switching between different
BrowserVersions
. You can set them when creating theWebClient
object. Internet Explorer (ironically) has proven to give me the best results when it comes to interpreting JavaScript - Make sure your HTML and JavaScript code are both correct
- Avoid using of complexlibraries (jQuery seems to be properly supported)
- Try to use non-minimized versions of libraries
- If you happen to be using jQuery (or other similar libraries) avoid complex jQuery methods (eg: dynamically adding events to elements)
- 最重要的一个是在不同的
BrowserVersions
. 您可以在创建WebClient
对象时设置它们。事实证明,Internet Explorer(具有讽刺意味的是)在解释 JavaScript 时给了我最好的结果 - 确保您的 HTML 和 JavaScript 代码都正确
- 避免使用复杂的库(jQuery 似乎得到了适当的支持)
- 尝试使用非最小化版本的库
- 如果您碰巧使用 jQuery(或其他类似库),请避免使用复杂的 jQuery 方法(例如:向元素动态添加事件)
Of course, those comments would apply if you have control over the source code you're fetching from the server. Sometimes, this is not the case. In this situation your hands are even more tied.
当然,如果您可以控制从服务器获取的源代码,那么这些注释将适用。有时,情况并非如此。在这种情况下,您的手会更加束缚。
One option, would be to suppress the exception with:
一种选择是通过以下方式抑制异常:
webClient.getOptions().setThrowExceptionOnScriptError(false);
Although, this will get you through the exception won't correct any JavaScript error. That means that if the JS piece of code that is throwing this exception happens to be crucial in your logic, I mean, you absolutely depend on the result of the execution of that code then you can not let HtmlUnit handle your JS. If this happens to be the result of an AJAX request then you can issue the request yourself manually instead of letting HtmlUnit do so.
虽然,这将使您通过异常不会纠正任何 JavaScript 错误。这意味着,如果抛出此异常的 JS 代码段恰好在您的逻辑中至关重要,我的意思是,您绝对依赖于该代码的执行结果,那么您不能让 HtmlUnit 处理您的 JS。如果这恰好是 AJAX 请求的结果,那么您可以自己手动发出请求,而不是让 HtmlUnit 这样做。
On the other hand, if the JS code that is giving you trouble is not critical in your logic, I mean, it might just be hiding an element or changing a color that you don't care about, then suppressing the exception would be the way to go.
另一方面,如果给您带来麻烦的 JS 代码在您的逻辑中并不重要,我的意思是,它可能只是隐藏了一个元素或更改了您不关心的颜色,那么抑制异常就是要走的路。
There aren't many options left.
剩下的选择不多了。
回答by Oxygenium
I had this same problem when I get some website with method:
当我使用方法获取一些网站时,我遇到了同样的问题:
webClient.getPage("http://somepage.com");
If you don't need use JavaScript to working with websites you can write:
如果您不需要使用 JavaScript 来处理网站,您可以编写:
webClient.getOptions().setJavaScriptEnabled(false);
In my case it works well and script is performing immediately (when I used only webClient.getOptions().setThrowExceptionOnScriptError(false)
then the script always tried perform bad JavaScript code and for about 10 seconds writing out exception messages in the console, so I don't recommend to use it).
在我的情况下,它运行良好,脚本立即执行(当我只webClient.getOptions().setThrowExceptionOnScriptError(false)
使用脚本时,脚本总是尝试执行错误的 JavaScript 代码,并在控制台中写出大约 10 秒的异常消息,所以我不建议使用它)。