Làm thế nào để bạn thực hiện Selenium 2.0 để tải trang?
Làm thế nào để bạn thực hiện Selenium 2.0 để tải trang?
Câu trả lời:
Bạn cũng có thể kiểm tra tải bằng cách sử dụng mã sau
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ử dụng lớp WebDriverWait
Cũng xem tại đây
Bạn có thể mong đợi để hiển thị một số yếu tố. một cái gì đó giống như trong 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"));
Nếu bạn đặt chờ đợi ngầm định của trình điều khiển, sau đó gọi findElement
phương thức trên một phần tử mà bạn mong đợi sẽ ở trên trang được tải, WebDriver sẽ thăm dò phần tử đó cho đến khi tìm thấy phần tử hoặc đạt đến giá trị hết thời gian.
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
nguồn: ngầm-chờ đợi
Nói chung, với Selenium 2.0, trình điều khiển web chỉ nên trả lại quyền điều khiển cho mã cuộc gọi khi nó đã xác định rằng trang đã được tải. Nếu không, bạn có thể gọi waitforelemement
, sẽ quay vòng cuộc gọi findelement
cho đến khi tìm thấy hoặc hết thời gian (có thể đặt thời gian chờ).
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
, chờ đợi tài liệu. YetState sẽ "hoàn tất". Bởi vì chuyến đi khứ hồi từ selenium đến trình duyệt, điều kiện cuộc đua được giảm nhẹ tôi đoán, và điều này "luôn luôn" hoạt động với tôi. Sau khi "click ()" khi tôi mong đợi một trang sẽ tải, tôi rõ ràng chờ đợi (sử dụng WebDriverWait) để đọc. ]
Thực hiện Ruby:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
Bạn có thể loại bỏ các System.out
dòng. Nó được thêm vào cho mục đích gỡ lỗi.
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ất cả các giải pháp này đều ổn đối với các trường hợp cụ thể, nhưng chúng gặp phải ít nhất một trong một vài vấn đề có thể xảy ra:
Chúng không đủ chung chung - họ muốn bạn biết trước thời hạn, một số điều kiện cụ thể sẽ đúng với trang bạn sẽ đến (ví dụ: một số yếu tố sẽ được hiển thị)
Chúng được mở cho một điều kiện cuộc đua trong đó bạn sử dụng một yếu tố thực sự có mặt trên trang cũ cũng như trang mới.
Đây là nỗ lực của tôi tại một giải pháp chung tránh được vấn đề này (bằng Python):
Đầu tiên, một chức năng "chờ" chung (sử dụng WebDriverWait nếu bạn thích, tôi thấy chúng xấu xí):
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__))
Tiếp theo, giải pháp dựa trên thực tế là selen ghi lại số id (nội bộ) cho tất cả các thành phần trên một trang, bao gồm cả thành <html>
phần cấp cao nhất. Khi một trang làm mới hoặc tải, nó nhận được một phần tử html mới với ID mới.
Vì vậy, giả sử bạn muốn nhấp vào liên kết có văn bản "liên kết của tôi" chẳng hạn:
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)
Để có thêm trình trợ giúp chung, có thể tái sử dụng, Pythonic, bạn có thể tạo trình quản lý bối cảnh:
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)
Và sau đó bạn có thể sử dụng nó trên hầu hết mọi tương tác selen:
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
Tôi nghĩ đó là chống đạn! Bạn nghĩ sao?
Thông tin thêm trong một bài đăng blog về nó ở đây
Bạn cũng có thể sử dụng lớp: ExpectedConditions
để chờ một phần tử hiển thị trên trang web một cách rõ ràng trước khi bạn có thể thực hiện bất kỳ hành động nào khác
Bạn có thể sử dụng ExpectedConditions
lớp để xác định xem một phần tử có thể nhìn thấy hay không:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
Xem ExpectedConditions class Javadoc
để biết danh sách tất cả các điều kiện bạn có thể kiểm tra.
Câu trả lời của Imran đã được thử lại cho 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");
}
});
Đây dường như là một hạn chế nghiêm trọng của WebDriver. Rõ ràng việc chờ đợi một phần tử sẽ không ngụ ý trang đang được tải, đặc biệt là DOM có thể được xây dựng hoàn chỉnh (trạng thái sẵn sàng), theo đó, JS vẫn đang thực thi và CSS và hình ảnh vẫn đang tải.
Tôi tin rằng giải pháp đơn giản nhất là đặt biến JS theo sự kiện onload sau khi mọi thứ được khởi tạo và kiểm tra và chờ đợi biến JS này trong Selenium.
Nếu bạn muốn đợi một phần tử cụ thể tải, bạn có thể sử dụng isDisplayed()
phương thức trên 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;
}
}
(Ví dụ từ Hướng dẫn bắt đầu 5 phút )
RenderedWebElement
API. Tuy nhiên, isDisplayed()
phương pháp hiện có sẵn trực tiếp trên WebElement
.
Hoàn toàn chờ đợi hoặc chờ đợi có điều kiện trong chờ đợi này cho đến khi đưa ra điều kiện này.
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
Điều này sẽ chờ cho mọi yếu tố web trong 60 giây.
Sử dụng ngầm chờ đợi mọi yếu tố trên trang cho đến thời điểm đó.
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Điều này sẽ chờ cho mọi yếu tố web trong 60 giây.
Sử dụng ngầm chờ đợi mọi yếu tố trên trang cho đến thời gian nhất định.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
điều này chờ cho mọi phần tử trên trang trong 30 giây.
Một sự chờ đợi khác là chờ đợi một cách rõ ràng hoặc chờ đợi có điều kiện trong sự chờ đợi này cho đến khi có điều kiện nhất định.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Trong id cung cấp id phần tử tĩnh được hiển thị rõ ràng trên trang, ngay khi trang được tải.
Tôi ngạc nhiên rằng các vị từ không phải là lựa chọn đầu tiên vì bạn thường biết phần tử nào bạn sẽ tương tác tiếp theo trên trang bạn đang chờ tải. Biện pháp của tôi đã luôn luôn được xây dựng ra các vị từ / chức năng như waitForElementByID(String id)
và waitForElemetVisibleByClass(String className)
, vv và sau đó sử dụng và tái sử dụng những bất cứ nơi nào tôi cần đến chúng, có thể là cho một tải trang hoặc trang thay đổi nội dung tôi đang chờ đợi trên.
Ví dụ,
Trong lớp kiểm tra của tôi:
driverWait.until(textIsPresent("expectedText");
Trong lớp kiểm tra của tôi phụ huynh:
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);
}
Mặc dù điều này có vẻ rất nhiều, nhưng bạn cần kiểm tra nhiều lần cho bạn và khoảng thời gian kiểm tra có thể được đặt cùng với thời gian chờ cuối cùng trước khi hết thời gian. Ngoài ra, bạn sẽ sử dụng lại các phương pháp như vậy.
Trong ví dụ này, lớp cha được định nghĩa và khởi tạo WebDriver driver
và WebDriverWait driverWait
.
Tôi hi vọng cái này giúp được.
Cách tốt nhất để chờ tải trang khi sử dụng các liên kết Java cho WebDriver là sử dụng mẫu thiết kế Đối tượng trang với PageFactory. Điều này cho phép bạn sử dụng AjaxElementLocatorFactory
cái để đặt nó đơn giản hoạt động như một sự chờ đợi toàn cầu cho tất cả các yếu tố của bạn. Nó có những hạn chế đối với các yếu tố như hộp thả hoặc chuyển đổi javascript phức tạp nhưng nó sẽ làm giảm đáng kể số lượng mã cần thiết và tăng tốc thời gian thử nghiệm. Một ví dụ tốt có thể được tìm thấy trong blogpost này. Hiểu biết cơ bản về Core Java được giả định.
http://startingwithseleniumwebdo.blogspot.ro/2015/02/wait-in-page-factory.html
Giải pháp NodeJS:
Trong Nodejs, bạn có thể nhận được thông qua lời hứa ...
Nếu bạn viết mã này, bạn có thể chắc chắn rằng trang đã được tải đầy đủ khi bạn đến ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
Nếu bạn viết mã này, bạn sẽ điều hướng và selen sẽ đợi 3 giây ...
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...
Từ tài liệu Selenium:
this .get (url) → Có thể
Lên lịch một lệnh để điều hướng đến URL đã cho.
Trả về một lời hứa sẽ được giải quyết khi tài liệu đã tải xong .
Đây là phiên bản Java 8 của câu trả lời được đánh giá cao nhất hiện nay :
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
Trường hợp myDriver
là một WebDriver
đối tượng (khai báo trước đó).
Lưu ý : Lưu ý rằng phương thức này ( document.readyState
) chỉ kiểm tra DOM.
Gọi bên dưới Chức năng trong tập lệnh của bạn, điều này sẽ đợi cho đến khi trang không được tải bằng 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;
}
});
}
Bạn có thể thay đổi từ tài liệu thành một yếu tố, trong trường hợp chỉ một phần của tài liệu được thay đổi.
Kỹ thuật này được lấy cảm hứng từ câu trả lời từ frombasic.
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);
}
};
}
}
Và để bạn sử dụng nó :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
Bạn có thể sử dụng phương thức hiện có bên dưới để đặt thời gian cho pageeLoadTimeout trong ví dụ bên dưới nếu trang mất hơn 20 giây để tải, sau đó nó sẽ ném ngoại lệ tải lại trang
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
Bạn rõ ràng có thể đợi một phần tử hiển thị trên trang web trước khi bạn có thể thực hiện bất kỳ hành động nào (như 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"));
}});
Đây là những gì tôi đã sử dụng cho một kịch bản tương tự và nó hoạt động tốt.
Cách tốt nhất tôi thấy là sử dụng stalenessOf
ExpectedCondition, chờ trang cũ trở nên cũ.
Thí dụ:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
Sẽ đợi mười giây để thẻ HTML cũ trở nên cũ và sau đó ném ngoại lệ nếu điều đó không xảy ra.
Tôi sử dụng nút + selenium-webdo (phiên bản nào là 3.5.0 bây giờ). những gì tôi làm cho điều này là:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
Bạn có thể sử dụng chờ đợi. về cơ bản có 2 loại chờ trong selen
- Chờ đợi ngầm
Điều này rất đơn giản xin vui lòng xem cú pháp dưới đây:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- Chờ đợi rõ ràng
Hoàn toàn chờ đợi hoặc chờ đợi có điều kiện trong chờ đợi này cho đến khi điều kiện được đưa ra.
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
Bạn có thể sử dụng các thuộc tính khác như visblityOf()
,visblityOfElement()
Nếu ai đó sử dụng selenide:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
Các điều kiện khác có thể được tìm thấy ở đây: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
Trong trường hợp của tôi, tôi đã sử dụng như sau để biết trạng thái tải trang. Trong ứng dụng tải gif (s) của chúng tôi có mặt và, tôi lắng nghe họ như sau để loại bỏ thời gian chờ đợi không mong muốn trong tập lệnh.
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")));
}
Trong đó xpath định vị gif trong HTML DOM. Sau này, Bạn cũng có thể thực hiện các phương thức hành động của mình Bấm.
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 tất cả những câu trả lời yêu cầu quá nhiều mã. Đây là một điều đơn giản vì nó khá phổ biến.
Tại sao không chỉ tiêm một số javascript đơn giản với webdo và kiểm tra. Đây là phương pháp tôi sử dụng trong lớp webscraper của mình. Các javascript khá cơ bản ngay cả khi bạn không biết 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
Cách nhận Selenium để chờ tải trang sau khi nhấp chuột cung cấp cách tiếp cận thú vị sau:
WebElement
từ trang cũ.WebElement
cho đến khi StaleElementReferenceException
được ném.Mã mẫu:
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))
.