【问题标题】:Iterating through website table (Element is not attached to the page document)遍历网站表格(元素未附加到页面文档)
【发布时间】:2020-08-05 04:18:44
【问题描述】:

我有一个遍历网站表的代码。表格是动态的,项目会在用户滚动时加载到其中。

我有参数:

public class UserTableRow
{
    private readonly IWebElement row;

    public string Username => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l0 r0')]")).Text;
    public string Firstname => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l1 r1')]")).Text;
    public string Lastname => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l2 r2')]")).Text;
    public string Type => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l3 r3')]")).Text;
    public string Crew => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l4 r4')]")).Text;
    public string JobTitle => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l5 r5')]")).Text;
    public string DefaultPrice => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l6 r6')]")).Text;
    public string Future => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l7 r7')]")).Text;
    public string Language => row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l8 r8')]")).Text;

    public override string ToString()
    {
        return "SharePrice: " + Username.ToString() + ": " + Firstname.ToString();
    }

    public UserTableRow(IWebElement row)
    {
        try
        {
            this.row = row;
        }
        catch (Exception)
        {

            throw;
        }
    }
}

这是将数据添加到列表中的方法本身。

    public static IEnumerable<UserTableRow> AddItemsToList(IWebDriver driver)
    {

        IReadOnlyCollection<IWebElement> rows = new List<IWebElement>();

        List<UserTableRow> DataHere = new List<UserTableRow>();

        driver.FindElement(By.XPath("//*[@id=\"disabled_users_show_label\"]")).Click();

        Thread.Sleep(7000);

        driver.FindElement(By.XPath("//*[@id=\"users_table\"]/div[5]/div/div[1]")).Click();

        for (int i = 0; i < 11; i++)
        {
            rows = driver.FindElements(By.CssSelector("#users_table .slick-viewport .slick-row"));

            // Now we will iterate through cells in table and compare to what we already have in the list
            foreach (IWebElement cell in rows)
            {
                rows = driver.FindElements(By.CssSelector("#users_table .slick-viewport .slick-row"));

                // Add data to our object
                DataHere.Add(new UserTableRow(cell));

                //We need to select table first to be able to scroll down. We do it directly here
                Actions actions = new Actions(driver);
                actions.SendKeys(Keys.ArrowDown).Build().Perform();

            }

        }

        List<UserTableRow> noDupes = DataHere.Distinct().ToList();

        return noDupes;
    }

一切正常,但在某些时候(我不知道为什么)它捕捉到一个错误:

OpenQA.Selenium.StaleElementReferenceException: '陈旧元素 参考:元素未附加到页面文档(会话 信息:铬=84.0.4147.105)'

指向row.FindElement(By.XPath(".//div[contains(@class, 'slick-cell l0 r0')]")).Text;

任何想法如何将 try catch 添加到参数以便代码将继续执行直到添加到列表完成?


我打电话的原因

rows = driver.FindElements(By.CssSelector("#users_table .slick-viewport .slick-row"));

在循环内部,我正在尝试更新表值以在向下滚动后进行迭代。这是一个棘手的表,它在滚动上卸载项目并从数据库中加载其他项目。所以我试图模仿用户使用键盘滚动并将表格项捕获到列表。

与航班上的物品清单进行比较是完美的选择。但是我想把所有东西都放到列表中(甚至是重复的),然后再制作其他列表,我将在其中消除重复的内容,例如:

    List<UserTableRow> noDupes = DataHere.Distinct().ToList();

HTML:

