Seleniumでページの読み込みを待つ


回答:


138

次のコードを使用してページロードを確認することもできます

IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));

 wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));

22
このようなものが組み込まれていると思います。ページの読み込みを待つことは、Web上ではかなり一般的なことです。
PRMan、2014

19
これは本当にうまくいくのでしょうか?多分私はあなたのコードから何かを逃していますが、あなたはdomが準備状態になるのを待っています。ただし、コードの実行速度が速すぎると、前のページがまだアンロードされていない可能性があり、古いページを開いていてもtrueが返されることを考慮してください。現在のページがアンロードされるのを待ってから、上記のコードを呼び出す必要があります。ページのアンロードを検出する方法は、現在のページでwebelementを取得し、古くなるまで待機することです。obeythetestinggoat.com/…–
ジョージ

6
FYI-それでも上記はページが完成したことを保証しません-domの準備ができているということだけです。どのdojo / jqueryでもページ上で動的に要素を構築している可能性があるため、動的要素を操作する前にまず動的要素を待つ必要がある場合があります。
ジョージ

3
このメソッドはDOMのみをチェックすることに注意してください。AjaxまたはAngularJSを使用する場合、document.readyStateで検出できない非同期呼び出しがいくつかあるため、これは機能しません。
Homewrecker 2015

3
これはC#コードです。これは、Javaで動作していない、と質問がについて尋ねたJava
Kingamere

89

クラスWebDriverWaitを使用

こちらもご覧ください

いくつかの要素が表示されることを期待できます。C#のようなもの:

WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));

_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement"));

これはうまくいきました。それは問題を解決するための非常に素晴らしい現代的な方法です。
CrazyDart

3
@ EmmanuelAngelo.R TimeSpanは.Netデータ構造です。
rjzii 14

12
ページに配置される要素がわからない場合はどうなりますか?
JustGoscha 2014

3
これは、ページ全体ではなく、特定の要素の読み込みを待つように機能します。
xyz

1
これは、要素が完全に読み込まれることも、質問に答えることもまったく保証されません。どうすればこれに賛成できますか?
ボリスD.テハロフ2017年

36

ドライバーの暗黙の待機を設定findElementし、ロードされたページにあると予想される要素でメソッドを呼び出すと、WebDriverは、要素が見つかるか、タイムアウト値に達するまでその要素をポーリングします。

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

ソース:暗黙の待機


3
ページの読み込みを待つのに役立ちません。
xyz

つまり、例外が発生する前の10秒間に何かを試みます。そのため、10秒の遅延がかかるかどうかを確認できません。
スカイサイン2016

1
@xyz-なぜ役に立たないのですか?
MasterJoe2 2016

@ testerjoe2特定の要素が見つかるまで待機します。質問は、ページの読み込みを待機する方法についてです。
xyz

35

一般に、Selenium 2.0では、ページが読み込まれたと判断した場合にのみ、Webドライバーは呼び出し元のコードに制御を返す必要があります。そうでない場合は、を呼び出すことができますwaitforelemement。これは、findelementそれが見つかるか、タイムアウトするまで、呼び出しを循環させます(タイムアウトを設定できます)。


2
ポールの答えに追加します。これもstackoverflow.com/questions/5858743/…で確認してください。
2011年

27
残念ながら、Selenium 2はすべてのケースでページのロードを待機しません。たとえば、WebElement:click()は待機せず、これは所属するJavadocで明示的に述べられています。ただし、新しいページが読み込まれるかどうかを確認する方法はわかりません。 If click() causes a new page to be loaded via an event or is done by sending a native event (which is a common case on Firefox, IE on Windows) then the method will not wait for it to be loaded and the caller should verify that a new page has been loaded.
セビ2011

doc から。ロードが完了するまでメソッドはブロックします...
xyz

2
@カルナ:はい、理論的には、それは常にそして実際にそれはほとんどの時間でした。当時Seleniumを使用していたことで、ページの読み込みが完了したと思っていたのに完了していなかったことが明らかになりました。私は最近セレンを使用していませんので、これはそうかもしれないし、そうでないかもしれません。
ポールハドフィールド

