Python Selenium find_element传变量定位元素报错解决
使用Selenium Python的find_element方法传入变量定位元素时,触发ElementNotInteractableException异常。待定位的页面HTML结构如下,需求是向find_element传入包含data-code属性值的变量,定位对应元素后执行点击操作:
<div class="stations-columns"> <span class="station-link" data-code="BC_">Bologna Centrale</span> <span class="station-link" data-code="SMN">Firenze S.M.Novella</span> <span class="station-link" data-code="LON">Lamezia Terme C</span> <span class="station-link" data-code="MRT">Maratea</span> <div>
初期先测试传入单个字符串参数,后续会改造为循环遍历列表批量传参。最初尝试CSS_SELECTOR和XPATH两种定位写法均无法正常运行,测试代码如下:
code = 'BC_' # CSS_SELECTOR 尝试写法 driver.find_element(By.CSS_SELECTOR, "span[data-code='" + code + "']").click() # XPATH 尝试写法 xpath = f'.//span[@data-code=\'{code}\']' driver.find_element(By.XPATH,xpath).click()
补充问题说明
后续尝试通过CLASS_NAME定位元素,效果相对更好,但存在两个问题:
- 该方法会返回全部匹配的元素列表,需要额外做解析筛选;
- 目标元素位于下拉菜单内,部分元素处于隐藏状态,需要滚动到对应元素位置才能操作。
编写的滚动实现代码在捕获异常后尝试滚动到隐藏元素时,触发MoveTargetOutOfBoundsException异常,待调整代码如下:
# 点击输入框触发下拉菜单加载(该操作会加载目标站点元素) box_destino.click() # 查找并筛选目标元素 station_codes_tot_new = driver.find_elements(By.CLASS_NAME, 'station-link') station_codes_destino_new = [] for elem in range(len(station_codes_origine),len(station_codes_tot_new)): station_codes_destino_new.append(station_codes_tot_new[elem]) # 尝试点击下拉菜单中隐藏的元素时触发MoveTargetOutOfBoundsException try: station_codes_destino_new[10].click() except: actions = ActionChains(driver) actions.move_to_element(station_codes_destino_new[10]).perform() station_codes_destino_new[10].click()
1. 定位逻辑问题排查
最初写的CSS选择器、XPath定位语法本身没有错误,触发ElementNotInteractableException的核心原因是执行点击时,下拉菜单未完全加载,目标元素还没进入可交互状态,和传参定位的写法无关。
不需要先抓取全量class匹配元素再手动筛选,直接用显式等待等目标元素加载到可交互状态即可,支持直接传入data-code变量定位:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC code = "BC_" wait = WebDriverWait(driver, 10) # 先点击输入框触发下拉菜单加载 box_destino.click() # 等待对应属性的元素可点击,直接定位不需要二次筛选 target_elem = wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR, f'span.station-link[data-code="{code}"]')) ) target_elem.click()
后续批量遍历场景,只需要把code换成列表循环即可。
2. 隐藏元素滚动越界问题修复
ActionChains.move_to_element触发MoveTargetOutOfBoundsException,是因为下拉菜单是独立滚动容器,直接移动到容器视口外的元素会超出边界。改用JS执行滚动,直接把目标元素滚动到下拉容器可视区域即可,不会触发越界:
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time wait = WebDriverWait(driver, 10) # 批量遍历的站点code列表 code_list = ["BC_", "SMN", "LON", "MRT"] # 点击输入框触发下拉加载 box_destino.click() # 等待下拉容器加载可见 wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "stations-columns"))) for code in code_list: # 定位对应code的目标元素 target = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, f'span.station-link[data-code="{code}"]')) ) # JS滚动元素到容器可视区域中间位置 driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", target) time.sleep(0.2) # 等待元素可点击后执行操作 wait.until(EC.element_to_be_clickable(target)).click() # 单选场景点击后下拉会关闭,直接终止循环即可;多选场景加短等待等菜单重新加载再进入下一轮 time.sleep(0.3)
代码里不要用无指定异常类型的裸
except,会吞掉定位失败、加载超时等核心报错信息,提升问题排查成本。需要做异常捕获时,明确指定要捕获的异常类即可。
内容的提问来源于stack exchange,提问作者Luca Giovanni Voglino

