HTMLUnit не ждет Javascript
У меня есть страница на основе GWT, которую я хотел бы создать для него снимок HTML, используя HtmlUnit.
Страница загружается с использованием информации Ajax/JavaScript на продукт, поэтому около 1 секунды появляется сообщение "Загрузка...", а затем появляется содержимое.
Проблема в том, что HtmlUnit, похоже, не захватывает информацию, и все, что я получаю, это диапазон "Загрузка...".
Ниже приведен экспериментальный код с HtmlUnit, где я пытаюсь дать ему достаточно времени, чтобы дождаться загрузки данных, но он ничего не меняет, и я все еще не могу захватить данные, загруженные GWT javascript.
WebClient webClient = new WebClient();
webClient.setJavaScriptEnabled(true);
webClient.setThrowExceptionOnScriptError(false);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
WebRequest request = new WebRequest(new URL("<my_url>"));
HtmlPage page = webClient.getPage(request);
int i = webClient.waitForBackgroundJavaScript(1000);
while (i > 0)
{
i = webClient.waitForBackgroundJavaScript(1000);
if (i == 0)
{
break;
}
synchronized (page)
{
System.out.println("wait");
page.wait(500);
}
}
webClient.getAjaxController().processSynchron(page, request, false);
System.out.println(page.asXml());
Любые идеи...?
Ответы
Ответ 1
Спасибо, что ответили.
На самом деле я должен был сообщить об этом раньше, что сам нашел решение.
По-видимому, при инициализации WebClient с FF:
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
Кажется, он работает.
При инициализации WebClient с конструктором по умолчанию он использует IE7 по умолчанию, и я полагаю, что FF лучше поддерживает Ajax и является рекомендуемым эмулятором для использования.
Ответ 2
Я полагаю, что по умолчанию NicelyResynchronizingAjaxController
будет только повторно синхронизировать вызовы AJAX, вызванные действием пользователя, отслеживая, с какого потока он произошел. Возможно, генерируемый JavaScript GWT вызывается другим потоком, который NicelyResynchronizingAjaxController
не хочет ждать.
Попробуйте объявить свой собственный AjaxController для синхронизации со всем, независимо от исходного потока:
webClient.setAjaxController(new AjaxController(){
@Override
public boolean processSynchron(HtmlPage page, WebRequest request, boolean async)
{
return true;
}
});
Ответ 3
Как указано в документации, waitForBackgroundJavaScript
является экспериментальным:
Экспериментальный API: может быть изменен в следующей версии и может еще не работать отлично!
Следующий подход всегда работал у меня, независимо от используемого BrowserVersion
:
int tries = 5; // Amount of tries to avoid infinite loop
while (tries > 0 && aCondition) {
tries--;
synchronized(page) {
page.wait(2000); // How often to check
}
}
Примечание aCondition
- это то, что вы проверяете. EG:
page.getElementById("loading-text-element").asText().equals("Loading...")
Ответ 4
Ни один из предоставленных мной решений не помог мне. Я закончил с решением Дэн Альвизу + мой собственный взлом:
private WebClient webClient = new WebClient();
public void scrapPage() {
makeWebClientWaitThroughJavaScriptLoadings();
HtmlPage page = login();
//do something that causes JavaScript loading
waitOutLoading(page);
}
private void makeWebClientWaitThroughJavaScriptLoadings() {
webClient.setAjaxController(new AjaxController(){
@Override
public boolean processSynchron(HtmlPage page, WebRequest request, boolean async)
{
return true;
}
});
}
private void waitOutLoading(HtmlPage page) {
while(page.asText().contains("Please wait while loading!")){
webClient.waitForBackgroundJavaScript(100);
}
}
Излишне говорить: "Подождите, пожалуйста, загрузитесь!" должен быть заменен любым текстом, пока отображается ваша страница. Если текст отсутствует, возможно, есть способ проверить наличие какого-либо gif (если он используется). Конечно, вы могли бы просто предоставить достаточно большое миллисекунду значение, если вы чувствуете приключения.