Bagaimana Anda membuat Selenium 2.0 menunggu halaman dimuat?
Bagaimana Anda membuat Selenium 2.0 menunggu halaman dimuat?
Jawaban:
Anda juga dapat memeriksa pageload menggunakan kode berikut
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"));
Gunakan kelas WebDriverWait
Lihat juga di sini
Anda dapat menampilkan beberapa elemen. sesuatu seperti di 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"));
Jika Anda mengatur tunggu driver, kemudian memanggil findElement
metode pada elemen yang Anda harapkan berada di halaman yang dimuat, WebDriver akan polling untuk elemen itu sampai menemukan elemen atau mencapai nilai batas waktu.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
sumber: implisit-menunggu
Secara umum, dengan Selenium 2.0 driver web hanya boleh mengembalikan kontrol ke kode panggilan setelah ditentukan bahwa halaman telah dimuat. Jika tidak, Anda dapat menelepon waitforelemement
, yang memanggil siklus putaran findelement
sampai ditemukan atau waktu habis (batas waktu dapat diatur).
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
, menunggu dokumen. SudahState menjadi "lengkap". Karena perjalanan pulang-pergi dari selenium ke peramban, kurasa kondisi balap dikurangi, dan ini "selalu" bekerja untuk saya. Setelah "klik ()" ketika saya mengharapkan halaman dimuat, saya secara eksplisit menunggu (menggunakan WebDriverWait) untuk readystate. ]
Implementasi Ruby:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
Anda dapat menghapus System.out
garis. Itu ditambahkan untuk keperluan debug.
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");
}
});
}
Semua solusi ini OK untuk kasus-kasus tertentu, tetapi mereka menderita setidaknya satu dari beberapa masalah yang mungkin terjadi:
Mereka tidak cukup umum - mereka ingin Anda tahu, sebelumnya, bahwa beberapa kondisi tertentu akan benar dari halaman yang Anda tuju (misalnya beberapa elemen akan ditampilkan)
Mereka terbuka untuk kondisi balapan di mana Anda menggunakan elemen yang sebenarnya ada di halaman lama dan juga halaman baru.
Inilah upaya saya pada solusi umum yang menghindari masalah ini (dengan Python):
Pertama, fungsi "tunggu" generik (gunakan WebDriverWait jika Anda suka, saya menganggapnya jelek):
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__))
Selanjutnya, solusinya bergantung pada fakta bahwa selenium mencatat nomor-id (internal) untuk semua elemen pada halaman, termasuk <html>
elemen level atas . Saat halaman disegarkan atau dimuat, ia mendapat elemen html baru dengan ID baru.
Jadi, anggap Anda ingin mengeklik tautan dengan teks "tautan saya" misalnya:
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)
Untuk lebih banyak Pythonic, reusable, helper generik, Anda dapat membuat manajer konteks:
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)
Dan kemudian Anda dapat menggunakannya di hampir semua interaksi selenium:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Saya rasa itu antipeluru! Bagaimana menurut anda?
Info lebih lanjut di posting blog tentang itu di sini
Anda juga dapat menggunakan kelas: ExpectedConditions
untuk secara eksplisit menunggu elemen muncul di halaman web sebelum Anda dapat mengambil tindakan tindakan selanjutnya
Anda bisa menggunakan ExpectedConditions
kelas untuk menentukan apakah suatu elemen terlihat:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
Lihat ExpectedConditions class Javadoc
daftar semua kondisi yang dapat Anda periksa.
Ini tampaknya menjadi batasan serius WebDriver. Jelas menunggu suatu elemen tidak akan menyiratkan halaman yang sedang dimuat, khususnya DOM dapat sepenuhnya membangun (keadaan sudah) dimana JS masih mengeksekusi dan CSS dan gambar masih memuat.
Saya percaya solusi paling sederhana adalah dengan menetapkan variabel JS pada acara onload setelah semuanya diinisialisasi dan periksa dan tunggu variabel JS ini di Selenium.
Jika Anda ingin menunggu elemen tertentu dimuat, Anda dapat menggunakan isDisplayed()
metode ini pada 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;
}
}
(Contoh dari Panduan Memulai 5 Menit )
RenderedWebElement
di API. Namun, isDisplayed()
metode sekarang tersedia langsung di WebElement
.
Menunggu secara eksplisit atau menunggu bersyarat dalam menunggu ini sampai diberikan kondisi ini.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Ini akan menunggu setiap elemen web selama 60 detik.
Gunakan menunggu secara implisit untuk menunggu setiap elemen pada halaman sampai waktu yang diberikan.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Ini akan menunggu setiap elemen web selama 60 detik.
Gunakan tunggu secara implisit untuk menunggu setiap elemen pada halaman sampai waktu yang ditentukan.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
tunggu ini untuk setiap elemen pada halaman selama 30 detik.
Penantian lainnya adalah Penantian secara eksplisit atau penantian bersyarat dalam penantian ini sampai kondisi yang ditentukan.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Dalam id, berikan id elemen statis yang ditampilkan secara berbeda pada halaman, segera setelah halaman dimuat.
Saya terkejut bahwa predikat bukan pilihan pertama karena Anda biasanya tahu elemen apa yang akan Anda interaksi selanjutnya pada halaman yang Anda tunggu muat. Pendekatan saya selalu membangun predikat / fungsi seperti waitForElementByID(String id)
dan waitForElemetVisibleByClass(String className)
, dll. Dan kemudian menggunakan dan menggunakan kembali ini di mana pun saya membutuhkannya, baik itu untuk memuat halaman atau perubahan konten halaman yang saya tunggu.
Sebagai contoh,
Di kelas ujian saya:
driverWait.until(textIsPresent("expectedText");
Di induk kelas uji saya:
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);
}
Meskipun ini kelihatannya banyak, perlu memeriksa berulang kali untuk Anda dan interval seberapa sering untuk memeriksa dapat diatur bersama dengan waktu tunggu terakhir sebelum waktu habis. Anda juga akan menggunakan kembali metode tersebut.
Dalam contoh ini, kelas induk mendefinisikan dan memulai WebDriver driver
dan WebDriverWait driverWait
.
Saya harap ini membantu.
Cara terbaik untuk menunggu pemuatan halaman saat menggunakan binding Java untuk WebDriver adalah dengan menggunakan pola desain Obyek Halaman dengan PageFactory. Ini memungkinkan Anda untuk memanfaatkanAjaxElementLocatorFactory
yang membuatnya hanya bertindak sebagai penantian global untuk semua elemen Anda. Ini memiliki batasan pada elemen-elemen seperti drop-box atau transisi javascript kompleks tetapi secara drastis akan mengurangi jumlah kode yang dibutuhkan dan mempercepat waktu pengujian. Contoh yang baik dapat ditemukan di blogpost ini. Pemahaman dasar Core Java diasumsikan.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
Solusi NodeJS:
Di Nodejs Anda bisa mendapatkannya melalui janji ...
Jika Anda menulis kode ini, Anda dapat memastikan bahwa halaman tersebut dimuat penuh ketika Anda sampai ke ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
Jika Anda menulis kode ini, Anda akan menavigasi, dan selenium akan menunggu 3 detik ...
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...
Dari dokumentasi Selenium:
this.get (url) → Thenable
Jadwalkan perintah untuk menavigasi ke URL yang diberikan.
Mengembalikan janji yang akan diselesaikan saat dokumen selesai dimuat .
Ini adalah versi Java 8 dari jawaban yang paling banyak dipilih saat ini :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Di mana myDriver
adalah WebDriver
objek (dinyatakan sebelumnya).
Catatan : Perlu diketahui bahwa metode ini ( document.readyState
) hanya memeriksa DOM.
Panggil fungsi di bawah ini dalam skrip Anda, ini akan menunggu sampai halaman tidak dimuat menggunakan 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;
}
});
}
Anda dapat mengubah dari dokumen ke elemen, dalam kasus di mana hanya bagian dari dokumen yang diubah.
Teknik ini terinspirasi oleh jawaban dari sincebasic.
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);
}
};
}
}
Dan untuk Anda menggunakannya :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Anda dapat menggunakan metode yang ada di bawah ini untuk mengatur waktu untuk pageeLoadTimeout dalam contoh di bawah ini jika halaman mengambil lebih dari 20 detik untuk memuat, maka itu akan membuang pengecualian dari memuat ulang halaman
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Anda dapat secara eksplisit menunggu sebuah elemen muncul di halaman web sebelum Anda dapat mengambil tindakan apa pun (seperti 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"));
}});
Ini yang saya gunakan untuk skenario yang sama dan berfungsi dengan baik.
Cara terbaik yang saya lihat adalah memanfaatkan stalenessOf
ExpectedCondition, untuk menunggu halaman lama menjadi basi.
Contoh:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Ini akan menunggu selama sepuluh detik untuk tag HTML lama menjadi basi, dan kemudian melemparkan pengecualian jika itu tidak terjadi.
Saya menggunakan node + selenium-webdriver (yang versi 3.5.0 sekarang). apa yang saya lakukan untuk ini adalah:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Anda bisa menggunakan wait. pada dasarnya ada 2 jenis menunggu dalam selenium
- Tunggu implisit
Ini sangat sederhana, silakan lihat sintaksis di bawah ini:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Tunggu eksplisit
Menunggu secara eksplisit atau menunggu bersyarat dalam menunggu ini sampai kondisi yang diberikan terjadi.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Anda dapat menggunakan properti lain seperti visblityOf()
,visblityOfElement()
Jika seseorang menggunakan selenide:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Ketentuan lainnya dapat ditemukan di sini: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
Dalam kasus saya, saya menggunakan yang berikut ini untuk mengetahui status memuat halaman. Dalam aplikasi kami memuat gif (s) hadir dan, saya mendengarkan mereka sebagai berikut untuk menghilangkan waktu tunggu yang tidak diinginkan dalam skrip.
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")));
}
Di mana xpath menemukan gif di HTML DOM. Setelah ini, Anda juga dapat menerapkan metode tindakan Anda. Klik.
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();
}
Man semua jawaban ini membutuhkan kode terlalu banyak. Ini harus menjadi hal yang sederhana karena cukup umum.
Mengapa tidak menyuntikkan beberapa javascript sederhana dengan webdriver dan periksa. Ini adalah metode yang saya gunakan di kelas webscraper saya. Javascript cukup mendasar bahkan jika Anda tidak tahu 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
Cara mendapatkan Selenium untuk menunggu pemuatan halaman setelah klik memberikan pendekatan menarik berikut:
WebElement
dari dari halaman lama.WebElement
sampai StaleElementReferenceException
terlempar.Kode sampel:
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))
.