Selenium Web 驱动程序 - 在循环中等待 (Java)

Posted

技术标签:

【中文标题】Selenium Web 驱动程序 - 在循环中等待 (Java)【英文标题】:Selenium web driver - Waiting within loop (Java) 【发布时间】:2020-03-04 15:29:12 【问题描述】:

我见过很多方法(such as this one)等待 Selenium Web 驱动程序(特别是 Java)。但是,在这里应用这些方法似乎不起作用。

我正在尝试通过遍历哈希表中的值来测试用户查询结果。我在下面的代码中尝试了两种方法:等待 document.readyState 和加载类选择的项目。但是,似乎列表正在创建所有内容,而没有留出完成元素刷新的时间。

package newproject;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;

import org.openqa.selenium.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
//import org.openqa.selenium.chrome.ChromeDriver;

public class MyClass 
  public static void main(String[] args) 
  System.setProperty("webdriver.gecko.driver", "/Users/niunani/Selenium/geckodriver");
  WebDriver driver = new FirefoxDriver();
  driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

  String baseUrl = "https://www.zillow.com/san-diego-ca-92109/";

  //get price button and click
  WebElement priceButton = driver.findElement(By.id("price"));
  priceText = priceButton.getText();
  System.out.println(priceText);
  //priceButton.click();

  Map<String, List<String>> priceTestCases = new HashMap<String, List<String>>();

  List<String> threeHundThouSet = new ArrayList<String>();
  threeHundThouSet.add("400000");
  threeHundThouSet.add("500000");
  threeHundThouSet.add("600000");
  threeHundThouSet.add("700000");
  threeHundThouSet.add("800000");
  threeHundThouSet.add("900000");
  threeHundThouSet.add("1000000");

  List<String> fourHundThouSet = new ArrayList<String>();
  fourHundThouSet.add("500000");
  fourHundThouSet.add("600000");
  fourHundThouSet.add("700000");
  fourHundThouSet.add("800000");
  fourHundThouSet.add("900000");
  fourHundThouSet.add("1000000");

  List<String> fiveHundThouSet = new ArrayList<String>();
  fiveHundThouSet.add("600000");
  fiveHundThouSet.add("700000");
  fiveHundThouSet.add("800000");
  fiveHundThouSet.add("900000");
  fiveHundThouSet.add("1000000");

  priceTestCases.put("300000", threeHundThouSet);
  priceTestCases.put("400000", fourHundThouSet);
  priceTestCases.put("500000", fiveHundThouSet);

  WebElement priceExposedMin = driver.findElement(By.id("price-exposed-min"));

  WebElement priceExposedMax = driver.findElement(By.id("price-exposed-max"));

  WebElement priceDoneButton = driver.findElement(By.xpath("/html/body/div[1]/div[6]/div/div[1]/div[1]/div[2]/div[2]/div/div/div/button"));

  priceButton.click();
  for (Map.Entry<String, List<String>> entry : priceTestCases.entrySet()) 
      String key = entry.getKey();
      List<String> values = entry.getValue();
      System.out.println("Key = " + key);
      System.out.println("Values = " + values + "n");
      //priceExposedMin.clear();
      for (int i=0;i<20;i++) 
          priceExposedMin.sendKeys(Keys.BACK_SPACE);
      
      priceExposedMin.sendKeys(key);
      for (String maxPrice : values) 
          System.out.println(maxPrice);
          //priceExposedMax.clear();
          //wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"price-exposed-max\"]"))).clear();
          for (int i=0;i<20;i++) 
              priceExposedMax.sendKeys(Keys.BACK_SPACE);
          
          priceExposedMax.sendKeys(maxPrice);
          priceDoneButton.click();

          //ONE WAY: wait for document.readyState
          new WebDriverWait(driver, 30).until(
                  webDriver -> ((javascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));

          //SECOND WAY: Wait for 30 sec until AJAX search load the content
          //new WebDriverWait(driver,30).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.className("list-card-price")));

          Integer countWrong = 0;
          List<WebElement> returnPrices = driver.findElements(By.className("list-card-price"));
          System.out.println(returnPrices);
          for (WebElement priceElement : returnPrices) 
              String priceString = priceElement.getText();
              priceString = priceString.replace("Est. $", "");
              priceString = priceString.replace("$", "");
              priceString = priceString.replace(",", "");
              Integer price = Integer.parseInt(priceString);
              if (price > Integer.parseInt(maxPrice)) 
                  countWrong++;
                  System.out.println("Over price : " + Integer.toString(price));
              
              System.out.println("This price : " + Integer.toString(price));

          
          System.out.println("Incorrect query result: " + Integer.toString(countWrong)) ;
          priceButton.click();
      
  

  

我有时会出现以下错误,这实际上可能是在元素更新时。我正在寻找可以解决此问题的解决方案:

Exception in thread "main" org.openqa.selenium.StaleElementReferenceException: The element reference of <div class="list-card-price"> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed
For documentation on this error, please visit: https://www.seleniumhq.org/exceptions/stale_element_reference.html
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:25:48'
System info: host: 'Nhus-MacBook-Pro.local', ip: 'fe80:0:0:0:27:7d6f:961a:384a%en0', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.14', java.version: '1.8.0_221'
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities acceptInsecureCerts: true, browserName: firefox, browserVersion: 70.0.1, javascriptEnabled: true, moz:accessibilityChecks: false, moz:buildID: 20191030021342, moz:geckodriverVersion: 0.26.0, moz:headless: false, moz:processID: 9634, moz:profile: /var/folders/8c/whfw1mpd5tq..., moz:shutdownTimeout: 60000, moz:useNonSpecCompliantPointerOrigin: false, moz:webdriverClick: true, pageLoadStrategy: normal, platform: MAC, platformName: MAC, platformVersion: 18.0.0, rotatable: false, setWindowRect: true, strictFileInteractability: false, timeouts: implicit: 0, pageLoad: 300000, script: 30000, unhandledPromptBehavior: dismiss and notify
Session ID: b93bceb8-123a-b546-8743-5c402cd8b341
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:285)
    at org.openqa.selenium.remote.RemoteWebElement.isDisplayed(RemoteWebElement.java:326)
    at org.openqa.selenium.support.ui.ExpectedConditions$8.apply(ExpectedConditions.java:233)
    at org.openqa.selenium.support.ui.ExpectedConditions$8.apply(ExpectedConditions.java:228)
    at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:249)
    at newproject.MyClass.main(MyClass.java:110)

