#java #selenium #xpath
Вопрос:
я пытаюсь мгновенно получить данные из активного элемента с помощью Xpath, но при запуске проекта я получил эту ошибку
Исключение в потоке «главная» org.openqa.selenium.Исключение StaleElementReferenceException: устаревший элемент ссылка: элемент не прикреплен к документу страницы
package read;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class ResdeStoFromBrowser {
public static final String TEXT_RESET = "u001B[0m";
public static final String TEXT_RED = "u001B[31m";
public static final String TEXT_GREEN = "u001B[32m";
public static final String TEXT_CYAN = "u001B[36m";
public void ResdeSto() throws InterruptedException {
System.setProperty("webdriver.chrome.driver", "C:\Users\owner\....\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.navigate().to("https:.........");
driver.manage().window().maximize();
while (true) {
TimeUnit.SECONDS.sleep(1);
String sel2 = driver.findElement(By.xpath("/html/body/div[2]/div[1]/div/div[2]/div[2]/div[2]/div[2]/div[1]/div[1]/span[3]")).getText();
System.out.println(TEXT_GREEN " " sel2 TEXT_RESET " ");
}
}
}
Комментарии:
1. Почему в конце у вас бесконечный цикл?
2. Продолжать бесконечно получать данные из источника !!
3. Это не имеет смысла, и это может стать проблемой.
4. Можете ли вы, пожалуйста, добавить HTML-код или URL-адрес
5. @Sonali Добавление HTML в сообщение не поможет, потому что содержимое страницы меняется.
Ответ №1:
Вы написали: «Я пытаюсь мгновенно получить данные…» Ну, это может быть проблемой.
StaleElementReferenceException
выбрасываются, когда веб-элемент получен до обновления содержимого веб-страницы или во время процесса обновления. Другими словами, она получается преждевременно. Решение состоит в том, чтобы подождать, пока страница полностью не загрузится.
«Элемент не прикреплен к документу страницы» означает, что веб-элемента, вероятно, больше нет в документе HTML.
Существует два способа получения веб-элемента:
WebDriver driver = new ChromeDriver();
driver.findElement(...);
Предполагая, что вы находитесь на правильной странице, findElement
попытаемся без промедления найти нужный элемент. Если страница находится в процессе загрузки, это, скорее всего, приведет к ошибке, упомянутой в сообщении OP. Правильный способ исправить это-добавить неявное ожидание.
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // Time amount and time units are arbitrary.
// get to the page...
driver.findElement(...);
В приведенном выше фрагменте кода с момента implicitlyWait
вызова до конца тестовой сессии, перед любой попыткой получить веб-элемент, приложение будет ждать минимальное время, переданное функции; в моем примере это 10 секунд.
Лучший способ сделать это-использовать WebDriverWait
класс.
WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, 10); // max. wait time set to 10 seconds with default 500 ms polling interval
WebDriverWait
имеет вариант с тремя аргументами, где третьим аргументом является интервал опроса в миллисекундах. Например, WebDriverWait(driver, 10, 100)
будет ждать максимум 10 секунд, опрашивая каждые 100 мс. Как только wait
объект будет получен, он будет использован для получения WebElement
объекта, передающего правильное ожидаемое условие, предусмотренное ExpectedConditions
классом. Например, дождаться, пока кнопка станет «кликабельной» (как видимой, так и включенной).
WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath(XPATH EXPRESSION HERE)));
button.click();
Этот подход, предполагающий, что вы уже находитесь на правильной странице, попытается найти нужный компонент за максимальное время, прошедшее с WebDriverWait
конструктором до истечения времени ожидания. Но, если компонент найден И ожидаемое условие достигнуто до истечения времени ожидания, он вернет запрошенный компонент. Это лучший способ избежать устаревшего элемента (хотя и не полностью).
Вероятно, лучший подход-это объединить оба подхода.
Для начала установите неявное время ожидания, как только будет получен экземпляр веб-драйвера
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Затем перейдите на страницу
driver.navigate().to("https:.........");
Наконец, используйте второй подход для получения веб-элемента
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("...")));
button.click();
Когда неявное и явное ожидания используются вместе, вероятность возникновения проблем с устаревшими элементами сводится почти к нулю. Вам просто нужно быть умным и всегда получать веб-элемент непосредственно перед тем, как вы собираетесь его использовать…. И ОПРЕДЕЛЕННО НЕ помещайте подобный код в бесконечный цикл.
В принципе, этот код работает … вроде того.
public class TickerPageTest {
@Test
public void printTickerValueEndlessLoop() {
System.setProperty("webdriver.chrome.driver", "F:\Users\Hector\webdriver\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://coincheck.com/exchange/tradeview");
while (true) {
WebDriverWait wait = new WebDriverWait(driver, 10, 10);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[2]/div[1]/div/div[2]/div[2]/div[2]/div[2]/div[1]/div[1]/span[3]")));
System.out.println(element.getTagName() ":" element.getText());
}
}
}
Приведенный выше код выводит следующее (большую часть времени)
span:5898999
...
span:5900895
...
span:5898999
Лучше всего завернуть взаимодействие с веб-элементом в попытку/уловку, где вы поймаете StaleElementReferenceException
, чтобы проигнорировать его и продолжить. В реальном тесте на Селен вы можете использовать эту стратегию, чтобы повторить попытку получения пропущенного элемента, но в этом случае вам это не нужно.
try {
System.out.println(element.getTagName() ":" element.getText());
} catch (StaleElementReferenceException e) {
System.err.println("Test lost sync... this will be ignored.");
}
Когда я сделал это, после нескольких сотен строк (или больше) Мне удалось уловить потерю синхронизации:
span:5906025
Test lost sync... this will be ignored.
span:5906249
Но, как вы можете видеть, я просто проигнорировал это и перешел к следующему обновлению.
Комментарии:
1. @DAROUYABDELKARIM-это общедоступный URL-адрес, который вы тестируете? Если да, опубликуйте URL-адрес.
2. я не знаю, можете ли вы увидеть это в своей стране [ coincheck.com/exchange/tradeview]
3. @DAROUYABDELKARIM Я вижу, что ты пытаешься сделать. НО вы должны понять, что я пытался сказать: страница постоянно обновляется. Это будет непросто.
4. извините за мое невежество, но когда вы говорите «хитрый», вы хотите сказать «Легальный»??
5. @DAROUYABDELKARIM мой предложенный код отлично работает для меня. Я буду публиковать.