<div id="users_table" class="security_slick_container slickgrid_300610 ui-widget" style="overflow: hidden; outline: 0px; position: relative;">
    <div tabindex="0" hidefocus="" style="position:fixed;width:0;height:0;top:0;left:0;outline:0;"></div>
    <div class="slick-header ui-state-default" style="overflow:hidden;position:relative;">
        <div class="slick-header-columns" style="left: -1000px; width: 2132px;" unselectable="on">
            <div class="ui-state-default slick-header-column slick-header-sortable slick-header-column-sorted" id="slickgrid_300610userName" title="" style="width: 94px;"><span class="slick-column-name"><strong>Username:</strong></span><span class="slick-sort-indicator slick-sort-indicator-asc"></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column slick-header-sortable" id="slickgrid_300610firstName" title="" style="width: 89px;"><span class="slick-column-name"><strong>Firstname:</strong></span><span class="slick-sort-indicator"></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column slick-header-sortable" id="slickgrid_300610lastName" title="" style="width: 109px;"><span class="slick-column-name"><strong>Lastname:</strong></span><span class="slick-sort-indicator"></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column slick-header-sortable" id="slickgrid_300610type" title="" style="width: 124px;"><span class="slick-column-name"><strong>Type:</strong></span><span class="slick-sort-indicator"></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column slick-header-sortable" id="slickgrid_300610crew" title="" style="width: 109px;"><span class="slick-column-name"><strong>Crew:</strong></span><span class="slick-sort-indicator"></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column slick-header-sortable" id="slickgrid_300610jobTitle" title="" style="width: 109px;"><span class="slick-column-name"><strong>Job title:</strong></span><span class="slick-sort-indicator"></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column slick-header-sortable" id="slickgrid_300610defaultPriceClass" title="" style="width: 124px;"><span class="slick-column-name"><strong>Defaultprice class:</strong></span><span class="slick-sort-indicator"></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column" id="slickgrid_300610description" title="" style="width: 129px;"><span class="slick-column-name"><strong>Description:</strong></span>
                <div class="slick-resizable-handle"></div>
            </div>
            <div class="ui-state-default slick-header-column" id="slickgrid_300610language" title="" style="width: 39px;"><span class="slick-column-name"><strong>Language:</strong></span>
                <div class="slick-resizable-handle"></div>
            </div>
        </div>
    </div>
    <div class="slick-headerrow ui-state-default" style="overflow: hidden; position: relative; display: none;">
        <div class="slick-headerrow-columns" style="width: 1115px;"></div>
        <div style="display: block; height: 1px; position: absolute; top: 0px; left: 0px; width: 1132px;"></div>
    </div>
    <div class="slick-top-panel-scroller ui-state-default" style="overflow: hidden; position: relative; display: none;">
        <div class="slick-top-panel" style="width:10000px"></div>
    </div>
    <div class="slick-viewport" style="width: 100%; overflow: auto; outline: 0px; position: relative; height: 567px;">
        <div class="grid-canvas" style="height: 16550px; width: 1115px;">
            <div class="ui-widget-content slick-row even" style="top:0px">
                <div class="slick-cell l0 r0">john.smith</div>
                <div class="slick-cell l1 r1">John</div>
                <div class="slick-cell l2 r2">Smith</div>
                <div class="slick-cell l3 r3">Contractor</div>
                <div class="slick-cell l4 r4">Microsoft</div>
                <div class="slick-cell l5 r5">Sales manager</div>
                <div class="slick-cell l6 r6">A</div>
                <div class="slick-cell l7 r7"></div>
                <div class="slick-cell l8 r8">en</div>
            </div>
            <div class="ui-widget-content slick-row odd" style="top:25px">
                <div class="slick-cell l0 r0">robert.geits</div>
                <div class="slick-cell l1 r1">Robert</div>
                <div class="slick-cell l2 r2">Geits</div>
                <div class="slick-cell l3 r3">Staff</div>
                <div class="slick-cell l4 r4">Google</div>
                <div class="slick-cell l5 r5">Project manager</div>
                <div class="slick-cell l6 r6">B</div>
                <div class="slick-cell l7 r7"></div>
                <div class="slick-cell l8 r8">de</div>
            </div>
            <div class="ui-widget-content slick-row even" style="top:50px">
                <div class="slick-cell l0 r0">amir.rooney</div>
                <div class="slick-cell l1 r1">Amir</div>
                <div class="slick-cell l2 r2">Rooney</div>
                <div class="slick-cell l3 r3">Staff</div>
                <div class="slick-cell l4 r4">Microsoft</div>
                <div class="slick-cell l5 r5">Sales manager</div>
                <div class="slick-cell l6 r6">A</div>
                <div class="slick-cell l7 r7"></div>
                <div class="slick-cell l8 r8">en</div>
            </div>
            # ETC # ETC # ETC # ETC # ETC # ETC # ETC # ETC # ETC # ETC 
        </div>
    </div>
    <div tabindex="0" hidefocus="" style="position:fixed;width:0;height:0;top:0;left:0;outline:0;"></div>
</div>

【问题讨论】:

  • 感谢您提供更多信息。我现在明白你为什么想要第二行赋值语句了。但是,是否更改了由 C# 以明确定义的方式处理的 foreach 中流的可迭代对象?我不是 C# 专家。不确定我是否有帮助。

标签: c# selenium selenium-webdriver selenium-chromedriver


【解决方案1】:

您正在刷新 foreach 中的行,但 rows 是 foreach 的可迭代对象。我猜这不是非法的(毕竟,它是编译的),但似乎是在自找麻烦。我的观点是,陈旧的元素引用在某种程度上与在其自己的 foreach 循环中重新分配的行有关。

但是,在您第二次分配行之后,您永远不会在 foreach 中使用它。似乎这是您可以删除的无意声明。毕竟,为什么要在 foreach 中分配行,然后在 foreach 中从不使用它?

如果您因为要与已经处理的内容进行比较而第二次分配行,我会给第二行分配一个不同的变量名称(例如,rows_B)。但正如我所说,我认为这里不会发生这种情况。您只需在 foreach 中分配行,从不使用它。

或者,如果第二行分配的原因是因为在您处理表格时表格正在动态变化?如果是这样,我认为您能做的最好的事情就是抓住错误并尝试从中途发生的任何变化中恢复。我知道这听起来很模糊,但实际上,如果您的输入数据在您尝试处理该输入时发生变化,那么您所希望的就是尽力而为。

例如,您可以创建第二行变量(例如 rows_b)以在 foreach 循环中刷新。然后将 rows_b 与原始行进行比较。如果它们相同 - 太棒了,请继续处理。

如果它们不同,我会记录您已经处理了哪些行,然后跳出循环并重新开始。在 foreach 期间,您将检查之前是否已处理过一行,如果是则跳到下一个迭代。

如果这是您想要做的 - 并且想查看代码示例 - 请告诉我。如果它甚至不是您想要完成的,我不想编写代码;-)

【讨论】:

  • 我已将我的想法添加到原始问题中
猜你喜欢
  • 2020-11-09
  • 2018-04-30
  • 1970-01-01
  • 2018-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
相关资源
最近更新 更多