Python Selenium触发ElementClickInterceptedException异常如何解决
问题描述
我一直尝试修复ElementClickInterceptedException异常但所用方法均无效,目标页面链接为英超赛事页。点击开赛前页面左侧栏位,会在当前窗口唤起类弹窗组件,效果如下图所示:
我可以正常提取弹窗内的所需信息,问题是点击x关闭弹窗后,程序无法进入下一轮循环,会抛出ElementClickInterceptedException: Message: Element is not clickable at point because another element obscures it异常。该异常大多出现在第二轮循环,偶尔能通过第二轮进入第三轮,但从未完成三轮以上循环。我尝试使用wait+until的显式等待方案但没有效果,只会触发Timeout超时。我使用的代码如下:
# 获取所有需要爬取的比赛对应的selenium元素列表 v1 = _.find_elements_by_class_name('trOddsSection') driver.implicitly_wait(10) for __ in v1: driver.implicitly_wait(10) #__.find_element_by_class_name("col-0").click() wait.until(EC.element_to_be_clickable((By.XPATH, ".//td[@class='col-0']"))) yyy = __.find_element_by_xpath(".//td[@class='col-0']") # 点击唤起弹窗 yyy.click() v3 = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "divStatisticsWidget"))) sleep(3) try: driver.implicitly_wait(10) # 提取弹窗内所需数据 a = v3.find_element_by_xpath(".//div[@id='right-container']/div[@id='content_headToHead']/div[@class='sectionFound']/div[@class='teamWinsDraws']") hm = a.find_element_by_xpath(".//div[@class='teamHomeWins']/span[@class='teamName']/span[@class='resultsPerc']").text dr = a.find_element_by_xpath(".//div[@class='teamDraws']/span[@class='teamName']/span[@class='resultsPerc']").text aw = a.find_element_by_xpath(".//div[@class='teamAwayWins']/span[@class='teamName']/span[@class='resultsPerc']").text print("Here:\t\t{}\t{}\t{}".format(hm, dr, aw)) driver.implicitly_wait(10) a_ = v3.find_element_by_xpath(".//div[@id='right-container']/div[@id='content_headToHead']/div[@class='sectionFound']/div[@class='headToHeadHistory']") a__ = a_.find_elements_by_xpath(".//table/tbody/tr/td[@class='score']") print("H2H {}".format(a__[0].text)) except(NoSuchElementException): print("teamWinDraws class not found") # 关闭弹窗进入下一轮 try: driver.implicitly_wait(10) sleep(4) wait.until(EC.element_to_be_clickable((By.XPATH, ".//*[@class='close-icon']"))) g_g = driver.find_element_by_xpath(".//*[@class = 'close-icon']") driver.execute_script("arguments[0].click();", g_g) except(NoSuchElementException): print('close-icon not found') except(TimeoutException): print('Timed out')
请问代码存在什么问题,有什么可行方案可以绕过该异常?
根因分析
- 预获取的元素失效:你在循环外提前获取了所有
trOddsSection元素存入列表,弹窗打开和关闭会触发页面DOM重绘,之前预存的元素会变成过期的stale元素,第二轮循环调用时元素已经失效,自然无法触发点击。 - 等待逻辑冲突:代码中同时混用隐式等待和显式等待,两种等待逻辑叠加会导致等待时长计算不可预期,直接引发超时或者元素状态判断错误。
- 遮罩层未消失:关闭弹窗后没有等待弹窗相关的遮罩层完全从DOM中移除,就直接执行下一轮点击,未消失的半透明遮罩层会遮挡目标元素,触发点击被拦截的异常。
- 关闭按钮定位错误:查找关闭按钮使用了相对路径
".//*[@class='close-icon']",如果当前上下文不对会导致找不到关闭按钮,弹窗未正常关闭也会遮挡后续操作。
解决方案
- 移除所有隐式等待配置,统一使用显式等待做元素状态判断。
- 不要预获取比赛列表,改为每轮循环重新获取当前DOM中的
trOddsSection元素,通过索引定位当前要处理的比赛,避免stale元素问题。 - 关闭弹窗后增加显式等待,校验弹窗容器和遮罩层已经完全不可见且从DOM中移除,再进入下一轮循环。
- 优先使用JS执行点击操作,从底层绕过元素遮挡的拦截判断。
修改后的核心代码示例:
# 先获取总比赛数量,确定循环次数 game_count = len(driver.find_elements_by_class_name('trOddsSection')) for i in range(game_count): # 每轮循环重新获取当前有效比赛元素 current_game = driver.find_elements_by_class_name('trOddsSection')[i] # 等待当前比赛的点击区域可点击 yyy = wait.until(EC.element_to_be_clickable(current_game.find_element(By.XPATH, ".//td[@class='col-0']"))) # 直接用js点击避免被遮挡拦截 driver.execute_script("arguments[0].click();", yyy) # 等待弹窗加载完成 v3 = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "divStatisticsWidget"))) # 原有数据提取逻辑不变,此处省略 # 关闭弹窗逻辑 close_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@class='close-icon']"))) driver.execute_script("arguments[0].click();", close_btn) # 等待弹窗完全消失 wait.until(EC.invisibility_of_element_located((By.CLASS_NAME, "divStatisticsWidget"))) # 额外等待遮罩层消失(可根据页面实际遮罩层的class调整定位规则) wait.until(EC.invisibility_of_element_located((By.CLASS_NAME, "modal-backdrop")))
内容的提问来源于stack exchange,提问作者Samson Bitrus
相关产品推荐
相关产品推荐

