Ссылка на устаревший объект при навигации с использованием Selenium

Я пробовал простую программу, которая перемещается и извлекает данные с новой страницы, возвращается в историю и открывает другую страницу, извлекает данные и так далее, пока все ссылки не будут посещены и данные не будут получены.

Получив результаты на указанном ниже сайте, я пытаюсь просмотреть все ссылки, которые я получаю в первом столбце, открывать эти ссылки одну за другой и извлекать текст с каждой из этих страниц. Но приведенная ниже программа посещает только первую ссылку и выдает исключение StaleElementReferenceException, я пытался использовать Actions, но это не сработало, и я не знаю о JavascriptExecutor. Я также пробовал решения, размещенные на других вопросах SO, один из которых был моим по здесь. Я хотел бы исправить ошибку в приведенном ниже коде и получить рабочий код.

public class Selenium {

    private final static String CHROME_DRIVER = "C:\\Selenium\\chromedriver\\chromedriver.exe";
    private static WebDriver driver = null;
    private static WebDriverWait wait = null;

    private void setConnection() {
        try {
            System.setProperty("webdriver.chrome.driver", CHROME_DRIVER);
            driver = ChromeDriver.class.newInstance();
            wait = new WebDriverWait(driver, 5);
            driver.get("https://sanctionssearch.ofac.treas.gov");
            this.search();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void search() {
        try {
            driver.findElement(By.id("ctl00_MainContent_txtLastName")).sendKeys("Dawood");
            driver.findElement(By.id("ctl00_MainContent_btnSearch")).click();
            this.extractText();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void extractText() {
        try {
            List<WebElement> rows = driver.findElements(By.xpath("//*[@id='gvSearchResults']/tbody/tr"));
            List<WebElement> links = null;
            for (int i = 1; i <= rows.size(); i++) {

                links = driver.findElements(By.xpath("//*[@id='gvSearchResults']/tbody/tr/td[1]/a"));

                for (int j = 0; j < links.size(); j++) {
                    System.out.println(links.get(j).getText() + ", ");
                    links.get(j).click();
                    System.out.println("Afte click");
                    driver.findElement(By.id("ctl00_MainContent_btnBack")).click();
                    this.search();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] ar) {
        Selenium object = new Selenium();
        object.setConnection();
    }

}

person Community    schedule 01.08.2017    source источник
comment
Разве вы не можете просто сделать new ChromeDriver() вместо ChromeDriver.class.newInstance()? К чему это отражение?   -  person M. Prokhorov    schedule 01.08.2017
comment
Нет конкретной причины, по которой я это сделал, не могли бы вы указать ошибку, из-за которой я получаю исключение устаревшего элемента?   -  person    schedule 01.08.2017


Ответы (3)


Как правило, мы будем получать устаревшее исключение, если атрибуты элемента или что-то еще будут изменены после запуска веб-элемента. Например, в некоторых случаях, если пользователь пытается щелкнуть тот же элемент на той же странице, но после обновления страницы, возникает исключение staleelement.

Чтобы преодолеть это, мы можем создать новый веб-элемент на случай, если страница будет изменена или обновлена. Код ниже может дать вам некоторое представление.

Пример:

 webElement element = driver.findElement(by.xpath("//*[@id='StackOverflow']"));
 element.click();
 //page is refreshed
 element.click();//This will obviously throw stale exception

Чтобы преодолеть это, мы можем сохранить xpath в некоторой строке и использовать его для создания нового веб-элемента по ходу дела.

String xpath = "//*[@id='StackOverflow']";
driver.findElement(by.xpath(xpath)).click();
//page has been refreshed. Now create a new element and work on it
driver.fineElement(by.xpath(xpath)).click();   //This works

В этом случае мы собираем группу веб-элементов и итерируем, чтобы получить текст. Но кажется, что есть некоторые изменения в веб-элементах после сбора веб-элементов, и gettext выбрасывает устаревшие. Мы можем использовать цикл и создавать элемент на ходу и получать текст.

for(int i = 0; i<5; i++)
{
  String value = driver.findElement(by.xpath("//.....["+i+"]")).getText);
  System.out.println(value);
}

Надеюсь, это поможет вам. Спасибо.

person santhosh kumar    schedule 01.08.2017
comment
Можете ли вы исправить ошибку в моей программе и вставить ответ? Как вы уже ответили на мой предыдущий вопрос, и я попробовал это решение! Спасибо! - person ; 01.08.2017
comment
Вместо ссылок --› создайте новый веб-элемент и нажмите --›driver.findElements(By.xpath(//*[@id='gvSearchResults']/tbody/tr[+i+]/td[1]/a) ).щелчок(); - person santhosh kumar; 01.08.2017
comment
for (int i = 1; i <= rows.size(); i++) { links = driver.findElements(By.xpath("//*[@id='gvSearchResults']/tbody/tr/td[1]/a")); for (int j = 1; j < links.size(); j++) { WebElement m = driver.findElement(By.xpath("//*[@id='gvSearchResults']/tbody/tr/td[1]/a")); m.click(); System.out.println("Afte click"); driver.findElement(By.id("ctl00_MainContent_btnBack")).click(); this.search(); } } Но все равно не работает :( - person ; 01.08.2017
comment
в xpath нам нужно параметризовать //*[@id='gvSearchResults']/tbod‌​y/tr[1]/td[1]/a --› tr[1]., tr[2] и так далее на - person santhosh kumar; 01.08.2017
comment
Можете ли вы опубликовать измененный блок кода здесь? Я перепробовал почти все и не смог получить это.... было бы очень признательно, если бы вы это сделали! - person ; 01.08.2017
comment
for (int j = 1; j ‹ links.size(); j++) { WebElement m = driver.findElement(By.xpath(//*[@id='gvSearchResults']/tbody/tr[+j+]/td [1]/а)); м.клик(); System.out.println(После клика); driver.findElement(By.id(ctl00_MainContent_btnBack)).cick(); это.поиск(); } - person santhosh kumar; 01.08.2017

Причина, по которой вы получаете исключение StaleElementReference Exception, обычно заключается в том, что вы сохранили элементы в некоторой переменной, однако после этого вы выполнили какое-то действие, и страница изменилась (из-за некоторого ответа ajax), и поэтому ваш сохраненный элемент стал устаревшим.

В таком случае лучшим решением будет не хранить элемент ни в какой переменной.

Это должно работать.

links = driver.findElements(By.xpath("//*[@id='gvSearchResults']/tbody/tr/td[1]/a"));

for (int j = 0; j < links.size(); j++) {
    System.out.println(links.get(j).getText() + ", ");
    driver.findElements(By.xpath("//*[@id='gvSearchResults']/tbody/tr/td[1]/a")).get(j).click();
    System.out.println("Afte click");
    driver.findElement(By.id("ctl00_MainContent_btnBack")).click();
    this.search();
}
person Gaurang Shah    schedule 01.08.2017
comment
Даже это дает исключение устаревшего элемента :( - person ; 01.08.2017
comment
как насчет этого driver.findElement(By.xpath("//*[@id='gvSearchResults']/tbody/tr/td["+j+"]/a")).click(). также попробуйте немного подождать, прежде чем вы получите этот элемент, если вы снова получите это исключение. - person Gaurang Shah; 01.08.2017
comment
где вы получаете это исключение, я имею в виду, в какой строке? - person Gaurang Shah; 01.08.2017
comment
после попытки вашего кода он дает ошибку в backbutton.click() - person ; 01.08.2017
comment
Это означает, что ваш браузер еще не перезагрузил страницу должным образом. Вам придется дождаться завершения загрузки, прежде чем искать и нажимать кнопки. - person M. Prokhorov; 01.08.2017

Пожалуйста, проверьте этот код

   private void extractText() {
        try {
            List<WebElement> rows = driver.findElements(By.xpath("//*[@id='gvSearchResults']/tbody/tr"));
            List<WebElement> links = null;
            System.out.println(rows.size());
            for (int i = 0; i < rows.size(); i++) {
                links = driver.findElements(By.xpath("//*[@id='gvSearchResults']/tbody/tr/td[1]/a"));
                WebElement ele= links.get(0);
                System.out.println(ele.getText() + ", ");
                ele.click();
                System.out.println("After click");
                driver.findElement(By.id("ctl00_MainContent_btnBack")).click();                     
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
person Raja Gopal    schedule 01.08.2017