一、前置知识

1、find_element()和find_elements()的区别

find_element():

  • 目标:查找并返回第一个匹配定位策略的元素
  • 返回对象:一个 WebElement 对象
  • 未找到对象时:抛出异常NoSuchElementException ,程序中断
  • 主要用途:与查找的唯一、特定元素进行交互,比如:点击登录按钮,唯一的搜索框中输入文本搜索
  • 后续操作:直接对返回的 WebElement 对象进行操作(send.keys(),click())

find_elements()

  • 目标:查找并返回所有定位策略的元素
  • 返回对象:一个或多个WebElement 对象的列表(list)
  • 未找到对象时:返回空列表[],程序继续执行
  • 主要用途:获取一组元素进行遍历、检查符合条件的元素是否存在(返回列表的长度大于0)、获取页面元素的总数
  • 后续操作:先遍历列表,再对列表中每个WebElement 对象进行操作

2、driver和drivers的区别

driver:一个单一的、控制一个浏览器实例的WebElement 对象

drivers:

一个或包含多个driver对象的集合(列表或者字典),同时管理多个浏览器实例

应用场景:

并发测试:同时在不同浏览器运行不同测试用例,缩短总的测试时间

跨浏览器测试:验证网页兼容性

多用户模拟:模拟多个用户同时登录或操作一个网站

3、实例脚本

from selenuim import webdriver
import time
import threading
from selenuim.wendriver.support import excepted_conditions as EC

browser_types= ['chome' ,'firefox'?]

drivers = []

for browser_type in browser_types:

? ? ? ? if browser_type == "chome":

? ? ? ? ? ? ? ? driver = webdriver.Chome()

? ? ? ? elsif browser_type == "firefox"

? ? ? ? ? ? ? ? driver = webdriver.Firefox()

? ? ? ? drivers.append(driver)

print(f"成功初始化了 {len(drivers)} 个浏览器实例。")
# 定义一个函数,让每个浏览器执行相同的操作
def perform_search(driver_instance, keyword):
    try:
        driver_instance.get("https://www.google.com" )
        search_box = driver_instance.find_element("name", "q")
        search_box.send_keys(keyword)
        search_box.submit()
        print(f"[{driver_instance.name}] 正在搜索: {keyword}")
        time.sleep(5) # 等待搜索结果
    except Exception as e:
        print(f"在 {driver_instance.name} 中发生错误: {e}")

# 创建并启动线程,让每个浏览器并行执行搜索任务
threads = []
for i, driver_item in enumerate(drivers):
    # 为每个浏览器创建一个线程
    thread = threading.Thread(target=perform_search, args=(driver_item, f"并行测试 {i+1}"))
    threads.append(thread)
    thread.start()

# 等待所有线程执行完毕
for thread in threads:
    thread.join()

