selenium点击(click)页面元素没有反应(报element not interactable)的一个案例

本文记录了解决使用Selenium在宁萌云网站上点击【密码登录】按钮的问题过程,通过两次点击不同XPath表达式的元素,成功切换到账号密码登录界面。

今天在QQ群上发现一哥们提了个问题,说是有个页面的按钮一直没法点击,用了js也没效果。
还好网站不是他们内网系统,好奇心的驱使下,点进去研究了下。
网址如下:https://www.ningmengyun.com/
需求:
打开网页后,点击登录按钮,弹出登录窗口,点击【密码登录】按钮,切换到账号密码登录界面
在这里插入图片描述
切换后:
在这里插入图片描述
看起来是不是很简单,于是我直接按F12,看下是不是有iframe之类的,结果并没有,而是很容易就写出了xpath:
//div[@class=“modal-bottom”]/a[text()=‘密码登录’]
在这里插入图片描述
直接上代码:

from time import sleep
from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://www.ningmengyun.com/')
sleep(2)
driver.find_element_by_id('regionNav').click()
sleep(2)
driver.find_element_by_xpath("//div[@class='modal-bottom']//a[text()='密码登录']").click()

运行后发现登录窗口没有任何反应,而且运行报错了……
在这里插入图片描述
难道是xpath不对?
我在代码打开的窗口里再次用F12定位下,发现class居然变了……
在这里插入图片描述
好吧,那我再改下xpath好了:

from time import sleep
from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://www.ningmengyun.com/')
sleep(2)
driver.find_element_by_id('regionNav').click()
sleep(2)
driver.find_element_by_xpath('//a[@class="go-login" and text()="密码登录"]').click()

结果这次是没报错了,但是窗口还是没切换啊?
不会是xpath还能变第二次吧?
按F12一看,好家伙,class又变回去了……
在这里插入图片描述
然后花了一个多小时就发现每次定位都是这2个xpath之间变来变去,就是用js也是不行。
最后发现,要执行2次click(),而且这两次click()的元素xpath就是上面的两个,才能正常切换。代码如下:

from time import sleep
from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window()
driver.get('https://www.ningmengyun.com/')
sleep(2)
driver.find_element_by_id('regionNav').click()
sleep(2)
driver.find_element_by_xpath('//a[@class="go-login" and text()="密码登录"]').click()
sleep(2)
driver.find_element_by_xpath("//div[@class='modal-bottom']//a[text()='密码登录']").click()
# 如果用js的话,也需要2次js
# driver.execute_script("document.getElementsByClassName('go-login')[2].click()")
# driver.execute_script("document.getElementsByClassName('modal-bottom')[0].children[0].click()")

最后虽然问题解决了,但是还是不大明白其中有啥问题。
自己打开网址操作,弹出的【密码登录】按钮的xpath和用selenium打开的页面按钮的xpath居然不一样,要先click()一次之后才会一样……难道是和onclick属性有关?
总之先把解决的办法记录下来,下次遇到类似的问题参考下了。

