滚动Web Telegram时Selenium获取innerText触发StaleElementReferenceException异常
问题成因
- StaleElementReferenceException 本质原因:向上滚动加载新聊天时,Telegram网页会动态更新DOM——旧消息元素可能被移除、重新渲染,或页面结构发生变化。你之前通过
document.querySelectorAll获取的WebElement对象,对应的DOM节点已不存在于当前页面文档中,此时调用get_attribute就会抛出该异常。 - 代码逻辑缺陷:
- 一次性获取所有元素后遍历,但滚动操作导致DOM更新,旧元素引用直接失效。
- 异常捕获仅处理
NoSuchElementException,未覆盖StaleElementReferenceException,导致程序直接崩溃。 - 每次循环都打开文件写入,IO操作频繁且低效。
修复方案
方案1:通过JS脚本直接提取文本(避免持有WebElement)
把元素查询和文本提取逻辑都放在JS脚本中,直接返回文本集合,从根源避免stale引用问题:
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException def find_message_container(driver): unique_texts = set() try: # 用JS一次性获取所有匹配元素的innerText并返回 texts = driver.execute_script(""" const elements = document.querySelectorAll('.message.spoilers-container'); return Array.from(elements).map(el => el.innerText.trim()); """) unique_texts.update(texts) # 统一写入文件,减少IO操作 with open("unique_texts.txt", "w", encoding="utf-8") as file: file.write("\n".join(unique_texts)) except (NoSuchElementException, StaleElementReferenceException) as e: print('处理元素时出错:', e) return unique_texts
方案2:滚动后重新查询元素+异常重试
若需保留WebElement操作,每次滚动后重新查询元素,并在遍历中捕获stale异常:
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By def find_message_container(driver): unique_texts = set() try: # 等待新元素加载完成(滚动后调用时触发) WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CSS_SELECTOR, '.message.spoilers-container')) ) # 每次都重新查询元素,不复用旧引用 elements = driver.find_elements(By.CSS_SELECTOR, '.message.spoilers-container') for element in elements: try: text = element.get_attribute("innerText").trim() if text: unique_texts.add(text) except StaleElementReferenceException: # 遇到失效元素直接跳过 continue with open("unique_texts.txt", "w", encoding="utf-8") as file: file.write("\n".join(unique_texts)) except NoSuchElementException as e: print('未找到目标元素容器:', e) return unique_texts
滚动加载的配合逻辑
调用上述函数时,每次滚动后都重新执行元素查询,不要复用之前的结果:
def scroll_and_load(driver): chat_container = driver.find_element(By.CSS_SELECTOR, '.messages-container') last_scroll_top = chat_container.get_attribute('scrollTop') while True: # 向上滚动聊天区域 driver.execute_script("arguments[0].scrollTop -= 500", chat_container) # 等待新内容加载 WebDriverWait(driver, 5).until( lambda d: d.find_element(By.CSS_SELECTOR, '.messages-container').get_attribute('scrollTop') != last_scroll_top ) last_scroll_top = chat_container.get_attribute('scrollTop') # 重新获取并保存文本 find_message_container(driver) # 滚动到顶部时停止 if last_scroll_top == '0': break
关键注意事项
- 页面更新(如滚动加载)后,永远重新查询元素,不要复用旧WebElement引用。
- 必须捕获
StaleElementReferenceException,动态页面中此类异常属于正常情况。 - 写入文件时统一操作,避免循环内频繁打开关闭文件,提升效率。
内容的提问来源于stack exchange,提问作者francomango
相关产品推荐
相关产品推荐

