使用 WebDriver.FindElement() 的 .NET。单击 SelectElement 选项后的文本不会更新“数据”

.NET using WebDriver.FindElement().Text after SelectElement option click doesn't update "data"

提问人:Thomas_Lcp 提问时间:11/11/2023 最后编辑:Thomas_Lcp 更新时间:11/12/2023 访问量:72

问:

在我的网页上,我有一个选择元素,可以在单击后更新页面内容。

我写了一段代码,允许我导航 select 元素的不同选项。 这部分代码运行良好,但是,在这些行之后,当我尝试使用

WebDriver.FindElement().Text(当然使用适当的 XPath)

在允许我导航抛出选项的循环中,数据似乎没有在页面上正确更新。

这是我写的片段:

foreach(IWebElement option in optionList)
             {
                option.Click();

                var productName = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/h1/span"));
                var productPrice = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[3]/div/div/div[1]/div/span[1]/meta"));
                var productDescription = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[2]/div/div[1]/div/div/p[5]"));
                var productReference = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/div/span"));
                var productReferer = driver.FindElement(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/span/a"));

                ProductReference pr = new()
                {
                    DisplayName = productName.Text,
                    Price = productPrice.Text,
                    Description = productDescription.Text,
                    Referer = productReferer.Text,
                    Reference = productReference.Text,
                    AttributName = "Couleurs",
                    AttributValue = option.Text,
                };
                products.Add(pr);

                Console.WriteLine(pr);
            }

如果有办法“刷新”浏览器或其他任何东西,我都不知道。

pr AttributValue 始终是正确的,但例如,引用已经相同,而它应该不同。

感谢您的帮助!

更多信息 :

这是循环之前的代码:

ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.AddArguments("--headless=new");
            chromeOptions.AddExcludedArgument("disable-popup-blocking");
            ChromeDriver driver = new ChromeDriver();

            driver.Navigate().GoToUrl(url);

            IWebElement colorChoiceElmt = driver.FindElement(By.Id("group_4"));

            SelectElement select = new SelectElement(colorChoiceElmt);
            IList<IWebElement> optionList = select.Options;

已经测试过的代码:

-- 拉蒙建议 --

在拉蒙的建议下,我尝试了这个。问题是,在 Selenium 文档上,他们要求我们不要使用 ExpectedConditions(并且使用它会产生错误),所以我遵循了他们的建议并使用 Explicit 等待,如下所示:

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(2));
                wait.Until(d => colorChoiceElmt.Displayed);
                colorChoiceElmt.SendKeys("Displayed");

-- 雅罗斯拉夫建议 --

由于 Selenium 在最新版本中尚不支持 ExpectedConditions,因此我安装了“SeleniumExtras.WaitHelpers”块包到以下代码中才能工作。剧透,结果是一样的。

static void ProcessUrl(string url)
        {
            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.AddArguments("--headless=new");
            chromeOptions.AddExcludedArgument("disable-popup-blocking");
            ChromeDriver driver = new ChromeDriver();

            driver.Navigate().GoToUrl(url);

            WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
            IWebElement colorChoiceElmt = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("group_4")));

            SelectElement select = new SelectElement(colorChoiceElmt);
            IList<IWebElement> optionList = select.Options;
            string currentProductReference = null;

            for (int index = 0; index < optionList.Count; index++)
            {
                if (index > 1)
                {
                    wait.Until(ExpectedConditions.StalenessOf(colorChoiceElmt));
                }

                colorChoiceElmt = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("group_4")));
                select = new SelectElement(colorChoiceElmt);
                optionList = select.Options;
                select.SelectByIndex(index);
                IWebElement product = driver.FindElement(By.CssSelector(".product-info-row"));
                IWebElement productName = product.FindElement(By.CssSelector("[itemprop=name]"));
                IWebElement productPrice = product.FindElement(By.CssSelector(".product-price"));
                IWebElement productDescription = driver.FindElements(By.CssSelector(".product-description p"))[4];
                IWebElement productReference = product.FindElement(By.CssSelector("[itemprop=sku]"));
                currentProductReference = productReference.Text;
                IWebElement productReferer = product.FindElement(By.CssSelector(".product_header_container a"));

                ProductReference pr = new()
                {
                    DisplayName = productName.Text,
                    Price = productPrice.Text,
                    Description = productDescription.Text,
                    Referer = productReferer.Text,
                    Reference = productReference.Text,
                    AttributName = "Couleurs",
                    AttributValue = optionList[index].Text,
                };
                products.Add(pr);

                Console.WriteLine(pr);
            }

            driver.Quit();
        }


