web-dev-qa-db-ja.com

HTMLUnitはJavaScriptを待ちません

HtmlUnitを使用してHTMLスナップショットを作成したいGWTベースのページがあります。ページは製品のAjax/JavaScript情報を使用してロードされるため、約1秒間、Loading ...メッセージが表示され、その後コンテンツが表示されます。

問題は、HtmlUnitが情報をキャプチャしていないようで、取得しているのは「Loading ...」スパンだけです。

以下は、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());

何か案は...?

20
Joly

お返事ありがとうございます。私は実際に自分で解決策を見つけたので、これをもっと早く報告するべきでした。どうやらFFでWebClientを初期化するとき:

WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3_6);

動作しているようです。デフォルトのコンストラクターでWebClientを初期化する場合、デフォルトでIE7を使用します。FFはAjaxのサポートが優れており、使用する推奨エミュレーターです。

19
Joly

デフォルトでは、NicelyResynchronizingAjaxControllerは、元のスレッドを追跡することにより、ユーザーアクションによって引き起こされたAJAX呼び出しのみを再同期します。おそらく、GWTが生成したJavaScriptがNicelyResynchronizingAjaxControllerが待機したくない他のスレッド。

元のスレッドに関係なく、すべてと同期する独自のAjaxControllerを宣言してみてください。

webClient.setAjaxController(new AjaxController(){
    @Override
    public boolean processSynchron(HtmlPage page, WebRequest request, boolean async)
    {
        return true;
    }
});
14
Dan Alvizu

これまでに提供された解決策のどれも私にとってうまくいきませんでした。私は Dan Alvizuのソリューション +私のハックで終わりました:

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が存在するかどうかを確認する方法がある可能性があります(使用されている場合)。もちろん、冒険したい場合は、十分に大きなミリ秒の値を指定することもできます。

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は、確認しているものです。例えば:

page.getElementById("loading-text-element").asText().equals("Loading...")
3
Mosty Mostacho