回答:
次のコードを使用してページロードを確認することもできます
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"));
クラス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"));
ドライバーの暗黙の待機を設定findElement
し、ロードされたページにあると予想される要素でメソッドを呼び出すと、WebDriverは、要素が見つかるか、タイムアウト値に達するまでその要素をポーリングします。
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
ソース:暗黙の待機
一般に、Selenium 2.0では、ページが読み込まれたと判断した場合にのみ、Webドライバーは呼び出し元のコードに制御を返す必要があります。そうでない場合は、を呼び出すことができますwaitforelemement
。これは、findelement
それが見つかるか、タイムアウトするまで、呼び出しを循環させます(タイムアウトを設定できます)。
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.
JavascriptExecutor
document.readyStateが「完了する」のを待機するを使用して待機を追加しました。セレンからブラウザへの往復のため、競合状態は緩和されると思いますが、これは「常に」機能します。「click()」の後、ページがロードされることを期待しているとき、readystateを(WebDriverWaitを使用して)明示的に待機します。]
Rubyの実装:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
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");
}
});
}
これらのソリューションはすべて、特定のケースでは問題ありませんが、考えられるいくつかの問題の少なくとも1つに悩まされています。
それらは十分に一般的ではありません-彼らはあなたが事前に、あなたが行くページにある特定の条件が真であることを知って欲しいです(例えばいくつかの要素が表示されます)
それらは、古いページと新しいページに実際に存在する要素を使用するという競合状態にさらされています。
(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()
それは防弾だと思います!どう思いますか?
また、次のクラスを使用して、ExpectedConditions
さらにアクションを実行する前に、要素がWebページに表示されるのを明示的に待機することもできます。
ExpectedConditions
クラスを使用して、要素が表示されるかどうかを判断できます。
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
ExpectedConditions class Javadoc
確認できるすべての状態のリストについては、を参照してください。
これはWebDriverの深刻な制限のようです。明らかに要素を待つことは、ページがロードされていることを意味するわけではありません。特に、DOMは完全に構築でき(ready状態)、JSはまだ実行中で、CSSと画像はまだロードされています。
最も単純な解決策は、すべてが初期化された後、onloadイベントでJS変数を設定し、SeleniumでこのJS変数を確認して待機することだと思います。
特定の要素が読み込まれるのを待つ場合は、この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;
}
}
RenderedWebElement
APIにはありません。ただし、isDisplayed()
メソッドはで直接使用できるようになりましたWebElement
。
この条件が指定されるまで、この待機で明示的に待機または条件付き待機します。
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
これにより、すべてのWeb要素が60秒間待機します。
指定された時間まで、ページ上のすべての要素の待機を暗黙的に待機します。
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
これにより、すべてのWeb要素が60秒間待機します。
指定された時間までページ上のすべての要素の待機を暗黙的に待機します。
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を指定します。
ロードするのを待っているページで次に操作する要素は通常知っているので、述語が最初の選択肢ではなかったのには驚いています。私のアプローチは常に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 driver
たWebDriverWait driverWait
。
これがお役に立てば幸いです。
WebDriverのJavaバインディングを使用するときにページのロードを待機する最良の方法は、PageFactoryでページオブジェクトのデザインパターンを使用することです。これは、あなたがAjaxElementLocatorFactory
それを置くことを利用することを可能にし、あなたのすべての要素に対するグローバルな待機として単に機能します。ドロップボックスや複雑なJavaScriptトランジションなどの要素には制限がありますが、必要なコードの量が大幅に削減され、テスト時間が短縮されます。良い例がこのブログ投稿にあります。Core Javaの基本的な理解を前提としています。
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
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を返します。
以下は、現在最も支持されている回答の 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のみをチェックすることに注意してください。
スクリプトの関数の下を呼び出します。これは、JavaScriptを使用してページがロードされなくなるまで待機します
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
/**
* 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からの回答に触発されました。
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
}
要素がウェブページに表示されるのを明示的に待ってから、(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"));
}});
これは私が同様のシナリオで使用したものであり、正常に動作します。
私が見てきた最良の方法は、stalenessOf
ExpectedCondition を利用して、古いページが古くなるのを待つことです。
例:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
古いHTMLタグが古くなるまで10秒間待機し、それが発生しない場合は例外をスローします。
私は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種類の待機があります
-暗黙の待機
これは非常に簡単です。以下の構文を参照してください。
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
-明示的な待機
特定の条件が発生するまで、この待機で明示的に待機または条件付き待機します。
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
あなたのような他のプロパティを使用することができvisblityOf()
、visblityOfElement()
誰かがセレン化物を使用する場合:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
その他の条件については、こちらをご覧ください:http : //selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
私の場合、ページの読み込みステータスを知るために次の方法を使用しました。私たちのアプリケーションでは、ロード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();
}
これらすべての答えに必要なコードは多すぎます。これはかなり一般的であるため、単純なものでなければなりません。
なぜ単純な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
クリック後にSeleniumがページのロードを待機するようにする方法は、以下の興味深いアプローチを提供します。
WebElement
古いページからへの参照を保存します。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;
}
});
new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(element))
。