无法在flexbox下找到的元素执行任何操作

8

Selenium能够查找位于flex盒子中的元素,但不能对这些元素执行任何操作。以下提供了几个示例网站以便更详细地了解:


示例#1:

网站:https://condos.ca/

HTML片段

<div class="styles___SearchField-sc-ntshwn-1 azZjo">
   <div class="styles___SiteSearch-sc-ntshwn-3 bvlPAF">
  <div class="styles___InputIcon-sc-ntshwn-4 eAuylQ">
     <svg viewBox="0 0 59.93 60" class="styles___Svg-sc-14upfal-0 frvNPk svg-icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="width: 20px; height: 20px;">
        <path d="M59.23,55.73L44.33,40.81a25,25,0,1,0-3.53,3.54L55.7,59.27A2.5,2.5,0,1,0,59.23,55.73ZM5,25A20,20,0,1,1,25,45,20,20,0,0,1,5,25Z" transform="translate(-0.03)"></path>
     </svg>
  </div>
  <input aria-label="Search by address, Neighbourhood, MLS #" placeholder="Search by address, Neighbourhood, MLS #" id="search-input">
   </div>
   <div class="styles___GetLocationContainer-sc-ntshwn-5 cCBUUE">
  <button target="_blank" name="search nearby button" class="styles___AppButton-sc-5pk18n-0 jXQNUT styles___SearchNearby-sc-ntshwn-6 dYpkAS" id="">
     <svg viewBox="0 0 20 20" class="styles___Svg-sc-14upfal-0 frvNPk svg-icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="width: 22px; height: 22px;">
        <path d="M10,17.49c-4.19-0.02-7.57-3.39-7.55-7.53c0.02-4.14,3.42-7.48,7.61-7.47c4.18,0.02,7.56,3.37,7.55,7.51C17.6,14.15,14.19,17.5,10,17.49C10,17.49,10,17.49,10,17.49z M10,3.48C6.37,3.5,3.43,6.43,3.45,10.02c0.02,3.59,2.98,6.5,6.61,6.48c3.62-0.02,6.54-2.92,6.55-6.5c0-3.6-2.95-6.52-6.59-6.52C10.01,3.48,10.01,3.48,10,3.48z"></path>
        <path d="M10,3.48c-0.28,0-0.5-0.22-0.5-0.49V0.49C9.5,0.22,9.72,0,10,0s0.5,0.22,0.5,0.49v2.49C10.5,3.26,10.28,3.48,10,3.48z"></path>
        <path d="M10,20c-0.28,0-0.5-0.22-0.5-0.49v-2.51c0-0.27,0.22-0.49,0.5-0.49s0.5,0.22,0.5,0.49v2.51C10.5,19.78,10.28,20,10,20z"></path>
        <path d="M19.54,10.48h-2.43c-0.28,0-0.5-0.22-0.5-0.49c0-0.27,0.22-0.49,0.5-0.49h2.43c0.28,0,0.5,0.22,0.5,0.49C20.04,10.26,19.82,10.48,19.54,10.48z"></path>
        <path d="M3,10.49H0.46c-0.28,0-0.5-0.22-0.5-0.49c0-0.27,0.22-0.49,0.5-0.49H3c0.28,0,0.5,0.22,0.5,0.49C3.5,10.27,3.28,10.49,3,10.49z"></path>
        <path d="M10,13.49c-1.95-0.02-3.52-1.61-3.5-3.54c0.02-1.93,1.62-3.48,3.58-3.46c1.94,0.02,3.51,1.59,3.5,3.51c-0.01,1.94-1.61,3.5-3.57,3.49C10.01,13.49,10,13.49,10,13.49z M10,7.48C8.6,7.5,7.48,8.64,7.5,10.03c0.02,1.39,1.18,2.49,2.58,2.47c1.38-0.02,2.49-1.13,2.5-2.5c0-1.39-1.14-2.52-2.55-2.52C10.02,7.48,10.01,7.48,10,7.48z"></path>
     </svg>
  </button>
   </div>
</div>

代码:

driver.get("https://condos.ca");
driver.findElement(By.xpath("//input[@id='search-input']")).sendKeys("test");

结果:该步骤执行时没有抛出任何错误,但未输入文本。


示例#2:

网站: https://demoqa.com/slider

HTML 片段

<div id="sliderContainer" class="form-group row">
   <div class="col-9">
  <span class="range-slider__wrap">
     <input type="range" class="range-slider range-slider--primary" min="0" max="100" value="25" style="--value:25;">
     <div class="range-slider__tooltip range-slider__tooltip--auto range-slider__tooltip--bottom" style="left: calc(25% + 5px);">
        <div class="range-slider__tooltip__label">25</div>
        <div class="range-slider__tooltip__arrow"></div>
     </div>
  </span>
   </div>
   <div class="col-3"><input id="sliderValue" class="form-control" value="25"></div>
</div>

代码:

driver.get("https://demoqa.com/slider");
JavascriptExecutor executor = (JavascriptExecutor) driver;
WebElement slider = driver.findElement(By.xpath("//input[@type='range']"));
System.out.println("Cuurent value: " + slider.getAttribute("value"));
executor.executeScript("arguments[0].setAttribute('value', ' 30 ')", slider);

结果: 打印属性值但未设置新值。


有些SO问题和博客建议使用Selenium flex api来自动化这些类型的应用程序,但我发现需要在eclipse上安装flex插件,而我找不到那个插件。此外,这些帖子有点旧(5年前)。

  • 如何处理这些元素?
  • 是否有新的方法来操作它们?