3
私は同意します。特にInternet Explorerドライバーはバグがあり、ページがまだ読み込まれている場合でも、すぐに制御を返す場合があります。私の場合は、JavascriptExecutordocument.readyStateが「完了する」のを待機するを使用して待機を追加しました。セレンからブラウザへの往復のため、競合状態は緩和されると思いますが、これは「常に」機能します。「click()」の後、ページがロードされることを期待しているとき、readystateを(WebDriverWaitを使用して)明示的に待機します。]
dmansfield

22

Rubyの実装:

wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
    @driver.execute_script("return document.readyState;") == "complete" 
}

17
Pythonでの同等機能:WebDriverWait(driver、10).until(lambda d:d.execute_script( 'return document.readyState')== 'complete')
blaze

2
Pythonは上記のコードを使用しますが、この行を忘れないでください。| from selenium.webdriver.support.ui import WebDriverWait
t3dodson 14

ページが完全に読み込まれていないときに要素をクリックすると問題が発生しました。Pythonでは、time.sleep(30)を試しました。出来た。ただし、常に最大30秒間待機します。それから私は次のコードを試してみましたが、それは今より速くより効率的です。WebDriverWait(driver、10).until(lambda d:driver.find_element_by_xpath( "// div [。= 'Administration']")。click())
Riaz Ladhani

20

System.out行を削除することができます。デバッグ目的で追加されます。

WebDriver driver_;

public void waitForPageLoad() {

    Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
    wait.until(new Function<WebDriver, Boolean>() {
        public Boolean apply(WebDriver driver) {
            System.out.println("Current Window State       : "
                + String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
            return String
                .valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
                .equals("complete");
        }
    });
}

このヒントをありがとう。私はそれを私のSeleniumHelperに追加します。cf. javabox
boly38

17

これらのソリューションはすべて、特定のケースでは問題ありませんが、考えられるいくつかの問題の少なくとも1つに悩まされています。

  1. それらは十分に一般的ではありません-彼らはあなたが事前に、あなたが行くページにある特定の条件が真であることを知って欲しいです(例えばいくつかの要素が表示されます)

  2. それらは、古いページと新しいページに実際に存在する要素を使用するという競合状態にさらされています。

(Pythonで)この問題を回避する一般的なソリューションでの私の試みは次のとおりです。

まず、一般的な「待機」関数(必要に応じてWebDriverWaitを使用します。醜いものです):

def wait_for(condition_function):
    start_time = time.time()
    while time.time() < start_time + 3:
        if condition_function():
            return True
        else:
            time.sleep(0.1)
    raise Exception('Timeout waiting for {}'.format(condition_function.__name__))

次に、ソリューションは、セレンがトップレベルの<html>要素を含むページ上のすべての要素の(内部)ID番号を記録するという事実に依存しています。ページが更新またはロードされると、新しいIDを持つ新しいhtml要素が取得されます。

たとえば、「my link」というテキストが含まれているリンクをクリックしたいとします。

old_page = browser.find_element_by_tag_name('html')

browser.find_element_by_link_text('my link').click()

def page_has_loaded():
    new_page = browser.find_element_by_tag_name('html')
    return new_page.id != old_page.id

wait_for(page_has_loaded)

よりPythonicで再利用可能な汎用ヘルパーについては、コンテキストマネージャを作成できます。

from contextlib import contextmanager

@contextmanager
def wait_for_page_load(browser):
    old_page = browser.find_element_by_tag_name('html')

    yield

    def page_has_loaded():
        new_page = browser.find_element_by_tag_name('html')
        return new_page.id != old_page.id

    wait_for(page_has_loaded)

そして、ほとんどすべてのセレンの相互作用でそれを使用できます:

with wait_for_page_load(browser):
    browser.find_element_by_link_text('my link').click()

それは防弾だと思います!どう思いますか?

それについてのブログ投稿の詳細はこちら


ソリューションを実装するJavaコードをさらに具体的に検索する前に、私はあなたのWebページを読みました。今のところ何もありません...
アンドリューlorien

11

また、次のクラスを使用して、ExpectedConditionsさらにアクションを実行する前に、要素がWebページに表示されるのを明示的に待機することもできます。

ExpectedConditionsクラスを使用して、要素が表示されるかどうかを判断できます。

WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));

ExpectedConditions class Javadoc確認できるすべての状態のリストについては、を参照してください。


