如何在无对应元素时获取元素数量且不触发WebDriver隐式等待?
如何在不触发WebDriver隐式等待的情况下获取元素数量(元素不存在时)
我需要在页面不存在指定元素时,以最优方式获取元素数量且不触发WebDriver的隐式等待。目前我的实现代码如下:
def get_number_of_elements(self, by, locator): self.driver.implicitly_wait(0) elements = self.driver.find_elements(by, locator) self.driver.implicitly_wait(self.config.IMPLICIT_TIMEOUT) return len(elements)
该方案可行,但想知道是否有更优的实现方式?
更新说明
问题源于webdriver.Chrome的实例化方式,简言之,请勿设置driver.implicitly_wait(),示例代码如下:
import time from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By if __name__ == '__main__': options = Options() options.add_argument('--disable-dev-shm-usage') options.add_argument('--crash-dumps-dir=tmp') options.add_argument('--remote-allow-origins=*') options.add_argument("--no-sandbox") options.add_argument("--disable-gpu") options.page_load_strategy = "eager" options.add_experimental_option("excludeSwitches", ["enable-automation"]) driver = webdriver.Chrome(options=options) driver.set_page_load_timeout(30) # driver.implicitly_wait(30) # <-- 若开启此设置,当元素不存在时find_elements会触发30秒隐式等待 driver.set_script_timeout(30) driver.get("https://www.google.com") driver.find_element(By.XPATH, "//div[text()='Accept all']").click() driver.find_element(By.NAME, "q").send_keys("Stack Overflow") driver.find_element(By.XPATH, "//input[@type='submit'][@value='Google Search']").submit() elements = driver.find_elements(By.XPATH, "//h1[text()='No such thing...']") print(len(elements)) elements = driver.find_elements(By.XPATH, "//a") print(len(elements)) time.sleep(5) driver.close()
更优实现方案
你的当前方案通过临时修改隐式等待时间来避免等待,虽然可行,但频繁修改全局等待配置可能引发竞态条件(比如多线程场景下的冲突)。以下是几种更优的思路:
1. 全局禁用隐式等待(推荐)
如更新说明所示,初始化ChromeDriver时不调用driver.implicitly_wait()。此时find_elements()方法会立即返回查询结果——无论元素是否存在,都不会触发等待逻辑。这种方式无需额外代码处理,简洁且无潜在风险,适合全局不需要隐式等待的场景。
2. 使用显式等待替代临时修改隐式等待
如果全局必须保留隐式等待,可以通过显式等待设置0秒超时,配合presence_of_all_elements_located条件来获取元素列表,更贴合Selenium最佳实践:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def get_number_of_elements(self, by, locator): elements = WebDriverWait(self.driver, 0).until( EC.presence_of_all_elements_located((by, locator)) ) return len(elements)
注意:部分Selenium版本中设置0秒等待可能仍有微小延迟,此时优先选择第一种方案。
3. 直接执行JavaScript查询元素
通过原生JavaScript查询元素,完全绕开WebDriver的等待机制,执行效率最高,且不受隐式等待配置影响:
from selenium.webdriver.common.by import By def get_number_of_elements(self, by, locator): # 根据定位方式生成对应的JavaScript查询脚本 if by == By.ID: js_script = f"return document.getElementById('{locator}') ? 1 : 0;" elif by == By.CLASS_NAME: js_script = f"return document.getElementsByClassName('{locator}').length;" elif by == By.TAG_NAME: js_script = f"return document.getElementsByTagName('{locator}').length;" elif by == By.NAME: js_script = f"return document.getElementsByName('{locator}').length;" elif by == By.XPATH: js_script = f""" return document.evaluate("{locator}", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength; """ else: # 默认处理CSS_SELECTOR等其他定位方式 js_script = f"return document.querySelectorAll('{locator}').length;" return self.driver.execute_script(js_script.strip())
内容的提问来源于stack exchange,提问作者Scott Deagan
相关产品推荐
相关产品推荐

