You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Selenium遍历元素时始终返回首个元素值的问题排查

问题描述

使用C# Selenium抓取工单数据时出现异常:

  1. 导航至工单页面并切换到目标iframe后,成功定位到工单容器//*[@id='task_table']/tbody,并获取到20条工单条目(XPath为//*[contains(@id, 'row_task_')])
  2. 遍历这些条目时,打印元素的Text或innerHTML能确认选中的是对应正确的工单
  3. 但提取子元素(如ID、优先级等)时,所有条目都返回第一个工单的子元素值

附相关代码:

private void grabTicketData()
{
    var docUrl = @"https://it4you.xyz/task_list_do#someParameters";

    ChromeOptions chromeOptions = new ChromeOptions();
    chromeOptions.AddArgument("--headless");

    IWebDriver driver = new ChromeDriver(chromeOptions);
    driver.Navigate().GoToUrl(docUrl);

    driver.Manage().Timeouts().ImplicitWait = new TimeSpan(10000);
    System.Threading.Thread.Sleep(3000);

    driver.SwitchTo().Frame("gsft_main");
    var webAppIframe = driver.FindElement(By.XPath("//*[@id='task_table']/tbody"));
    var elements = webAppIframe.FindElements(By.XPath(@"//*[contains(@id, 'row_task_')]"));

    var newLstTickets = new ObservableCollection<Ticket>();
    
    for (int i = 0; i <= (elements.Count - 1); i++)
    {
        Debug.WriteLine(elements[i].Text);

        var Id = elements[i].FindElement(By.XPath("//td[3]/a")).Text;
        var Prio = elements[i].FindElement(By.XPath("//td[4]")).Text;
        var Status = elements[i].FindElement(By.XPath("//td[5]")).Text;
        var DelegatedTo = elements[i].FindElement(By.XPath("//td[7]")).Text;
        var Subject = elements[i].FindElement(By.XPath("//td[8]")).Text;
        var Type = elements[i].FindElement(By.XPath("//td[9]")).Text;

        Debug.WriteLine("#####ID:" + Id + " ---- Prio:" + Prio + " -- Status:" + Status + " - DelegatedTo:" + DelegatedTo + " - Subject:" + Subject + " - Type:" + Type);

        newLstTickets.Add(new Ticket(Id, Prio, Status, DelegatedTo, Subject, Type));
    }

    driver.Quit();
} 

原因分析与解决方法

核心原因

子元素定位时使用的XPath以//开头,这表示从整个文档的根节点开始搜索匹配元素,而非从当前遍历的elements[i]节点上下文搜索。因此每次调用elements[i].FindElement时,都会返回页面中第一个匹配的<td>元素,也就是第一条工单的对应列。

解决方法

将子元素定位的XPath改为以.//开头,.代表当前节点的上下文,确保从当前工单条目元素内部搜索对应的子节点。

修改后的代码片段

for (int i = 0; i <= (elements.Count - 1); i++)
{
    Debug.WriteLine(elements[i].Text);

    // 所有子元素XPath改为.//开头,基于当前元素上下文搜索
    var Id = elements[i].FindElement(By.XPath(".//td[3]/a")).Text;
    var Prio = elements[i].FindElement(By.XPath(".//td[4]")).Text;
    var Status = elements[i].FindElement(By.XPath(".//td[5]")).Text;
    var DelegatedTo = elements[i].FindElement(By.XPath(".//td[7]")).Text;
    var Subject = elements[i].FindElement(By.XPath(".//td[8]")).Text;
    var Type = elements[i].FindElement(By.XPath(".//td[9]")).Text;

    Debug.WriteLine("#####ID:" + Id + " ---- Prio:" + Prio + " -- Status:" + Status + " - DelegatedTo:" + DelegatedTo + " - Subject:" + Subject + " - Type:" + Type);

    newLstTickets.Add(new Ticket(Id, Prio, Status, DelegatedTo, Subject, Type));
}

额外优化建议

  1. 替换Thread.Sleep为WebDriverWait实现显式等待,提升代码稳定性:
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.SwitchTo().Frame("gsft_main") != null);
wait.Until(d => d.FindElement(By.XPath("//*[@id='task_table']/tbody")) != null);
  1. 工单条目的定位XPath也可改为相对路径:webAppIframe.FindElements(By.XPath(".//*[contains(@id, 'row_task_')]"))

内容的提问来源于stack exchange,提问作者Markus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 04:20:33