11

イムランの答えは、Java 7のためにリハッシュされました:

    WebDriverWait wait = new WebDriverWait(driver, 30);

    wait.until(new ExpectedCondition<Boolean>() {
        public Boolean apply(WebDriver wdriver) {
            return ((JavascriptExecutor) driver).executeScript(
                "return document.readyState"
            ).equals("complete");
        }
    });

10

これはWebDriverの深刻な制限のようです。明らかに要素を待つことは、ページがロードされていることを意味するわけではありません。特に、DOMは完全に構築でき(ready状態)、JSはまだ実行中で、CSSと画像はまだロードされています。

最も単純な解決策は、すべてが初期化された後、onloadイベントでJS変数を設定し、SeleniumでこのJS変数を確認して待機することだと思います。


あなたのサイトがあなたのサイトを修正するのであれば、それは簡単です!
reinierpost 2012

はい、JavascriptExecutorを使用してjQuery.jsを実行すると、jQueryロードイベントにアクセスできます。ただし、これが必要な場合はまれです。標準のWebdriverには、適切な待機の98%を実行するのに十分な能力があります。
djangofan 2014

@djangofanはその例を見ると素晴らしいでしょう...私はフロントエンドの人なので、JavascriptExecutorがどこでどのように使用されているのかわかりません。
BradGreens 14

@BradGreens - [OK]を、ここに私のプロジェクトを見て:github.com/djangofan/jquery-growl-selenium-example 。その例を完了するための帯域幅がある場合、jQueryは正常に機能しますが、jGrowlをそのテストプロジェクトで動作させることができませんでした。
djangofan 14

1
@BradGreens djangofanのコメントに加えて、ここで私の回答を参照してください:stackoverflow.com/a/24638792/730326
jmathew

9

特定の要素が読み込まれるのを待つ場合は、このisDisplayed()メソッドをで使用できますRenderedWebElement

// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
    // Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
    RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));

    // If results have been returned, the results are displayed in a drop down.
    if (resultsDiv.isDisplayed()) {
      break;
    }
}

5分間の入門ガイドの例


4
1年後(現在のSeleniumバージョン2.23.1)、RenderedWebElementAPIにはありません。ただし、isDisplayed()メソッドはで直接使用できるようになりましたWebElement
PetrJaneček12年

1
回避できる場合、ポーリングはひどいです。
reinierpost 2012

8

この条件が指定されるまで、この待機で明示的に待機または条件付き待機します。

WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));

これにより、すべてのWeb要素が60秒間待機します。

指定された時間まで、ページ上のすべての要素の待機を暗黙的に待機します。

driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);

これにより、すべてのWeb要素が60秒間待機します。


5

指定された時間までページ上のすべての要素の待機を暗黙的に待機します。

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

これは、ページ上のすべての要素を30秒間待機します。

別の待機は、指定された条件までのこの待機での明示的な待機または条件付き待機です。

WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

idには、ページが読み込まれるとすぐにページに表示される静的要素のidを指定します。


4

ロードするのを待っているページで次に操作する要素は通常知っているので、述語が最初の選択肢ではなかったのには驚いています。私のアプローチは常にwaitForElementByID(String id)waitForElemetVisibleByClass(String className)やなどの述語/関数を構築し、ページのロードやページのコンテンツの変更のために、必要に応じてこれらを使用して再利用することでした。

例えば、

私のテストクラスでは:

