Wie lässt du Selenium 2.0 auf das Laden der Seite warten?
Wie lässt du Selenium 2.0 auf das Laden der Seite warten?
Antworten:
Sie können pageloaded auch mit dem folgenden Code überprüfen
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"));
Verwenden Sie die Klasse WebDriverWait
Siehe auch hier
Sie können erwarten, ein Element zu zeigen. so etwas wie in 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"));
Wenn Sie die implizite Wartezeit des Treibers festlegen und dann die findElement
Methode für ein Element aufrufen, von dem Sie erwarten, dass es sich auf der geladenen Seite befindet, fragt der WebDriver nach diesem Element, bis er das Element findet oder den Zeitlimitwert erreicht.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Quelle: implizite Wartezeiten
Im Allgemeinen sollte der Webtreiber mit Selenium 2.0 die Kontrolle über den aufrufenden Code erst zurückgeben, wenn festgestellt wurde, dass die Seite geladen wurde. Wenn dies nicht der Fall ist, können Sie anrufen waitforelemement
, wodurch der Anruf wiederholt wird, findelement
bis er gefunden wird oder eine Zeitüberschreitung auftritt (Zeitüberschreitung kann eingestellt werden).
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
und darauf gewartet, dass document.readyState "vollständig" ist. Aufgrund der Hin- und Rückfahrt von Selen zum Browser wird der Rennzustand vermutlich gemildert, und dies funktioniert "immer" für mich. Nach "click ()", wenn ich erwarte, dass eine Seite geladen wird, warte ich explizit (mit WebDriverWait) auf den Readystate. ]
Ruby-Implementierung:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
Sie können die System.out
Zeile entfernen . Es wird zu Debug-Zwecken hinzugefügt.
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");
}
});
}
Alle diese Lösungen sind für bestimmte Fälle in Ordnung, leiden jedoch unter mindestens einem von mehreren möglichen Problemen:
Sie sind nicht allgemein genug - sie möchten, dass Sie im Voraus wissen, dass eine bestimmte Bedingung für die Seite gilt, auf die Sie gehen (z. B. wird ein Element angezeigt).
Sie sind offen für eine Race-Bedingung, bei der Sie ein Element verwenden, das sowohl auf der alten als auch auf der neuen Seite vorhanden ist.
Hier ist mein Versuch einer generischen Lösung, die dieses Problem vermeidet (in Python):
Zunächst eine generische "Warte" -Funktion (verwenden Sie ein WebDriverWait, wenn Sie möchten, ich finde sie hässlich):
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__))
Als nächstes beruht die Lösung auf der Tatsache, dass Selen eine (interne) ID-Nummer für alle Elemente auf einer Seite aufzeichnet, einschließlich der obersten Ebene <html>
Elements . Wenn eine Seite aktualisiert oder geladen wird, erhält sie ein neues HTML-Element mit einer neuen ID.
Angenommen, Sie möchten auf einen Link mit dem Text "Mein Link" klicken, zum Beispiel:
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)
Für mehr pythonische, wiederverwendbare, generische Hilfsmittel können Sie einen Kontextmanager erstellen:
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)
Und dann können Sie es für so ziemlich jede Selen-Wechselwirkung verwenden:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Ich denke, das ist kugelsicher! Was denken Sie?
Mehr Infos in einem Blogbeitrag dazu hier
Sie können auch die Klasse verwenden: ExpectedConditions
um explizit darauf zu warten, dass ein Element auf der Webseite angezeigt wird, bevor Sie weitere Aktionen ausführen können
Mit der ExpectedConditions
Klasse können Sie feststellen, ob ein Element sichtbar ist:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
In der ExpectedConditions class Javadoc
Liste finden Sie alle Bedingungen, die Sie überprüfen können.
Dies scheint eine ernsthafte Einschränkung von WebDriver zu sein. Das Warten auf ein Element bedeutet natürlich nicht, dass die Seite geladen wird. Insbesondere kann das DOM vollständig erstellt werden (Onready-Status), wobei JS noch ausgeführt wird und CSS und Bilder noch geladen werden.
Ich glaube, die einfachste Lösung besteht darin, eine JS-Variable für das Onload-Ereignis festzulegen, nachdem alles initialisiert wurde, und diese JS-Variable in Selen zu überprüfen und auf sie zu warten.
Imrans Antwort für Java 7 erneut aufbereitet:
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");
}
});
Wenn Sie auf das Laden eines bestimmten Elements warten möchten, können Sie die isDisplayed()
Methode für Folgendes verwenden 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;
}
}
(Beispiel aus dem 5-Minuten-Handbuch Erste Schritte )
RenderedWebElement
in der API. Die isDisplayed()
Methode ist jetzt jedoch direkt auf verfügbar WebElement
.
Warten Sie explizit oder bedingt in dieser Wartezeit, bis diese Bedingung erfüllt ist.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Dies wartet 60 Sekunden lang auf jedes Webelement.
Verwenden Sie implizit das Warten auf jedes Element auf der Seite bis zu dieser bestimmten Zeit.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Dies wartet 60 Sekunden lang auf jedes Webelement.
Verwenden Sie implizit das Warten auf jedes Element auf der Seite bis zur angegebenen Zeit.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
Warten Sie 30 Sekunden lang auf jedes Element auf der Seite.
Eine weitere Wartezeit ist Explizites Warten oder bedingtes Warten in dieser Wartezeit bis zur gegebenen Bedingung.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Geben Sie in id die statische Element-ID an, die auf der Seite unterschiedlich angezeigt wird, sobald die Seite geladen wird.
Ich bin überrascht, dass Prädikate nicht die erste Wahl waren, da Sie normalerweise wissen, mit welchen Elementen Sie als Nächstes auf der Seite interagieren, auf die Sie warten. Mein Ansatz war es immer, Prädikate / Funktionen wie waitForElementByID(String id)
und waitForElemetVisibleByClass(String className)
usw. zu erstellen und diese dann zu verwenden und wiederzuverwenden, wo immer ich sie benötige, sei es zum Laden einer Seite oder zum Ändern des Seiteninhalts, auf den ich warte.
Beispielsweise,
In meiner Testklasse:
driverWait.until(textIsPresent("expectedText");
In meiner Testklasse Eltern:
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);
}
Obwohl dies viel zu sein scheint, müssen Sie wiederholt nachsehen, und das Intervall für die Überprüfungsdauer kann zusammen mit der endgültigen Wartezeit vor dem Timeout festgelegt werden. Außerdem werden Sie solche Methoden wiederverwenden.
In diesem Beispiel definiert die Elternklasse und initiiert das WebDriver driver
und das WebDriverWait driverWait
.
Ich hoffe das hilft.
Der beste Weg, um auf das Laden von Seiten zu warten, wenn Sie die Java-Bindungen für WebDriver verwenden, ist die Verwendung des Seitenobjekt-Entwurfsmusters mit PageFactory. Dies ermöglicht es Ihnen, die zu nutzenAjaxElementLocatorFactory
was einfach ausgedrückt als globales Warten auf alle Ihre Elemente fungiert. Es gibt Einschränkungen für Elemente wie Dropboxen oder komplexe Javascript-Übergänge, aber es reduziert die benötigte Codemenge drastisch und beschleunigt die Testzeiten. Ein gutes Beispiel finden Sie in diesem Blogpost. Grundlegendes Verständnis von Core Java wird vorausgesetzt.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
NodeJS-Lösung:
In Nodejs können Sie es über Versprechen bekommen ...
Wenn Sie diesen Code schreiben, können Sie sicher sein, dass die Seite vollständig geladen ist, wenn Sie zum ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
Wenn Sie diesen Code schreiben, navigieren Sie und Selen wartet 3 Sekunden ...
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...
Aus der Selendokumentation:
this.get (url) → Thenable
Plant einen Befehl zum Navigieren zur angegebenen URL.
Gibt ein Versprechen zurück, das aufgelöst wird, wenn das Dokument vollständig geladen wurde .
Hier ist eine Java 8-Version der derzeit am besten bewerteten Antwort :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Wo myDriver
ist ein WebDriver
Objekt (früher deklariert).
Hinweis : Beachten Sie, dass diese Methode ( document.readyState
) nur das DOM überprüft.
Rufen Sie unten Funktion in Ihrem Skript auf, dies wartet, bis die Seite nicht mit Javascript geladen wird
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;
}
});
}
Sie können vom Dokument zu einem Element wechseln, wenn nur ein Teil eines Dokuments geändert wird.
Diese Technik wurde von der Antwort von Sincebasic inspiriert.
SelenWaiter :
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);
}
};
}
}
Und für Sie verwenden Sie es :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Mit der folgenden vorhandenen Methode können Sie die Zeit für pageeLoadTimeout im folgenden Beispiel festlegen. Wenn das Laden der Seite länger als 20 Sekunden dauert, wird eine Ausnahme beim erneuten Laden der Seite ausgelöst
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Sie können explizit warten, bis ein Element auf der Webseite angezeigt wird, bevor Sie Maßnahmen ergreifen können (z. B. 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"));
}});
Dies ist, was ich für ein ähnliches Szenario verwendet habe und es funktioniert gut.
Der beste Weg, den ich gesehen habe, ist die Nutzung der stalenessOf
ExpectedCondition zu verwenden, um darauf zu warten, dass die alte Seite veraltet ist.
Beispiel:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Es wird zehn Sekunden warten, bis das alte HTML-Tag veraltet ist, und dann eine Ausnahme auslösen, wenn dies nicht der Fall ist.
Ich benutze Node + Selenium-Webdriver (welche Version ist jetzt 3.5.0). was ich dafür mache ist:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Sie können wait verwenden. Grundsätzlich gibt es zwei Arten von Wartezeiten in Selen
- Implizites Warten
Dies ist sehr einfach, siehe Syntax unten:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Explizites Warten
Warten Sie explizit oder bedingt, bis eine bestimmte Bedingung erfüllt ist.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Sie können wie andere Eigenschaften verwenden visblityOf()
,visblityOfElement()
Wenn jemand Selenid verwendet:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Weitere Bedingungen finden Sie hier: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
In meinem Fall habe ich Folgendes verwendet, um den Seitenladestatus zu ermitteln. In unserer Anwendung sind GIFs zum Laden vorhanden, und ich höre sie wie folgt an, um unerwünschte Wartezeiten im Skript zu vermeiden.
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")));
}
Wo der xpath das GIF im HTML-DOM findet. Danach können Sie auch Ihre Aktionsmethoden implementieren. Klicken Sie auf.
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();
}
Mann all diese Antworten erfordern zu viel Code. Dies sollte eine einfache Sache sein, da es ziemlich häufig ist.
Warum nicht einfach ein einfaches Javascript mit dem Webdriver injizieren und überprüfen. Dies ist die Methode, die ich in meiner Webscraper-Klasse verwende. Das Javascript ist ziemlich einfach, auch wenn Sie js nicht kennen.
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
Wie Selenium nach einem Klick auf das Laden der Seite wartet, bietet den folgenden interessanten Ansatz:
WebElement
von der alten Seite.WebElement
bis StaleElementReferenceException
die Kasse ausgelöst wird.Beispielcode:
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))
.