# 所有任务完成后,遍历 drivers 列表,关闭所有浏览器
print("
所有任务完成,正在关闭所有浏览器...")
for driver_item in drivers:
    driver_item.quit()

print("所有浏览器已关闭。")

二、selenium元素定位的八种方法

1、ID定位

优点:在一个页面中id是唯一的,定位是最快的

缺点:不是所有元素都有id

适用场景:当前元素有id属性时,优先使用

html页面示例:

定位脚本:

username = driver.find_element(By.ID, “loginName”)

2、Name定位

优点:表单通常使用name属性

缺点:定位不唯一,可能有多个

适用场景:表单元素(下拉框、输入框、单选框)

html页面示例:

定位脚本:

pwd = driver.find_element(By.NAME, “password”)

pwd.send_keys(“123456”)

3、Class_Name定位

优点:元素基本都会使用class

缺点:定位不唯一,可能会定位到多个元素

适用场景:元素有独特的class名称

html示例:

登录

运营角色

定位脚本:

login_button = driver.find_element(By.CLASS_NAME, “login-btn”)

login_button.click()

checkbox = driver.find_element(By.CLASS_NAME, “t-checkbox__label”)

4、Tag_Name定位

优点:通过html标签名定位

缺点:同类型标签很多,定位不唯一

适用场景:标签少,或配合其他定位方式一起使用

html示例:

    • 谷歌
    • 必应
    • 雅虎
    • 定位上面的所有的链接:

      links = driver.find_elemets(By.TAG_NAME,“a”)

      5、Link Text定位

      优点:通过链接的完整内容文本定位,直观,利于理解和维护

      缺点:只能用于链接元素,且文本需完全匹配

      适用场景:专门用于定位超链接(标签)

      html示例:

      首页

      定位脚本:

      home_link = driver.find_element(By.LINK_TEXT, “首页”)

      home_link.click()

      6、Partial Link Text定位

      优点:链接文本部分内容定位,更灵活不需要完整匹配

      缺点:只能用于链接,可能会匹配到多个

      适用场景:当链接文本过长或需要变化时

      html示例:

      下载最新版本软件

      定位脚本:

      find_link = driver.find_elemet(By.PARTIAL_LINK_TEXT, “下载”)

      find_link.click()

      7、CSS选择器定位

      优点:适用CSS语法选择器定位,灵活性高,可组合多种条件查找

      缺点:语法复杂

      适用场景:复杂定位需求,其他方法需组合使用时

      html示例:

      运营角色

      定位脚本:
      label = driver.find_element(By.CSS_SELECTOR, “span.t-checkbox__label”)

      8、XPath定位

      优点:适用xpath语法定位元素,是最强大的定位方法,可以实现任何复杂的定位需求

      缺点:语法复杂,性能相对较慢

      适用场景:当其他定位方法都不可用时

      定位脚本:

      # 绝对路径(不推荐,太脆弱)
      element = driver.find_element(By.XPATH, “//html/body/div[1]/form/input[1]”)

      # 相对路径(推荐)
      element = driver.find_element(By.XPATH, “//input[@id=‘username’]”)

      # 通过文本内容定位
      button = driver.find_element(By.XPATH, “//button[text()=‘登录’]”)

      # 通过属性定位
      element = driver.find_element(By.XPATH, “//input[@placeholder=‘请输入用户名’]”)

      # 通过父子关系定位
      element = driver.find_element(By.XPATH, “//div[@class=‘form-group’]//input”)

      parent::找父元素

      child::找子元素

      # 通过兄弟关系定位
      element = driver.find_element(By.XPATH, “//label[text()=‘用户名’]/following-sibling::input”)

      preceding-sibling::向前找兄弟元素

      following-sibling::向后找兄弟元素

      三、定位示例

      # 假设HTML结构:
      html_example = “”"

      运营角色 确定

      “”"

      # 各种轴的使用:
      axis_examples = {
      “前面的兄弟”: “//span[text()=‘运营角色’]/preceding-sibling::input”,
      “后面的兄弟”: “//span[text()=‘运营角色’]/following-sibling::button”,
      “父元素”: “//span[text()=‘运营角色’]/parent::div”,
      “子元素”: “//div[@class=‘parent’]/child::span”,
      “所有前面兄弟”: “//span[text()=‘运营角色’]/preceding-sibling:😗”
      }

      复杂的XPath详细解析

      html示例:

      定位脚本:

      “//div[@class=‘t-popup__content’]//input[@type=‘checkbox’ and @tabindex=‘-1’]”

      //div[@class=‘t-popup__content’]:整个页面中查找class为’t-popup__content’的div元素,通常是一个弹出框的内容区域

      //input[@type=‘checkbox’ and @tabindex=‘-1’]:在前面找到的div的任意层级中查找type为’checkbox‘并且tabindex为’-1’的input元素

      • // = 任意层级(不管隔了多少层)
      • / = 直接子层级(只能是直接子元素)
      • and = 同时满足多个条件

      四、踩过的坑

      原始HTML


      登录

      定位脚本1(未找到该元素):

      login_button = (By.XPATH, “//button[@type=‘submit’ and contains(@class,‘t-button’)]”)

      定位脚本2(未找到该元素):

      login_button = (By.XPATH, “//button[contains(@class,‘t-button’) and .//span[normalize-space()=‘登录’]]”)

      定位失败原因:

      • 依赖文字
      • 语法层级太深
      • XPATH易读性差

      最终换成了如下脚本(定位到了该元素):
      login_button = (By.CSS_SELECTOR, “button.t-button[type=‘submit’]”)

      其他情况:如果HTML页面上有多个submit按钮

      driver.find_elements(By.CSS_SELECTOR, “button.t-button[type=‘submit’]”)[0]

      定位成功原因:

      基于标准属性(type=submit)+稳定class(t-button)+明确标签(button),不依赖会频繁变动的UI文本或层级,能保证定位长期可用

    Logo

    有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

    更多推荐