driverWait.until(textIsPresent("expectedText");

私のテストクラスの親では:

protected Predicate<WebDriver> textIsPresent(String text){
    final String t = text;
    return new Predicate<WebDriver>(){
        public boolean apply(WebDriver driver){
            return isTextPresent(t);
        }
    };
}

protected boolean isTextPresent(String text){
    return driver.getPageSource().contains(text);
}

これは多くのように見えますが、繰り返しチェックを行うので、チェックする頻度の間隔と、タイムアウトになるまでの最終的な待機時間を設定できます。また、そのようなメソッドを再利用します。

この例では、親クラスがとを定義して開始しましWebDriver driverWebDriverWait driverWait

これがお役に立てば幸いです。


これは私を助けます!この素晴らしいサンプルをありがとう。私はそれを私のSeleniumHelperに追加します。cf. javabox
boly38

4

WebDriverのJavaバインディングを使用するときにページのロードを待機する最良の方法は、PageFactoryでページオブジェクトのデザインパターンを使用することです。これは、あなたがAjaxElementLocatorFactoryそれを置くことを利用することを可能にし、あなたのすべての要素に対するグローバルな待機として単に機能します。ドロップボックスや複雑なJavaScriptトランジションなどの要素には制限がありますが、必要なコードの量が大幅に削減され、テスト時間が短縮されます。良い例がこのブログ投稿にあります。Core Javaの基本的な理解を前提としています。

http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html


4

NodeJSソリューション:

Nodejsあなたは約束を経由してそれを得ることができます...

このコードを記述すれば、その時点でページが完全に読み込まれていることを確認できます...

driver.get('www.sidanmor.com').then(()=> {
    // here the page is fully loaded!!!
    // do your stuff...
}).catch(console.log.bind(console));

このコードを書くと、ナビゲートし、セレンは3秒間待機します...

driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...

Seleniumのドキュメントから:

this.get(url)→Thenable

指定されたURLに移動するコマンドをスケジュールします。

ドキュメントの読み込み完了すると解決されるpromiseを返します。

Seleniumのドキュメント(Nodejs)


4

以下は、現在最も支持されている回答の Java 8バージョンです。

WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));

オブジェクトmyDriverはどこにありWebDriverますか(前に宣言)。

:このメソッド(document.readyState)はDOMのみをチェックすることに注意してください。


4

スクリプトの関数の下を呼び出します。これは、JavaScriptを使用してページがロードされなくなるまで待機します

public static boolean isloadComplete(WebDriver driver)
{
    return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
            || ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}

ブール値をvoidに変更しましたが、Chromeでは機能しません
nosequeweaponer '15年

3
/**
 * Call this method before an event that will change the page.
 */
private void beforePageLoad() {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    js.executeScript("document.mpPageReloaded='notYet';");
}

/**
 * Call this method after an event that will change the page.
 * 
 * @see #beforePageLoad
 * 
 *      Waits for the previous page to disappear.
 */
private void afterPageLoad() throws Exception {
    (new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {

        @Override
        public boolean apply(WebDriver driver) {
            JavascriptExecutor js = (JavascriptExecutor) driver;
            Object obj = js.executeScript("return document.mpPageReloaded;");
            if (obj == null) {
                return true;
            }
            String str = (String) obj;
            if (!str.equals("notYet")) {
                return true;
            }
            return false;
        }
    });
}

ドキュメントの一部のみが変更される場合は、ドキュメントから要素に変更できます。

このテクニックは、sincbasicからの回答に触発されました。


3

SeleniumWaiter

import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;

public class SeleniumWaiter {

      private WebDriver driver;

      public SeleniumWaiter(WebDriver driver) {
           this.driver = driver;
      }

      public WebElement waitForMe(By locatorname, int timeout){
           WebDriverWait wait = new WebDriverWait(driver, timeout);
           return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
      }

      public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
            // TODO Auto-generated method stub
            return new Function<WebDriver, WebElement>() {
                 @Override
                 public WebElement apply(WebDriver driver) {
                      return driver.findElement(locator);
                 }
            };
      }
 }

そしてあなたはそれ使う

_waiter = new SeleniumWaiter(_driver);

try {
   _waiter.waitForMe(By.xpath("//..."), 10);
} 
catch (Exception e) {
   // Error
}

3

以下の既存のメソッドを使用して、ページの読み込みに20秒以上かかる場合、以下の例のpageeLoadTimeoutの時間を設定できます。そうすると、ページの再読み込みの例外がスローされます

 WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)

2

要素がウェブページに表示されるのを明示的に待ってから、(element.click()などの)アクションを実行できます。

driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
  .until(new ExpectedCondition<WebElement>(){
        @Override
        public WebElement apply(WebDriver d) {
        return d.findElement(By.id("myDynamicElement"));
}});

これは私が同様のシナリオで使用したものであり、正常に動作します。


ページにajaxがたくさんない限り、driver.getはonload関数が完了するのを待ってからコードに制御を戻します
goh

2

私の簡単な方法:

long timeOut = 5000;
    long end = System.currentTimeMillis() + timeOut;

        while (System.currentTimeMillis() < end) {

            if (String.valueOf(
                    ((JavascriptExecutor) driver)
                            .executeScript("return document.readyState"))
                    .equals("complete")) {
                break;
            }
        }

2

私が見てきた最良の方法は、stalenessOfExpectedCondition を利用して、古いページが古くなるのを待つことです。

例:

WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);

WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));

古いHTMLタグが古くなるまで10秒間待機し、それが発生しない場合は例外をスローします。


1
WebElementが古くなっても、新しいページの読み込みが完了したわけではありません。
Corey Goldberg

もちろん、古いページのアンロードが終了したということです。私の経験では、古いページがいつアンロードされたか、または何らかの理由で停止したかどうかを知ることも同様に重要です。
フォレストホプキンサ2017年

もちろん、通常、stalenessOfを他のテストと組み合わせて使用​​して、完全なアンロード/ロードプロセスを取得します。
フォレストホプキンサ2017年

2

私はnode + selenium-webdriver(現在のバージョンは3.5.0)を使用しています。これのために私がすることは:

var webdriver = require('selenium-webdriver'),
    driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
  return state === 'complete';
}))

2

お待ちいただけます。セレンには基本的に2種類の待機があります

  • 暗黙の待機
  • 明示的な待機

-暗黙の待機

これは非常に簡単です。以下の構文を参照してください。

driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);

-明示的な待機

特定の条件が発生するまで、この待機で明示的に待機または条件付き待機します。

WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

あなたのような他のプロパティを使用することができvisblityOf()visblityOfElement()



2

私の場合、ページの読み込みステータスを知るために次の方法を使用しました。私たちのアプリケーションでは、ロードgifが存在し、次のようにそれらを聞いて、スクリプト内の不要な待機時間を排除します。

public static void processing(){ 
    WebDriverWait wait = new WebDriverWait(driver, 30);
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
    wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}

xpathがHTML DOMでgifを見つける場所。この後、アクションメソッドClickを実装することもできます。

public static void click(WebElement elementToBeClicked){
    WebDriverWait wait = new WebDriverWait(driver, 45);
    wait.until(ExpectedConditions.visibilityOf(element));
    wait.until(ExpectedConditions.elementToBeClickable(element)); 
    wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click(); 
 }

2

これらすべての答えに必要なコードは多すぎます。これはかなり一般的であるため、単純なものでなければなりません。

なぜ単純なJavaScriptをWebドライバーに挿入してチェックしないのか これは、私のWebscraperクラスで使用するメソッドです。JavaScriptは、jsを知らなくてもかなり基本的です。

    def js_get_page_state(self):        
    """
    Javascript for getting document.readyState
    :return: Pages state.

    More Info: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
    """
    ready_state = self.driver.execute_script('return document.readyState')
    if ready_state == 'loading':
        self.logger.info("Loading Page...")
    elif ready_state == 'interactive':
        self.logger.info("Page is interactive")
    elif ready_state == 'complete':
        self.logger.info("The page is fully loaded!")
    return ready_state

1

クリック後にSeleniumがページのロードを待機するようにする方法は、以下の興味深いアプローチを提供します。

  1. WebElement古いページからへの参照を保存します。
  2. リンクをクリックします。
  3. がスローされるWebElementまで、操作を呼び出し続けStaleElementReferenceExceptionます。

サンプルコード:

WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
    try
    {
        link.isDisplayed();
        return false;
    }
    catch (StaleElementReferenceException unused)
    {
        return true;
    }
});

良いアイデア!私はこの状況に対処するために、ページの読み込みの成功、ページの読み込みの成功(反対の言葉がない)の反対を確認することは考えていませんでした。これが最良のオプションかどうかは、StaleElementReferenceExceptionがロードの成功を待つよりも時間がかかるかどうかなどに基づいています。それにもかかわらず、それを行う別の良い方法。
ジョセフオーランド

4
これは、現在のページがロードされているかどうかを通知するのではなく、最後のページ(特に1つの要素)がアンロードされているかどうかを通知します。現在のページが読み込まれるのを待つ必要があります。ところで、上記のコードをに置き換えることができますnew WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(element))
JeffC 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.