【问题标题】:Why do I get StaleElementReferenceException when I "read" the text contents of a column?当我“读取”列的文本内容时,为什么会出现 StaleElementReferenceException?
【发布时间】:2019-05-19 09:14:49
【问题描述】:

仅当我尝试两次收集(“抓取”)表的内容时才会出现此问题。我第一次读取表格内容是成功的,但第二次总是失败。

这仅在 Chrome 浏览器(版本 74 和相应的 chromedriver)中发生。我对 FireFox 进行了同样的尝试,但它从未发生过。我在 Chrome 中找到了某种解决方法,它没有任何意义,但它确实有效。

当我“转到”包含表格的屏幕之外的其他屏幕然后返回时,表格抓取成功。

以下是我用来收集表格的函数:

def Get_Faults_List(Port_Number=None, PSU=None, Retries=5):
    for attempt in range(Retries):
        try:
            if Port_Number:
                # Show the Faults view in the context of "Port_Number"
                Device_Panel_Frame.Click_Port(self, Port_Number)
            elif PSU:
                if not Device_Panel_Frame.Click_PSU(self, PSU):
                    return None
            Left_Panel_Frame.Click_Fault(self)

            self.driver.switch_to_default_content()
            Main_Body = self.driver.find_element_by_name('main_page')
            self.driver.switch_to.frame(Main_Body)
            alarms_tab = self.driver.find_element_by_id('tab_alarms')
            alarms_tab.click()
            Fault_Screen = self.driver.find_element_by_name('faults')
            self.driver.switch_to.frame(Fault_Screen)
            # the rows that the following variable collect are automatically
            # the relevant fault lines. The XPATH that was used omits the two
            # irrelevant lines
            faultTable_rows = WebDriverWait(self.driver, timeout=3, poll_frequency=0.5).until(
                EC.presence_of_all_elements_located((By.XPATH, "//table[@id='faultTab']//tr[not(@id or @style)]")))

            current_faults = []
            row_index = 0
            for row in faultTable_rows:  # Go through each of the rows
                current_faults.append([])
                # Collect all the column elements of a certain row into a list
                faultTable_row_cols = row.find_elements_by_tag_name("td")
                for col in faultTable_row_cols:
                    # Each row of the Faults table is separated into 5 columns each column holds a string
                    current_faults[row_index].append(col.text)
                row_index += 1

            break
        except:
            print(attempt + 1, 'attempt failed', Retries - (attempt + 1), 'to go')
            self.Refresh_Screen()
            sleep(5)
            continue

如果我打开一个新的浏览器,我也会成功收集表格的内容。顺便说一句,失败总是发生在下表的第一行(标题之后)。这条线是current_faults[row_index].append(col.text),我不明白为什么。这个例外没有任何意义。

还有其他方法可以有效地抓取表格的内容吗?

表:

【问题讨论】:

  • 我仍在寻找一种能够成功爬取此类表的算法,顺便说一句,我发现以下行代码' current_faults[row_index].append(col.text ) ' 是有时会得到 StaleElementReferenceException 的那个。似乎收集“单元格”文本有时会失败。但是,当它失败时,即使我刷新屏幕也无济于事

标签: python python-3.x selenium google-chrome selenium-chromedriver


【解决方案1】:

请参阅this answer,了解获得Stale Element Reference Exception 的原因。

Stale Element Reference Exception 在元素出现时出现:

  1. 已删除
  2. 不再附加到 DOM(如您的情况)
  3. 已更改

来自文档:

你应该丢弃你持有的当前引用并替换它,可能通过在元素附加到 DOM 后再次定位元素。

即:再次“查找”元素。

我的建议是捕获 HTML 并循环遍历它:

您可以使用driver.page_source,然后使用BeautifulSoup

html = driver.page_source
soup = BeautifulSoup(html, "lxml")

这应该在你切换帧之后实现。

希望对您有所帮助!

【讨论】:

  • 感谢您的帮助。每次我调用函数“Get_Faults _List()”时,我都会丢弃上次调用此函数时对表的引用。如果我理解正确的话,在层次结构中查找表涉及到新的引用,并且每次调用函数时都会这样做。
  • 顺便说一下,关于你的建议。通过这样做,我实际上只会从设备读取整个页面一次。比,所有的解析都可以“离线”完成
  • 关于我的建议...您可以“离线”进行,但如果它是动态的,事情可能会改变...考虑到这一点...
  • 我在工作,所以我帮不上什么忙……但是在将驱动程序切换到 iframe 后尝试打印 DOM,看看它是否在那里。你可能想在你正在抓取的桌子上使用get_text()crummy.com/software/BeautifulSoup/bs4/doc/#get-text
  • 非常感谢。通过获取某个 iframe 的“ page_source ”(在切换帧之后),我设法解析了我感兴趣的表的内容
猜你喜欢
  • 1970-01-01
  • 2022-10-06
  • 1970-01-01
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
  • 1970-01-01
相关资源
最近更新 更多