HTMLUnit不使用AngularJS

时间:2013-11-22 19:35:57

标签: javascript ajax angularjs web-crawler htmlunit

根据https://developers.google.com/webmasters/ajax-crawling/docs/html-snapshot,使用HtmlUnit(2.13)我试图使用AngularJS(1.2.1)为网页创建快照。

我的Java代码是:

WebClient webClient = new WebClient();

webClient.setAjaxController(new NicelyResynchronizingAjaxController());
webClient.setCssErrorHandler(new SilentCssErrorHandler());

webClient.getOptions().setCssEnabled(true);
webClient.getOptions().setRedirectEnabled(false);
webClient.getOptions().setAppletEnabled(false);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setPopupBlockerEnabled(true);
webClient.getOptions().setTimeout(10000);

webClient.getOptions().setThrowExceptionOnFailingStatusCode(true);
webClient.getOptions().setThrowExceptionOnScriptError(true);
webClient.getOptions().setPrintContentOnFailingStatusCode(true);

HtmlPage page = webClient.getPage(new WebRequest(new URL("..."), HttpMethod.GET));
webClient.waitForBackgroundJavaScript(5000);
String result = page.asXml();

虽然webClient.getPage(...)不会抛出任何异常,但结果字符串仍然包含“未评估的角度表达式”,例如

<div>
    {{name}}
</div>

我知道http://htmlunit.10904.n7.nabble.com/htmlunit-to-scrape-angularjs-td29931.html#a30075但是那里给出的推荐也没有用。

当然,相同的GET请求在所有当前浏览器中都没有例外。

如何让HtmlUnit与AngularJS一起使用的任何想法/经验?

更新:

我创建了一个HTMLUnit bug report 目前,我将我的实现切换到了PhantomJS。也许这段代码片段可以帮助其他人解决类似的问题:

System.setProperty("phantomjs.binary.path", "phantomjs.exe");
DesiredCapabilities caps = new DesiredCapabilities();
caps.setJavascriptEnabled(true);
caps.setCapability("takesScreenshot", false);

PhantomJSDriver driver = new PhantomJSDriver(caps);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.get(new URL("..."));
String result = driver.getPageSource();

UPDATE2: 由于Google抓取工具现在呈现Angular网站

,我手动设置了我的网页

5 个答案:

答案 0 :(得分:8)

我遇到了同样的问题,但无法使用显式引导,因为有角度的e2e测试无法使用显式引导程序。

我使用

解决了这个问题
<html id="ng-app" class="ng-app: appmodule;"> 

而不是

<html ng-app="appmodule">

htmlunit测试工作和e2e测试也可以。

很有可能,htmlunit没有(完全?)支持document.querySelectorAll()。 angularInit()使用此方法来查找ng-app指令。

ng-app指令的语法变体适用于angularInit()中的document.querySelectorAll()调用。

答案 1 :(得分:1)

如果我使用HtmlUnit,我对“未评估的角度表达式”也有同样的问题。解决方案是bootstrap application manually。复制步骤:

应用程序在浏览器中工作的最小示例,但没有使用HtmlUnit:

<!doctype html>
<html ng-app>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
</head>
<body>
    <div>
        <label>Name:</label> <input type="text" ng-model="yourName"
            placeholder="Enter a name here">
        <hr>
        <h1>Hello {{yourName}}!</h1>
    </div>
</body>
</html>

修改步骤:

  1. Bootstrap manually
  2. Remove ng-app to not bootstrap app twice
  3. If you use $http or like you should re-sync it with

    webClient.setAjaxController(new NicelyResynchronizingAjaxController());

  4. 现在正在运作的例子:

    <!doctype html>
    <html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
        <script>
            angular.element(document).ready(function() {
                angular.module('myApp', []);
                angular.bootstrap(document, ['myApp']);
            });
        </script>
    </head>
    <body>
        <div>
            <label>Name:</label> <input type="text" ng-model="yourName"
                placeholder="Enter a name here">
            <hr>
            <h1>Hello {{yourName}}!</h1>
        </div>
    </body>
    </html>
    

    测试:

    WebClient webClient = new WebClient();
    webClient.setAjaxController(new NicelyResynchronizingAjaxController());
    HtmlPage page = webClient.getPage("http://localhost:8080/index.html");
    
    // Initial state
    assertEquals("Hello !", page.getElementsByTagName("h1").get(0).asText());
    
    // Set value
    ((HtmlInput)page.getElementsByTagName("input").get(0)).setValueAttribute("world");
    
    // New state
    assertEquals("Hello world!", page.getElementsByTagName("h1").get(0).asText());
    

    这是一个有效的解决方案,但不是真正的快乐解决方案。我不知道这是HtmlUnit或Angularjs的问题。

答案 2 :(得分:1)

HtmlUnit问题现已修复。现在可以正确评估AngularJS表达式。

https://sourceforge.net/p/htmlunit/bugs/1559/

答案 3 :(得分:0)

当我的单页应用程序使用angularjs 1.0.4时,我的工作正常。唯一不同的是我要告诉htmlunit使用FIREFOX_17而不是htmlunit 2.12中的默认IE8(类似于您提供的链接,但FIREFOX_17而不是FIREFOX_10)

final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_17);

我升级到angularjs 1.2并展开我的页面显示所有有角度的占位符。

答案 4 :(得分:0)

感谢您报告,修复了SVN。请尽快预计HtmlUnit 2.15。

测试用例现在适用于Chrome模拟,原因是querySelectorAll()应该在document / element中定义。

请注意,似乎其他人已经确定了根本原因,并且向HtmlUnit团队提供最小的测试用例可以在很短的时间内修复它。

再次感谢您的反馈。