我目前的解决方法非常难看,并且可能导致测试时间过长:

package newproject;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;

import org.openqa.selenium.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
//import org.openqa.selenium.chrome.ChromeDriver;

public class MyClass 
  public static void main(String[] args) 
  System.setProperty("webdriver.gecko.driver", "/Users/niunani/Selenium/geckodriver");
  WebDriver driver = new FirefoxDriver();
  driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

  String baseUrl = "https://www.zillow.com/san-diego-ca-92109/";
  String tagName = "";
  String titleText = "";
  String priceText = "";

  //search title
  driver.get(baseUrl);
  WebElement searchTitle = driver.findElement(By.className("search-title"));
  tagName = searchTitle.getTagName();
  System.out.println(tagName);
  titleText = searchTitle.getText();
  System.out.println(titleText);

  //get price button and click
  WebElement priceButton = driver.findElement(By.id("price"));
  priceText = priceButton.getText();
  System.out.println(priceText);
  //priceButton.click();

  Map<String, List<String>> priceTestCases = new HashMap<String, List<String>>();

  List<String> threeHundThouSet = new ArrayList<String>();
  threeHundThouSet.add("400000");
  threeHundThouSet.add("500000");
  threeHundThouSet.add("600000");
  threeHundThouSet.add("700000");
  threeHundThouSet.add("800000");
  threeHundThouSet.add("900000");
  threeHundThouSet.add("1000000");

  List<String> fourHundThouSet = new ArrayList<String>();
  fourHundThouSet.add("500000");
  fourHundThouSet.add("600000");
  fourHundThouSet.add("700000");
  fourHundThouSet.add("800000");
  fourHundThouSet.add("900000");
  fourHundThouSet.add("1000000");

  List<String> fiveHundThouSet = new ArrayList<String>();
  fiveHundThouSet.add("600000");
  fiveHundThouSet.add("700000");
  fiveHundThouSet.add("800000");
  fiveHundThouSet.add("900000");
  fiveHundThouSet.add("1000000");

  priceTestCases.put("300000", threeHundThouSet);
  priceTestCases.put("400000", fourHundThouSet);
  priceTestCases.put("500000", fiveHundThouSet);

  WebElement priceExposedMin = driver.findElement(By.id("price-exposed-min"));
  //priceExposedMin.clear();
  //priceExposedMin.sendKeys("300000");

  WebElement priceExposedMax = driver.findElement(By.id("price-exposed-max"));
  //WebElement priceExposedMax = wait.until(