C# 硒 web驱动程序 selenium-chromedriver

评论

0赞 Yaroslavm 11/11/2023
没有资源,很难帮助你。请提供最低限度的可重复示例。
0赞 Thomas_Lcp 11/12/2023
现在,您可以看到我之前描述的循环之前的所有代码。希望这能帮助你理解。@Yaroslavm
0赞 Yaroslavm 11/12/2023
我只需要变量,没有它就无法调试代码url
0赞 Thomas_Lcp 11/12/2023
这是@Yaroslavm

答:

-1赞 Ramon 11/11/2023 #1

您面临的问题似乎与单击选择元素中的选项后检索元素的时间有关。WebDriver 可能正在尝试在页面完全更新之前获取元素。

为了解决这个问题,您可以引入一种等待机制,以确保 WebDriver 在尝试检索其值之前等待元素存在且可见。下面是一个使用以下示例:WebDriverWait

foreach (IWebElement option in optionList)
{
    option.Click();

    // Introduce WebDriverWait to wait for the elements to be present
    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));

    var productName = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/h1/span")));
    var productPrice = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[3]/div/div/div[1]/div/span[1]/meta")));
    var productDescription = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[2]/div/div[1]/div/div/p[5]")));
    var productReference = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/div/span")));
    var productReferer = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/main/section/div[2]/div/section/div[2]/div[1]/div[2]/div[1]/span/a")));

    // Rest of your code
}

这样,WebDriver 将等待最多 10 秒(您可以根据需要调整超时)以使元素可见,然后再尝试检索其值。

此外,您可能需要考虑使用更简洁的 XPath 表达式或其他定位器策略来使代码更易于维护。

评论

0赞 Thomas_Lcp 11/11/2023
我尝试了您的代码,但是,正如 Selenium 文档所说,并且因为我使用它的最后一个版本,我应该考虑使用显式等待。我查看了他们提供的代码并尝试了同样的事情,但无法让它工作,因为“OpenQA.Selenium.ElementNotInteractableException:'元素不可交互”我尝试了我的选择“wich is interactable”,但对结果没有任何更改
1赞 DavidW 11/13/2023
我认为这个答案可能是 ChatGPT 未经测试的复制粘贴
1赞 Yaroslavm 11/12/2023 #2

首先 - 不要使用绝对选择器。 尝试使用指向所需元素的唯一且简短的选择器。

然后 - 在 2+ 尝试上选择下拉选项后,您应该等待上一个下拉元素重新呈现(它发生在您的情况下),因此当它发生时 - 显示新的产品卡信息。 然后,您只需重新初始化下拉元素并从下一个循环中获取数据。

我添加了具有描述逻辑的通用代码,您可以对其进行调整并采用您的脚本结构。

等待元素可见度,使用会像这样4.0+WebDriverWait

IWebElement colorChoiceElmt = wait.Until(webDriver =>
        {
            IWebElement target = driver.FindElement(By.Id("group_4"));
            return target.Displayed ? target : null;
        });

等待元素过时,类似于

wait.Until(webDriver =>
                {
                    try
                    {
                        IWebElement target = driver.FindElement(By.CssSelector("[itemprop=image]"));
                        return !target.Displayed
                    }
                    catch (Exception)
                    {
                        return true;
                    }
                });

因此,工作示例是:

using System;
using System.Collections.Generic;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;

