Selenium爬取YouTube评论偶发element not attached错误求助
问题成因
你遇到的是Selenium中常见的StaleElementReferenceException错误,核心原因如下:
- 代码执行初期就通过
find_elements_by_xpath把所有评论元素一次性存到了l_com列表中,这些元素本质是指向当时页面DOM树节点的引用 - 循环过程中执行了点击回复按钮、
window.history.go(-1)回退页面的操作,会触发页面DOM树重新渲染,甚至整个页面重载 - 回退后当前页面的DOM树已经是全新的,之前存在
l_com里的所有引用都不属于当前DOM,因此访问i.text或者调用元素方法时就会抛出「element is not attached to the page document」错误
解决方案
可以按照以下逻辑修改代码修复问题:
- 不要提前存储评论元素对象,改为先获取所有评论的文本和对应位置索引,只存可序列化的字符串和数字,不存DOM引用
- 处理单条评论完成回退后,先等待页面评论区域渲染完成,再重新获取当前页的评论元素列表,再处理下一条
- 不要用全局索引
n匹配评论和回复按钮,改为从当前评论元素出发查找对应子级的回复按钮,避免索引错位 - 可以增加异常捕获逻辑,遇到过时元素错误时自动重试获取元素
如果社区评论是懒加载的,需要先滚动页面触发所有评论加载完成后再执行预扫描逻辑,避免漏掉后续未加载的评论。
修改后参考代码:
from selenium import webdriver as wbd from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import StaleElementReferenceException attend = wbd.support.ui.WebDriverWait avec = wbd.common.by.By com_commu = {} terme = 'vidéo' délai = 5 # 第一步:预扫描所有评论,记录符合关键词的索引,不存储易失效的DOM元素对象 valid_indexes = [] # 首次获取评论列表 attend(driver, délai).until(EC.presence_of_element_located((avec.XPATH, '//*[@id="content-text"]'))) l_com = driver.find_elements_by_xpath('//*[@id="content-text"]') for idx, com in enumerate(l_com): try: if terme in com.text: valid_indexes.append(idx) else: print(f'Il n\'y a pas le terme "{terme}" dans le post : {com.text}') except StaleElementReferenceException: # 预扫描时如果遇到元素失效,重新获取评论列表后重试 l_com = driver.find_elements_by_xpath('//*[@id="content-text"]') if terme in l_com[idx].text: valid_indexes.append(idx) # 第二步:逐个处理符合要求的评论 for idx in valid_indexes: # 每次处理前重新获取最新的评论和回复按钮列表,避免引用失效 attend(driver, délai).until(EC.presence_of_element_located((avec.XPATH, '//*[@id="content-text"]'))) current_coms = driver.find_elements_by_xpath('//*[@id="content-text"]') reply_btns = driver.find_elements_by_xpath('//*[@id="reply-button-end"]/ytd-button-renderer/a') current_com_text = current_coms[idx].text # 点击对应评论的回复按钮 reply_btns[idx].click() # 等待回复内容加载完成 attend(driver, délai).until(EC.presence_of_element_located((avec.XPATH, '//*[@id="body"]'))) com_commu[current_com_text] = driver.find_elements_by_xpath('//*[@id="body"]') # 回退到评论列表页 driver.execute_script("window.history.go(-1)") # 等待回退后评论列表重新渲染完成 attend(driver, délai).until(EC.presence_of_element_located((avec.XPATH, '//*[@id="content-text"]')))
内容的提问来源于stack exchange,提问作者Tom Kuntz
相关产品推荐
相关产品推荐

