如何检查元素是否存在

本文关键字:元素 是否 存在 检查 何检查 | 更新日期: 2023-09-27 18:34:34

在我的使用Firefox Selenium WebDriver的C# Windows Forms应用程序中,我需要检查一个元素是否存在,如果不存在,请单击另一个元素。如果有视频,观看后会变成W_VIEWED

driver.FindElement(By.XPath("//div[@class='video']/a")).Click();
else
{
    driver.FindElement(By.XPath("//div[@class='W_VIEWED']/a")).Click();
}

错误 3 只有赋值、调用、递增、递减、等待和新对象表达式可以用作语句 242

如何检查元素是否存在

您可以使用

以下命令检查元素是否退出

bool isElementDisplayed = driver.findElement(By.xpath("element")).isDisplayed()

请记住,如果findElement找不到元素,则会引发异常,因此您需要正确处理它。

在我的一个应用程序中,我通过检查单独函数中的元素来处理异常:

private bool IsElementPresent(By by)
{
    try
    {
        driver.FindElement(by);
        return true;
    }
    catch (NoSuchElementException)
    {
        return false;
    }
}

调用功能:

if (IsElementPresent(By.Id("element name")))
{
    // Do if exists
}
else
{
    // Do if does not exists
}

您可以使用带有"s"的 FindElements 来确定它是否存在,因为 FindElement 会导致异常。 如果 FindElements 不返回元素,则返回一个空列表。

List<IWebElement> elementList = new List<IWebElement>();
elementList.AddRange(driver.FindElements(By.XPath("//input[@att='something']")));
if(elementList.Count > 0)
{
    //If the count is greater than 0 your element exists.
    elementList[0].Click();
}

所以我最近想出了另一种方法,它要快得多。如果您的元素具有唯一 ID 或页面上其他任何地方都不存在的某些属性,则可以检查页面源代码。

driver.PageSource.Contains("UniqueID");

它会检查页面以查看 ID 或其他唯一文本是否存在。 这几乎是瞬间发生的,而不是使用 Try/Catch 语句,这需要 ~20 秒。 FindElements也需要很长时间才能运行。

我使用接受答案的解决方案有一段时间了,但我需要一种更快的方法来检查,而不是每次检查失败时都等待超时期限。因此,我制作了一些适用于 IWebElement 和 IWebDriver 的扩展函数,用于检查标记或类是否存在。

public static class ExtensionMethods {
    public static bool ContainsTag(this IWebElement element, string tagName)
    {
        string elementText = element.GetAttribute("innerHTML");
        return CheckStringForTag(elementText, tagName);
    }
    public static bool ContainsClass(this IWebElement element, string className)
    {
        string elementText = element.GetAttribute("innerHTML");
        return CheckStringForClass(elementText, className);
    }
    public static bool ContainsTag(this IWebDriver driver, string tagName)
    {
        return CheckStringForTag(driver.PageSource, tagName);
    }
    public static bool ContainsClass(this IWebDriver driver, string className)
    {
        return CheckStringForClass(driver.PageSource, className);
    }
    private static bool CheckStringForTag(string text, string tagName)
    {
        if (!string.IsNullOrWhiteSpace(text))
        {
            return text.Contains("<" + tagName + ">") || text.Contains("</" + tagName + ">") || text.Contains("<" + tagName + " ");
        }
        return false;
    }
    private static bool CheckStringForClass(string text, string className)
    {
        if (!string.IsNullOrWhiteSpace(text))
        {
            string pattern = string.Format(".*class[''s]?=[''s]?.*[''s''"]{0}[''s''"].*.*", className);
            Match m = Regex.Match(text, className, RegexOptions.IgnoreCase);
            return m.Success;
        }
        return false;
    }
    public static string InnerHTML(this IWebElement element)
    {
        return element.GetAttribute("innerHTML");
    }
}

注意:这与Dominic Giallombardo的答案类似,但扩展了。

此方法将允许您等待元素存在。这在有条件地创建元素的前端 SPA 框架中尤其重要,例如 Vue.js。您可以根据应用程序的性能调整重试计数。无论如何,它将等待您的ELEMENT_FIND_WAIT_TIME * ELEMENT_FIND_WAIT_RETRY_COUNT毫秒,然后完全失败。这解决了我们遇到的问题。

protected Func<IWebElement> GetLazyElement(By by, int retryCount=0)
{
    if (retryCount >= ELEMENT_FIND_WAIT_RETRY_COUNT)
    {
        throw new Exception("Wait timeout for element to show up" + by.ToString());
    }
    return new Func<IWebElement>(() => {
        try
        {
            Debug.WriteLine("Finding element " + by.ToString());
            var element = _webDriver.FindElement(by);
            return element;
        }
        catch (Exception)
        {
            Debug.WriteLine($"Failed to find element: {by} (Waiting {ELEMENT_FIND_WAIT_TIME}ms)");
            Thread.Sleep(ELEMENT_FIND_WAIT_TIME);
            var lazyFunc = GetLazyElement(by, retryCount++);
            return lazyFunc();
        }
    });
}

Dominic Giallombardo的回答对我有用。在后台加载的基于 Ajax 的信息上,需要等待元素出现。

因此,如果您想等待并在元素出现时执行操作,可以使用标签和转到标签 + else 条件。以下是修改后的代码,它将等待元素通过循环出现:

ChecksomeElement

List<IWebElement> elementList = new List<IWebElement>();
elementList.AddRange(driver.FindElements(By.XPath("//div[@class='video']/a")));
if (elementList.Count > 0)
{
     elementList[0].Click();
}
else
{
     System.Threading.Thread.Sleep(2000);
     goto checksomeelement;
}
这是我

使用的。"verify"方法将根据元素是否存在返回 true 或 false。名为"testfunc"的方法是您输入元素名称的位置。在此示例中,我正在寻找页面上是否显示"英语"。

此外,我在之前帖子的评论中注意到,人们说他们必须等待 10 秒或更长时间才能捕获才能工作。尝试删除代码中的显式等待,以便 catch 立即工作。

static public bool verify(string elementName)
{
    try
    {
        bool isElementDisplayed = driver.FindElement(By.XPath(elementName)).Displayed;
        return true;
    }
    catch
    {
        return false;
    }
    return false;
}
static void testfunc()
{
    bool test = verify("//option[contains(.,'English')]");
    Console.WriteLine(test);
}

如果您正在使用ImplicitWait并且想要通过使用FindElement来查看元素是否存在而无需等待,请尝试以下代码:

ElementExists(By.Id(id));
static public bool ElementExists(By method)
{
    var oldTime = _driver.Manage().Timeouts().ImplicitWait;
    _driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(1);
    try
    {
        bool isElementDisplayed = _driver.FindElement(method).Displayed;
        _driver.Manage().Timeouts().ImplicitWait = oldTime;
        return true;
    }
    catch
    {
        _driver.Manage().Timeouts().ImplicitWait = oldTime;
        return false;
    }
}