2013-11-22 19 views
6

Nach https://developers.google.com/webmasters/ajax-crawling/docs/html-snapshot, mit HtmlUnit (2.13) Ich versuche, einen Snapshot für eine Webseite mit AngularJS (1.2.1) zu erstellen.HTMLUnit funktioniert nicht mit AngularJS

Mein Java-Code ist:

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(); 

Obwohl webClient.getPage(...) keine Ausnahme macht wirft das Ergebnis Zeichenfolge enthält noch „unbewertet Winkel Ausdrücke“ wie

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

Ich bin mir bewusst, http://htmlunit.10904.n7.nabble.com/htmlunit-to-scrape-angularjs-td29931.html#a30075 aber die recomendation da gegeben funktioniert auch nicht.

Natürlich funktioniert die gleiche GET-Anfrage ohne Ausnahmen in allen aktuellen Browsern.

Irgendwelche Ideen/Erfahrungen wie HtmlUnit mit AngularJS arbeiten?

Update:

habe ich eine Htmlunit bug report.
Im Moment habe ich meine Implementierung auf PhantomJS umgestellt. Vielleicht andere dieser Code-Schnipsel hilft mit einem ähnlichen Problem:

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: ich manuell als Google-Crawler meiner Seiten-Rendering stoped macht Angular Websites selbst jetzt

Antwort

0

Einen ähnlichen Code I funktionieren gut, wenn Meine einzelne Seite App verwendet angularjs 1.0.4; das einzige, was anders muss ich war Htmlunit tun sagen FIREFOX_17 anstelle des Standard-IE8 in Htmlunit 2.12 zu verwenden (ähnlich dem Link zur Verfügung gestellt, aber FIREFOX_17 statt FIREFOX_10)

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

Ich habe ein Upgrade 1,2 bis AngularJS und boom mein Seite erscheint mit allen eckigen Platzhaltern.

1

Ich hatte das gleiche Problem mit "unevaluierten Winkelausdrücken", wenn ich HtmlUnit verwende. Die Lösung ist bootstrap application manually. Reproduction Schritte:

Minimal Beispiel für App im Browser zu arbeiten, aber nicht mit 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> 

Modifikationsschritte:

  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());

Und jetzt arbeiten Beispiel:

<!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> 

Test:

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()); 

Es Lösung funktioniert, aber Vergnügen Lösung nicht wirklich. Ich weiß nicht, dass es ein Problem von HtmlUnit oder Angularjs ist.

8

Ich hatte das gleiche Problem, konnte aber explizites Bootstrapping nicht verwenden, da angulare e2e-Tests nicht mit explizitem Bootstrap funktionieren.

löste ich das Problem, indem

<html id="ng-app" class="ng-app: appmodule;"> 

statt

<html ng-app="appmodule"> 

Htmlunit-Tests arbeiten und e2e Tests funktionieren auch mit.

Sehr wahrscheinlich unterstützt htmlunit nicht (vollständig?) Document.querySelectorAll(). Diese Methode wird von angularInit() verwendet, um ng-app-Anweisungen zu finden.

Die syntaktische Variante für die ng-app-Direktive funktioniert um die document.querySelectorAll() -Aufrufe in angularInit().

+0

Dies sollte die akzeptierte Antwort sein, da es das Problem gelöst hat, wo HTMLUnit die Winkelanweisungen nicht auflöst. Vielen Dank! – chaitanya

+0

Dies scheint zu helfen, aufgrund der schlechten Unterstützung von HtmlUnit für AngularJS, aber es löst nicht alle Probleme. Hoffentlich wird 2.15 besser sein ... – Splaktar

1

Das HtmlUnit-Problem wurde behoben. AngularJS-Ausdrücke werden jetzt korrekt ausgewertet.

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

+0

In welcher Version ist das behoben? Ich verwende 2.14 und die Verwendung von BrowserVersion.CHROME oder FIREFOX_24 führt zu nicht evaluierten AngularJS-Ausdrücken, aber die Verwendung von BrowserVersion.INTERNET_EXPLORER_8 scheint diese Ausdrücke auszuwerten. – Splaktar

+0

Sieht aus, als wäre dies noch nicht in einer Veröffentlichung (2.14 wurde im Februar veröffentlicht). Dieser Fix wurde im März erstellt und ist noch nicht Teil einer Veröffentlichung. Ich habe versucht, aus dem neuesten SVN zu bauen, aber es ist fehlgeschlagen: https://sourceforge.net/p/htmlunit/bugs/1596/ – Splaktar

+0

Ich habe dies erneut mit dem neuesten SVN-Zweig von 2,15 getestet und ich muss noch tun der alte Hack, der in der Antwort von @stephanme erwähnt wird. Ich benutze AngularJS 1.0.8. – Splaktar

0

Dank für die Berichterstattung, in SVN behoben. Bitte erwarten Sie HtmlUnit 2.15 sehr bald.

Der Testfall funktioniert jetzt mit Chrome-Simulation, der Grund war querySelectorAll() sollte in Dokument/Element definiert werden.

Bitte beachten Sie, es scheint, dass andere die Ursache bereits identifiziert haben, und die Bereitstellung eines minimalen Testfalls für das HtmlUnit-Team kann in sehr kurzer Zeit behoben werden.

Nochmals vielen Dank für Ihr Feedback.