参考资料:


你尝试过在执行这些动作之前添加一些等待/延迟吗?不是隐式等待,而是显式等待元素可见或者只是一个虚拟的暂停来确保页面已经完全加载了100%? - Prophet
是的。我尝试了,但没有在问题中添加。 - Nandan A
这样做完全没有解决问题吗? - Prophet
1
好的,我明白了,只是想要完全确定。那是一个有趣的问题! - Prophet
1
如果您希望将问题的范围缩小到特定用例而不是两个用例,我很乐意尝试回答 :) (目前没有Java的IDE,所以答案将基于Python) - undetected Selenium
显示剩余4条评论
1个回答

2

例子1的解决方案

如果您加载该网站,您会发现搜索编辑框上方的文本最初如下:

enter image description here

一段时间后,相同元素的文本更改为: enter image description here

只有在此发生后,才尝试执行sendkeys操作。请注意,您不必对id ='search-input'的元素执行sendkeys操作。您首先需要单击该元素,然后另一个元素(cssSelector -> div[role='combobox'] [placeholder='Search by address, Neighbourhood, MLS #'])变得可见,您需要对其执行sendkeys操作。

请参考下面的代码(在chrome、edge和firefox上测试过)。

package usecase;

import java.time.Duration;
import java.util.regex.Pattern;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import io.github.bonigarcia.wdm.WebDriverManager;

public class Flexcase {
    public static WebDriver driver;
    private static final int maxtime = 20;

    /**
     * Creating a custom findElement method that uses Explicit wait and waits for an
     * element to be clickable
     */
    public static WebElement findElement(By by) {
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(maxtime));
        return wait.until(ExpectedConditions.elementToBeClickable(by));
    }

    /**
     * Waits for an element to contain a text matched by the given pattern(regex)
     */
    public static Boolean doesElementContainTextPattern(By by, String pattern) {
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(maxtime));
        return wait.until(ExpectedConditions.textMatches(by, Pattern.compile(pattern)));
    }

    public static void main(String[] args) throws InterruptedException {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("https://condos.ca/");
        // Waiting for the text to achieve a specific pattern - Search followed by 1+
        // occurrences of either digits or commas followed by 0+ occurrences of any
        // character that is not a newline character followed by the word Listings
        if (doesElementContainTextPattern(By.className("dPFjpJ"), "Search [\\d,]+.*Listings")) {
            findElement(By.id("search-input")).click();
            findElement(By.cssSelector("div[role='combobox'] [placeholder='Search by address, Neighbourhood, MLS #']"))
                    .sendKeys("Test");
        }

        Thread.sleep(10000); // Pls let me see what's happening on the screen
        driver.quit();
    }
}

演示: enter image description here

解决方案2:

不使用javascriptexecutor,而是使用Actions类来构建一个由以下操作组成的复合操作:

  • 通过查找滑块宽度(以像素为单位),将鼠标移动到滑块的最左边
  • 将鼠标移到相对于传递的百分比值的所需位置上的滑块上

代码:(可以提高滑动精度)

package usecase;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;

import io.github.bonigarcia.wdm.WebDriverManager;

public class Slider {

    public static WebDriver driver;

    public static void moveSliderToPosition(By by, int percentage) throws InterruptedException {
        WebElement slider = driver.findElement(by);
        Actions builder = new Actions(driver);
        builder.moveToElement(slider, (int) (-slider.getRect().width / 2), 0) // move to the leftmost position of the
                                                                                // element
                .moveByOffset((int) (percentage * slider.getRect().width / 100), 0) // move the cursor by an offset
                                                                                    // proportionate to the value passed
                .click().build().perform();
        Thread.sleep(3000); // let me see what has happened on the screen
    }

    public static void main(String[] args) throws InterruptedException {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("https://demoqa.com/slider");
        By slider = By.cssSelector("input.range-slider");
        moveSliderToPosition(slider, 47);
        moveSliderToPosition(slider, 83);
        moveSliderToPosition(slider, 35);
        driver.quit();
    }
}

演示: 在此输入图片描述

(注:该内容为一个演示图片,无法进行翻译。)

1
谢谢你详细的回答。我一定会尝试,但我有一个问题。在示例#1中,为什么元素(input标记)在点击后可见?如果不可见,它应该抛出异常。你对示例#2的回答太棒了。 - Nandan A
1
好的,这就是应用程序的制作方式;)。如果您重新加载网站并按CTRL + SHIFT + I,然后在控制台选项卡中尝试查找元素'div[role ='combobox'] [placeholder ='Search by address,Neighbourhood,MLS#']',您将无法找到它。但是,当您单击搜索框并再次尝试在控制台中搜索相同的元素时,您将能够定位它。 - Gurmanjot Singh
同意。然后它应该抛出异常,但事实并非如此。 - Nandan A
示例2的结果符合预期,但示例1仍然失败。我尝试了在selenium 3和4版本中运行示例1,但不确定为什么会失败。 - Nandan A
嗯...代码在我的机器上仍然能够工作...我也在使用Selenium 4...当你说它无法工作时,究竟发生了什么?它根本没有输入任何文本吗?还是输入的内容很快就消失了?你可以尝试在调试模式下运行吗?或者添加日志语句或添加硬编码等待,以便查看代码在哪个点未能按预期执行...然后我们再继续解决问题。 - Gurmanjot Singh
我尝试了你提到的所有方法。代码执行时没有抛出任何错误,所以我在想可能是什么原因。 - Nandan A

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接