namespace TestProject1
{
    [TestFixture]
    public class Tests
    {
        [Test]
        public void Test1()
        { 
            ChromeOptions chromeOptions = new ChromeOptions();
        chromeOptions.AddExcludedArgument("disable-popup-blocking");
        chromeOptions.AddArgument("--headless=new");

        IWebDriver driver = new ChromeDriver(chromeOptions);
        string url = "https://www.wrs.it/fr/bouchon-de-huile-moteur/200579-too02-bouchon-de-remplissage-d-huile-ducabike-ducati-diavel-2011.html";
        driver.Navigate().GoToUrl(url);

        WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
        IWebElement colorChoiceElmt = wait.Until(webDriver =>
        {
            IWebElement target = driver.FindElement(By.Id("group_4"));
            return target.Displayed ? target : null;
        });

        SelectElement select = new SelectElement(colorChoiceElmt);
        IList<IWebElement> optionList = select.Options;

        List<Dictionary<string, string>> products = new List<Dictionary<string, string>>();
        IWebElement product = driver.FindElement(By.CssSelector(".product-info-row"));
        string imageHref = product.FindElement(By.CssSelector("[itemprop=image]")).GetDomProperty("href");
        string referenceText = product.FindElement(By.CssSelector("[itemprop=sku]")).Text;
        for (int index = 0; index < optionList.Count; index++)
        {
            select.SelectByIndex(index);
            wait.Until(webDriver =>
                {
                    try
                    {
                        IWebElement target = product.FindElement(By.CssSelector("[itemprop=image]"));
                        return !target.GetDomProperty("href").Equals(imageHref);
                    }
                    catch (Exception)
                    {
                        return true;
                    }
                });
            wait.Until(webDriver =>
            {
                try
                {
                    IWebElement target = product.FindElement(By.CssSelector("[itemprop=sku]"));
                    return !target.Text.Equals(referenceText);
                }
                catch (Exception)
                {
                    return true;
                }
            });
            imageHref = product.FindElement(By.CssSelector("[itemprop=image]")).GetDomProperty("href");
            product = driver.FindElement(By.CssSelector(".product-info-row"));
            colorChoiceElmt = wait.Until(webDriver =>
            {
                IWebElement target = driver.FindElement(By.Id("group_4"));
                return target.Displayed ? target : null;
            });
            select = new SelectElement(colorChoiceElmt);
            optionList = select.Options;
            
            string productName = product.FindElement(By.CssSelector("[itemprop=name]")).Text;
            string productPrice = product.FindElement(By.CssSelector(".product-price")).Text;
            string productDescription = driver.FindElements(By.CssSelector(".product-description p"))[4].Text;
            referenceText = product.FindElement(By.CssSelector("[itemprop=sku]")).Text;
            string productReferer = product.FindElement(By.CssSelector(".product_header_container a")).Text;

            Dictionary<string, string> pr = new Dictionary<string, string>
            {
                { "DisplayName", productName },
                { "Price", productPrice },
                { "Description", productDescription },
                { "Referer", productReferer },
                { "Reference", referenceText },
                { "AttributName", "Couleurs" },
                { "AttributValue", optionList[index].Text },
            };
            products.Add(pr);
        }

        driver.Quit();
        }
    }
}

评论

0赞 Thomas_Lcp 11/12/2023
查看我对 Ramon 的回答,ExpectedConditions 不适用于我的 Selenium 版本。正如他们网站所描述的那样,他们邀请我们使用 Explicit Wait。你能告诉我你让它工作的硒块包的哪个版本吗?
0赞 Thomas_Lcp 11/12/2023
是因为每次您在选择器中选择另一个选项时 url 都会更改,以至于我们无法让它工作?代码中产品的“引用”是否针对每个选项进行了更改?
0赞 Yaroslavm 11/12/2023
@Thomas_Lcp更新的代码片段到您的 Selenium 版本
1赞 Thomas_Lcp 11/12/2023
感谢您抽出宝贵时间@Yaroslavm。我刚刚删除了与“imageHref”相关的所有代码,因为它会产生一些错误,但如果没有这个,它就像一个魅力!