//        ExpectedConditions.visibilityOfElementLocated(By.id("price-exposed-max")));
  //WebElement priceExposedMax = new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(driver.findElement(By.id("price-exposed-max"))));
  //priceExposedMax.clear();
  //priceExposedMax.sendKeys("500000");

  WebElement priceDoneButton = driver.findElement(By.xpath("/html/body/div[1]/div[6]/div/div[1]/div[1]/div[2]/div[2]/div/div/div/button"));

  priceButton.click();
  for (Map.Entry<String, List<String>> entry : priceTestCases.entrySet()) 
      String key = entry.getKey();
      List<String> values = entry.getValue();
      System.out.println("Key = " + key);
      System.out.println("Values = " + values + "n");
      //priceExposedMin.clear();
      for (int i=0;i<20;i++) 
          priceExposedMin.sendKeys(Keys.BACK_SPACE);
      
      priceExposedMin.sendKeys(key);
      for (String maxPrice : values) 
          System.out.println(maxPrice);
          //priceExposedMax.clear();
          //wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"price-exposed-max\"]"))).clear();
          for (int i=0;i<20;i++) 
              priceExposedMax.sendKeys(Keys.BACK_SPACE);
          
          priceExposedMax.sendKeys(maxPrice);
          priceDoneButton.click();

          //wait for document.readyState
          //new WebDriverWait(driver, 30).until(
            //      webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));

          //Wait for 30 sec until AJAX search load the content
          new WebDriverWait(driver,30).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.className("list-card-price")));
          //new WebDriverWait(driver,30).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("ul > li.closed")));

          int timeToWait = 10; //second
          try 
              for (int i=0; i<timeToWait ; i++) 
                  Thread.sleep(2000);
              
           catch (InterruptedException ie)
          
              Thread.currentThread().interrupt();
          

          Integer countWrong = 0;

          boolean result = false;
          int attempts = 0;
          while (attempts < 2) 
              try 
                  List<WebElement> returnPrices = driver.findElements(By.className("list-card-price"));
                  System.out.println(returnPrices);
                  for (WebElement priceElement : returnPrices) 
                      String priceString = priceElement.getText();
                      priceString = priceString.replace("Est. $", "");
                      priceString = priceString.replace("$", "");
                      priceString = priceString.replace(",", "");
                      Integer price = Integer.parseInt(priceString);
                      if (price > Integer.parseInt(maxPrice)) 
                          countWrong++;
                          System.out.println("Over price : " + Integer.toString(price));
                      
                      System.out.println("This price : " + Integer.toString(price));

                  
                  System.out.println("Incorrect query result: " + Integer.toString(countWrong)) ;
                  priceButton.click();
                  result = true;
                  break;
               catch(StaleElementReferenceException e) 
              
              attempts++;
          

      
  

  //driver.close();
  //System.exit(0);
  

【问题讨论】:

寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及必要的最短代码 重现它在问题本身。没有清晰的问题陈述的问题对其他读者没有用处。请参阅:minimal reproducible example。请注意有关最短代码的部分...您包含的许多代码都不相关。将其缩减为重现问题、编辑您的问题并仅添加该代码所需的内容。 【参考方案1】:

如果你使用reusables编写代码,那么它会更容易理解并且看起来不难看。尝试使用小的reusables,然后结合它们来测试功能

【讨论】:

以上是关于Selenium Web 驱动程序 - 在循环中等待 (Java)的主要内容,如果未能解决你的问题,请参考以下文章

System.Web.Providers 在中等信任下不起作用

如何使用java中的selenium Web驱动程序中的分页搜索表中的元素

什么技术可以在 Web 浏览器中渲染中等规模的 3d 环境 [关闭]

如何在 Java 中执行 Selenium 测试

页面有很多链接,如何用selenium进行自动化测试,验证每个链接的正确性

带有Python的Selenium Webdriver - 无法使用Selenium Web驱动程序在Web应用程序中提供输入(Date)