<think>我们参考了提供的引用资料,特别是引用[1]到[5],其中详细描述了ElementNotInteractableException错误的常见原因和解决方案。根据这些引用,我们可以总结出以下主要原因及对应的解决方法: 1. **元素未完全加载/渲染**:页面元素尚未加载完成或未渲染出来,导致无法交互。 - 解决方案:使用显式等待(Explicit Wait)或增加延时(如`time.sleep()`)确保元素可交互。 2. **元素被隐藏或覆盖**:目标元素可能被其他元素(如遮罩层、广告、其他DOM元素)覆盖,或者元素本身不可见(例如CSS属性为`display: none`或`visibility: hidden`)。 - 解决方案: - 检查元素是否可见,并确保它没有被其他元素覆盖。 - 如果被覆盖,可以尝试先点击覆盖元素(如关闭按钮)或空白处使目标元素可交互(如引用[3]中提到的先点击空白处)。 - 对于隐藏元素,可以考虑使用JavaScript直接操作元素(如引用[4]和[5]中提到的使用`execute_script`方法)。 3. **分辨率问题**:在无头模式下,前端和后台的最大化分辨率不一致,导致元素位置偏移或不可见。 - 解决方案:指定窗口大小,确保与有头模式一致(如引用[3]中提到的`--window-size=1960,1080`)。 4. **元素在iframe/frame内**:目标元素位于iframe中,需要先切换到对应的iframe才能操作。 - 解决方案:使用`driver.switch_to.frame()`切换到目标iframe后再操作元素。 5. **元素不可交互的状态**:元素虽然可见,但可能处于不可交互的状态(例如被禁用`disabled`属性)。 - 解决方案:检查元素属性,等待直到元素变为可交互状态。 6. **使用JavaScript绕过交互限制**:当常规方法无法操作元素时,可以使用JavaScript直接操作DOM元素(如引用[4]和[5]中提到的做法)。 - 解决方案:使用`driver.execute_script()`方法执行JavaScript代码来操作元素。 下面我们将详细说明这些解决方案的步骤,并提供代码示例。 ### 1. 等待元素可交互 使用显式等待(WebDriverWait)等待元素满足可交互条件(例如可见、可点击)。 ```python from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待元素可见并可点击 element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "element_id")) ) element.click() # 或者发送文本等操作 ``` ### 2. 检查元素是否被覆盖或隐藏 如果元素被其他元素覆盖,可以尝试先操作覆盖元素(例如关闭弹窗)或者点击页面空白处(引用[3]中的方法): ```python # 点击页面空白处(通常是body元素)以解除覆盖 driver.find_element(By.TAG_NAME, 'body').click() # 然后再尝试操作目标元素 target_element = driver.find_element(By.ID, 'target_id') target_element.click() ``` ### 3. 指定窗口大小解决分辨率问题 在无头模式下,指定窗口大小以确保元素可见: ```python from selenium import webdriver options = webdriver.ChromeOptions() options.add_argument('--headless') # 无头模式 options.add_argument('--window-size=1960,1080') # 指定分辨率 driver = webdriver.Chrome(options=options) ``` ### 4. 处理iframe中的元素 如果元素在iframe内,需要先切换到该iframe: ```python # 切换到iframe iframe = driver.find_element(By.ID, "iframe_id") driver.switch_to.frame(iframe) # 操作iframe内的元素 element_in_iframe = driver.find_element(By.ID, "element_id") element_in_iframe.send_keys("text") # 操作完成后切换回主文档 driver.switch_to.default_content() ``` ### 5. 使用JavaScript直接操作 当元素被隐藏或常规方法无法操作时,使用JavaScript: ```python element = driver.find_element(By.ID, "element_id") # 设置输入框的值 driver.execute_script("arguments[0].value = arguments[1];", element, "text") # 或者点击元素 driver.execute_script("arguments[0].click();", element) ``` ### 6. 检查元素状态 确保元素没有被禁用(`disabled`属性不存在或为`false`): ```python element = driver.find_element(By.ID, "element_id") if element.get_attribute("disabled") is None: # 元素没有被禁用,可以操作 element.click() else: # 元素被禁用,需要等待直到可用状态 WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "element_id")) ) element.click() ``` ### 总结步骤 当遇到`ElementNotInteractableException`错误时,建议按照以下步骤排查: 1. 确认元素定位正确。 2. 等待元素可交互(显式等待)。 3. 检查元素是否被覆盖或隐藏,尝试移除覆盖物。 4. 检查是否在iframe中,如果是先切换iframe。 5. 调整窗口大小(特别是无头模式)。 6. 使用JavaScript操作作为备选方案。 希望这些方法能够解决您遇到的问题。 §§相关问题§§ 1. 如何判断Selenium中的元素是否被覆盖? 2. 如何在Selenium中处理动态加载的元素? 3. Selenium中显式等待和隐式等待的区别是什么? </think>### Selenium出现ElementNotInteractableException错误的原因及解决方案 根据引用内容[1]-[5],这个错误通常意味着元素存在但不可交互。主要原因和解决方案如下: #### 常见原因及解决方案: 1. **元素未加载完成**(引用[3]) - ✅ 增加显式等待:使用`WebDriverWait`等待元素可交互状态 ```python from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "element_id")) ) element.click() ``` 2. **元素被覆盖或隐藏**(引用[2][3][4]) - ✅ 移除覆盖元素:先关闭弹窗/广告等遮挡物 - ✅ 滚动元素到可视区域: ```python driver.execute_script("arguments[0].scrollIntoView();", element) ``` - ✅ 点击空白处解除锁定(引用[3]): ```python driver.find_element(By.XPATH, '//body').click() ``` 3. **分辨率问题**(引用[3]) - ✅ 指定浏览器窗口尺寸: ```python options.add_argument("--window-size=1920,1080") # 避免headless模式分辨率不一致 ``` 4. **操作隐藏元素**(引用[4][5]) - ✅ 使用JavaScript直接操作: ```python driver.execute_script("arguments[0].value='密码';", hidden_input) ``` 5. **iframe嵌套问题**(未直接提及但常见) - ✅ 切换到对应iframe: ```python driver.switch_to.frame("iframe_id") # 操作元素... driver.switch_to.default_content() ``` #### 疑难案例处理(引用[5]): 当遇到密码框等特殊场景: ```python # 1. 定位实际接收输入的隐藏元素 hidden_input = driver.find_element(By.CSS_SELECTOR, "input[type='password']") # 2. 使用JavaScript注入值 driver.execute_script("arguments[0].value='your_password';", hidden_input) # 3. 触发验证事件(如有需要) driver.execute_script("arguments[0].dispatchEvent(new Event('input'))", hidden_input) ``` > **调试建议**: > 使用`element.is_displayed()`和`element.is_enabled()`检查元素状态,结合浏览器开发者工具检查元素是否被遮挡或存在多个匹配元素。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值