0

0

Selenium Python自动化中处理动态元素与显式等待

花韻仙語

花韻仙語

发布时间:2025-10-24 13:48:01

|

724人浏览过

|

来源于php中文网

原创

Selenium Python自动化中处理动态元素与显式等待

selenium自动化测试中,循环操作和动态页面元素常常导致“元素未找到”错误。本文将深入探讨隐式等待和`time.sleep()`的局限性,并详细介绍如何利用selenium的显式等待机制(`webdriverwait`和`expected_conditions`)来解决此类问题,确保自动化脚本的稳定性和健壮性,特别是在重复执行任务时。

Selenium自动化中“元素未找到”的困境与显式等待的艺术

在进行Web自动化测试或数据抓取时,尤其是在涉及页面导航、动态内容加载或重复操作的场景中,我们经常会遇到“元素未找到”(ElementNotVisibleException 或 NoSuchElementException)的错误。这通常发生在脚本尝试与某个元素交互时,该元素尚未完全加载、渲染或变得可交互。本文将以一个实际的预约系统自动化案例为例,深入探讨这一问题,并提供使用Selenium显式等待的解决方案,以构建更稳定、可靠的自动化脚本。

问题的根源:隐式等待与time.sleep()的局限性

在上述预约系统的自动化流程中,用户反馈在首次执行时元素能被找到,但在循环重复执行时,却报告Element {#mat-select-value-1} was not present after 7 seconds!。这典型地揭示了两种常见的等待机制的不足:

  1. time.sleep(): 强制脚本暂停指定秒数。虽然简单,但效率低下且不可靠。如果元素提前加载,脚本会不必要地等待;如果元素加载延迟,则可能因等待时间不足而失败。在上述代码中,sleep(1)或sleep(3)等硬编码的等待时间,在不同网络环境或服务器响应速度下极易失效。
  2. 隐式等待(driver.implicitly_wait(seconds)): 设置一个全局的等待时间。在查找任何元素时,如果元素未能立即找到,WebDriver会在指定的时间内不断地查找。一旦找到,立即执行后续操作;如果超时仍未找到,则抛出异常。隐式等待的优点是全局生效,但它的缺点在于它只关心元素是否存在于DOM中,而不关心元素是否可见、是否可点击。此外,它会延长所有元素查找的时间,即使元素已经存在。在页面状态复杂或元素动态变化的场景下,隐式等待往往力不从心。错误信息中的“after 7 seconds”强烈暗示了隐式等待可能被设置为7秒,但这仍然无法解决元素可交互性的问题。

解决方案:显式等待(Explicit Waits)

显式等待是Selenium中最强大和灵活的等待机制。它允许我们定义一个特定的条件,并设置一个最长等待时间。WebDriver会在此时间内不断检查该条件是否满足,一旦满足,立即继续执行;如果超时仍未满足,则抛出TimeoutException。

显式等待主要通过WebDriverWait类和expected_conditions模块来实现。

立即学习Python免费学习笔记(深入)”;

1. 导入必要的模块

在使用显式等待之前,需要从Selenium库中导入相关模块:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

2. WebDriverWait与expected_conditions

WebDriverWait的构造函数接收两个参数:WebDriver实例和最长等待时间(秒)。

expected_conditions模块提供了多种预定义的条件,例如:

  • presence_of_element_located((By.LOCATOR, "value")):等待元素出现在DOM中。
  • visibility_of_element_located((By.LOCATOR, "value")):等待元素出现在DOM中且可见。
  • element_to_be_clickable((By.LOCATOR, "value")):等待元素可见且可点击。
  • text_to_be_present_in_element((By.LOCATOR, "value"), "text"):等待指定文本出现在元素中。

3. 改造问题代码:以select_first_category为例

根据用户提供的错误信息Element {#mat-select-value-1} was not present after 7 seconds!,问题出在选择第一个类别时。我们可以使用显式等待来确保该下拉菜单元素加载并变得可点击。

假设sb是WebDriver的实例(或其包装类,其行为类似WebDriver)。

Replit Ghostwrite
Replit Ghostwrite

一种基于 ML 的工具,可提供代码完成、生成、转换和编辑器内搜索功能。

下载

原始代码片段:

def select_first_category(sb):
    sleep(1)
    sb.highlight(".mt-15")
    sb.click('#mat-select-value-1') # Opens (Choose your Visa Application Centre) 'the Drop-down menu
    sb.click('span:contains("Application Centre")')
    select_second_category(sb)

使用显式等待改造后的代码:

def select_first_category(sb):
    # 定义最长等待时间,例如10秒
    wait = WebDriverWait(sb, 10)

    # 等待类别选择器元素变得可点击
    # 使用CSS选择器定位 #mat-select-value-1
    first_category_selector = wait.until(
        EC.element_to_be_clickable((By.ID, "mat-select-value-1")) # 注意:By.ID不需要#前缀
    )
    first_category_selector.click()
    print("First category selector clicked >>>>> Success")

    # 等待下拉菜单中的“Application Centre”选项出现并可点击
    # 这里假设sb.click('span:contains("Application Centre")') 内部能够处理等待或这是一个可靠的定位方式
    # 如果该选项也是动态加载的,也需要显式等待
    application_center_option = wait.until(
        EC.element_to_be_clickable((By.XPATH, '//span[contains(text(), "Application Centre")]'))
    )
    application_center_option.click()
    print("Application Centre option selected >>>>> Success")

    select_second_category(sb)

注意事项:

  • By.ID定位器不需要在ID值前添加#符号。#是CSS选择器的一部分。
  • 对于span:contains("Application Centre")这种CSS选择器,Selenium原生并不直接支持:contains()。通常需要转换为XPath,如//span[contains(text(), "Application Centre")]。
  • 在select_second_category和select_last_category中,也应该使用类似的显式等待来确保下拉菜单和选项加载完成并可点击。

4. 优化Check_Appointment循环逻辑

在Check_Appointment函数中,我们希望在没有预约信息时返回主页并重试,直到找到预约信息。显式等待可以更好地处理“没有预约”信息的出现或“有预约”信息的出现。

原始Check_Appointment代码片段:

def Check_Appointment(sb):
    while True:
        no_appointment_message = "We are sorry but no appointment slots are currently available. New slots open at regular intervals, please try again later"
        element_text = sb.get_text('/html/body/app-root/div/div/app-eligibility-criteria/section/form/mat-card[1]/form/div[4]')

        if no_appointment_message in element_text:
            go_to_homepage(sb)
            print("We are sorry but no appointment slots are currently available.")
            go_to_homepage(sb) # 这里重复调用 go_to_homepage
        else:
            print("Earliest available slot for Applicants")
            # playsound('./Music.mp3') # 假设这个功能是外部的
            print("Attention Alarm >>>>> Success")
            get_appointment_data(sb)
            break  # Break the loop when an appointment is found

使用显式等待和try-except优化后的Check_Appointment:

为了更好地处理预约信息页面的状态,我们可以尝试等待“无预约”消息或“有预约”的元素出现。

def Check_Appointment(sb):
    wait = WebDriverWait(sb, 15) # 给页面加载和信息出现留足时间
    no_appointment_xpath = '/html/body/app-root/div/div/app-eligibility-criteria/section/form/mat-card[1]/form/div[4]'

    while True:
        try:
            # 尝试等待“无预约”消息出现
            # 注意:这里假设sb.get_text能够获取到元素文本,或者我们可以直接等待元素出现并获取文本
            # 更好的做法是等待包含该文本的元素出现

            # 等待包含“no appointment”消息的元素出现
            # 假设该消息总是出现在特定的元素中,并且我们可以等待该元素的文本包含特定内容
            wait.until(EC.text_to_be_present_in_element((By.XPATH, no_appointment_xpath), "no appointment"))

            # 如果条件满足,说明没有预约
            print("We are sorry but no appointment slots are currently available.")
            go_to_homepage(sb)
            # 每次返回主页后,需要重新开始整个预约流程,所以这里不需要break,而是让外层循环继续
            # 如果 go_to_homepage 会自动触发 click_new_booking,那么这里就直接返回
            return # 返回到主循环,让它重新开始整个流程

        except TimeoutException:
            # 如果在规定时间内没有出现“无预约”消息,则可能是找到了预约
            # 此时可以尝试等待“有预约”的标志性元素,或者直接认为当前页面有预约
            print("Earliest available slot for Applicants")
            # playsound('./Music.mp3') # 触发警报
            print("Attention Alarm >>>>> Success")
            get_appointment_data(sb)
            break  # 找到预约,跳出循环
        except Exception as e:
            print(f"An unexpected error occurred in Check_Appointment: {e}")
            go_to_homepage(sb) # 遇到其他错误也返回主页重试
            return # 返回到主循环

重要提示:

  • go_to_homepage(sb)函数在原始代码中会调用click_new_booking(sb),这意味着它会重新开始整个预约流程。因此,在Check_Appointment中,如果发现没有预约,调用go_to_homepage(sb)后,当前Check_Appointment的循环应该结束,并将控制权交回给主循环,让主循环重新启动整个预约流程。
  • no_appointment_message的完整文本很长,使用"no appointment"作为部分匹配更具鲁棒性。

总结与最佳实践

  1. 优先使用显式等待: 显式等待是处理动态页面和异步加载内容的首选方案。它能确保在元素达到特定状态(如可见、可点击、包含特定文本)后才进行操作,大大提高脚本的稳定性。
  2. 避免滥用time.sleep(): 除非是在调试或确实需要固定延迟的特定场景,否则应尽量避免使用time.sleep()。
  3. 合理设置等待时间: WebDriverWait中的超时时间应根据实际情况设置,既不能太短导致频繁超时,也不能太长浪费执行时间。
  4. 选择正确的expected_conditions: 根据要执行的操作选择最合适的条件。例如,点击操作使用element_to_be_clickable,获取文本使用visibility_of_element_located或presence_of_element_located。
  5. 结合try-except处理: 在循环中,如果某个显式等待可能因元素确实不存在而超时,可以使用try-except TimeoutException来捕获异常,并根据业务逻辑进行相应的处理(如重试、记录日志等)。
  6. 稳健的定位器: 确保使用的元素定位器(ID、XPath、CSS选择器等)是稳定且唯一的,这是所有自动化操作的基础。

通过采纳显式等待,您的Selenium自动化脚本将能够更有效地应对Web页面的动态性,显著提升其健壮性和可靠性,尤其是在需要重复执行复杂任务的场景中。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

772

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

661

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

764

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

679

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1365

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

569

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

730

2023.08.11

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

0

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

CSS教程
CSS教程

共754课时 | 22.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号