Nasıl yapabilirim Selenyum yüke sayfa için 2.0 beklemek?
Nasıl yapabilirim Selenyum yüke sayfa için 2.0 beklemek?
Yanıtlar:
Sayfa yüklenenleri aşağıdaki kodu kullanarak da kontrol edebilirsiniz
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"));
Sınıfı kullan WebDriverWait
Ayrıca bakınız buraya
Bazı öğeleri göstermeyi bekleyebilirsiniz. C # gibi bir şey:
WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));
_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement"));
Sürücünün örtük beklemesini ayarlarsanız, findElement
yöntemi yüklenen sayfada olmasını beklediğiniz bir öğede çağırırsanız , WebDriver öğeyi bulana veya zaman aşımı değerine ulaşıncaya kadar bu öğe için yoklama yapar.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Kaynak: implicit-waits
Genel olarak, Selenium 2.0 ile web sürücüsünün kontrolü yalnızca sayfanın yüklendiğini belirledikten sonra arama koduna döndürmesi gerekir. Başlamazsa waitforelemement
, hangi çağrıyı findelement
bulunana veya zaman aşımına uğrayacak şekilde çevirir (zaman aşımı ayarlanabilir).
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 "tam" olmasını bekliyorum. Selenyumdan tarayıcıya gidiş dönüş nedeniyle yarış durumu hafifletildi sanırım ve bu "her zaman" benim için çalışıyor. Bir sayfanın yüklenmesini beklediğimde "click ()" den sonra, readystate için açıkça (WebDriverWait kullanarak) beklerim. ]
Ruby uygulaması:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
System.out
Çizgiyi kaldırabilirsiniz . Hata ayıklama amacıyla eklenir.
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");
}
});
}
Tüm bu çözümler belirli durumlar için uygundur, ancak birkaç olası sorundan en az birini yaşarlar:
Yeterince genel değildirler - önceden, belirli bir koşulun gideceğiniz sayfa için geçerli olacağını bilmenizi isterler (örneğin, bazı öğeler görüntülenir)
Bunlar, hem eski sayfada hem de yeni sayfada mevcut olan bir öğeyi kullandığınız bir yarış koşullarına açıktır.
İşte bu sorunu (Python'da) önleyen genel bir çözüm denemem:
İlk olarak, genel bir "bekle" fonksiyonu (isterseniz bir WebDriverWait kullanın, onları çirkin buluyorum):
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__))
Daha sonra çözüm, selenyumun, üst düzey <html>
öğe de dahil olmak üzere bir sayfadaki tüm öğeler için (dahili) bir kimlik numarası kaydetmesine dayanır . Bir sayfa yenilendiğinde veya yüklendiğinde, yeni bir kimliğe sahip yeni bir html öğesi alır.
Örneğin, "bağlantım" metnine sahip bir bağlantıyı tıklamak istediğinizi varsayarsak, örneğin:
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)
Daha fazla Pythonic, yeniden kullanılabilir, genel yardımcı için bir içerik yöneticisi yapabilirsiniz:
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)
Ve sonra hemen hemen tüm selenyum etkileşimlerinde kullanabilirsiniz:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Sanırım bu kurşun geçirmez! Ne düşünüyorsun?
Bu konuda bir blog yazısında daha fazla bilgi
Ayrıca, ExpectedConditions
herhangi bir işlem yapmadan önce bir öğenin web sayfasında görünmesini açıkça beklemek için class: öğesini kullanabilirsiniz.
ExpectedConditions
Bir öğenin görünür olup olmadığını belirlemek için sınıfı kullanabilirsiniz :
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
ExpectedConditions class Javadoc
Kontrol edebileceğiniz tüm koşulların listesi için bkz .
İmran'ın yanıtı Java 7 için yeniden düzenlendi:
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");
}
});
Bu WebDriver'ın ciddi bir kısıtlaması gibi görünüyor. Bir öğeyi beklemek, sayfanın yüklenmekte olduğu anlamına gelmez, özellikle DOM tamamen oluşturulabilir (zaten devlet), böylece JS hala yürütülüyor ve CSS ve görüntüler hala yükleniyor.
Her şey başlatıldıktan sonra onload olay üzerine bir JS değişkeni ayarlamak ve Selenium bu JS değişkeni beklemek ve beklemek en basit çözüm olduğuna inanıyorum.
Belirli bir öğenin yüklenmesini beklemek istiyorsanız, isDisplayed()
yöntemi aşağıdakiler üzerinde kullanabilirsiniz 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
. Ancak, isDisplayed()
yöntem artık doğrudan kullanılabilir WebElement
.
Açıkça bekleyin ya da koşullu bekleyin, bu koşul verilene kadar bekleyin.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Bu, her web öğesi için 60 saniye bekleyecektir.
Sayfadaki her öğenin verilen süreye kadar beklemesini dolaylı olarak kullanın.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Bu, her web öğesi için 60 saniye bekleyecektir.
Belirli bir zamana kadar sayfadaki her öğenin beklemesini dolaylı olarak kullanın.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
bu sayfadaki her öğe için 30 saniye bekleyin.
Başka bir bekleme, belirli bir duruma gelene kadar bu bekleyişte açıkça beklemek veya koşullu beklemedir.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
İd'de, sayfa yüklenir yüklenmez sayfada farklı şekilde görüntülenen statik öğe kimliği verin.
Yüklemeyi beklediğiniz sayfada genellikle hangi öğeyle etkileşime gireceğinizi bildiğiniz için tahminlerin ilk seçenek olmadığına şaşırıyorum. Benim yaklaşımım her zaman waitForElementByID(String id)
,waitForElemetVisibleByClass(String className)
ve sonra bunları beklediğim sayfa yükü veya sayfa içeriği değişikliği için ihtiyaç duyduğum her yerde kullanmak ve yeniden kullanmak olmuştur.
Örneğin,
Test sınıfımda:
driverWait.until(textIsPresent("expectedText");
Test sınıfı üstümde:
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);
}
Bu çok fazla gibi görünse de, sizin için tekrar tekrar kontrol etmeye özen gösterir ve zaman aşımına uğramadan önce nihai bekleme süresi ile birlikte ne sıklıkta kontrol edilebileceğine dair aralık ayarlanabilir. Ayrıca, bu yöntemleri yeniden kullanacaksınız.
Bu örnekte, ve sınıfı üst WebDriver driver
ve WebDriverWait driverWait
.
Umarım bu yardımcı olur.
WebDriver için Java bağlarını kullanırken sayfa yüklemelerini beklemenin en iyi yolu, PageFactory ile Sayfa Nesnesi tasarım desenini kullanmaktır. Bu, AjaxElementLocatorFactory
hangi öğeyi koyacağınızı tüm öğeleriniz için küresel bir bekleme görevi görmenizi sağlar. Drop-box veya karmaşık javascript geçişleri gibi öğeler üzerinde sınırlamalar vardır, ancak gerekli kod miktarını önemli ölçüde azaltacak ve test sürelerini hızlandıracaktır. Bu blog yazısında iyi bir örnek bulunabilir. Core Java'nın temel olarak anlaşıldığı varsayılmaktadır.
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
NodeJS Çözümü:
In Nodejs Eğer vaat yoluyla alabilirsiniz ...
Bu kodu yazarsanız, bu sayfaya ulaştığınızda sayfanın tamamen yüklendiğinden emin olabilirsiniz ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
Bu kodu yazarsanız, navigasyon yaparsınız ve selenyum 3 saniye bekleyecektir ...
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...
Selenyum belgelerinden:
this.get (url) → Sonradan
Belirtilen URL'ye gitmek için bir komut zamanlar.
Belge yüklemesi bittiğinde çözülecek bir söz verir .
Şu anda en çok oylanan cevabın Java 8 sürümü :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
myDriver
Bir WebDriver
nesne nerede (daha önce beyan edilmiş).
Not : Bu yöntemin ( document.readyState
) yalnızca DOM'yi kontrol ettiğini unutmayın.
Komut dosyanızdaki fonksiyonun altında arayın, sayfa javascript kullanılarak yüklenene kadar bekler
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;
}
});
}
Belgenin yalnızca bir bölümünün değişmesi durumunda, belgeden bir öğeye geçiş yapabilirsiniz.
Bu teknik, sincebasic'in cevabından ilham aldı.
SelenyumWaiter :
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);
}
};
}
}
Ve onu kullanmak için :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Sayfanın yüklenmesi 20 saniyeden uzun sürüyorsa, aşağıdaki örnekte pageeLoadTimeout zamanını ayarlamak için aşağıdaki mevcut yöntemi kullanabilirsiniz, ardından sayfanın yeniden yüklenmesi için bir istisna atar
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Herhangi bir işlem yapmadan önce bir öğenin web sayfasında görünmesini açıkça bekleyebilirsiniz (element.click () gibi)
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"));
}});
Benzer bir senaryo için kullandığım bu ve iyi çalışıyor.
Gördüğüm en iyi yol, stalenessOf
, eski sayfanın eski haline gelmesini beklemek için ExpectedCondition'ı .
Misal:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Eski HTML etiketinin eski hale gelmesi on saniye bekleyecek ve sonra gerçekleşmezse bir istisna atacaktır.
Düğüm + selenyum-webdriver kullanıyorum (hangi sürüm şimdi 3.5.0). bunun için ne yapıyorum:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Wait kullanabilirsiniz. selenyumda temel olarak 2 tip bekleme vardır
- Örtük bekleme
Bu çok basit, lütfen aşağıdaki sözdizimine bakın:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Açık bekle
Belirli bir koşul oluşana kadar bu bekleyişte açıkça bekleyin veya koşullu bekleyin.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Gibi diğer özellikleri kullanabilirsiniz visblityOf()
,visblityOfElement()
Birisi selenide kullanıyorsa:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Daha fazla koşul burada bulunabilir: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
Benim durumumda, sayfa yükleme durumunu bilmek için aşağıdakileri kullandım. Bizim uygulama yükleme gif (ler) mevcuttur ve ben, ben komut dosyasında istenmeyen bekleme süresini ortadan kaldırmak için aşağıdaki gibi onları dinlerim.
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")));
}
Burada xpath, HTML DOM'deki gif'i bulur. Bundan sonra, eylem yöntemlerinizi de uygulayabilirsiniz Tıklayın.
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();
}
Dostum, tüm bu cevaplar çok fazla kod gerektiriyor. Bu oldukça yaygın olduğu için basit bir şey olmalı.
Neden sadece webdriver ve kontrol ile basit bir javascript enjekte değil. Bu benim web scraper sınıfımda kullandığım yöntem. JavaScript bilmeseniz bile javascript oldukça basittir.
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
Bir tıklamadan sonra Selenyum'un sayfa yüklemesini beklemesi nasıl yapılır , aşağıdaki ilginç yaklaşımı sağlar:
WebElement
Eski sayfadaki bir öğeye referans depolayın .WebElement
kadar işlemleri çağırmaya devam edin StaleElementReferenceException
.Basit kod:
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))
.