【selenium】八种定位元素方法详解

一、前置知识

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("\n所有任务完成,正在关闭所有浏览器...")
for driver_item in drivers:
    driver_item.quit()

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

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

1、ID定位

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

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

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

html页面示例:

<input id="loginName" type="text" placeholder="请输入用户名">

定位脚本:

username = driver.find_element(By.ID, "loginName")

2、Name定位

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

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

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

html页面示例:

<input name="password" type="password">

定位脚本:

pwd = driver.find_element(By.NAME, "password")

pwd.send_keys("123456")

3、Class_Name定位

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

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

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

html示例:

<button class="login-btn">登录</button>

<span class="t-checkbox__label">运营角色</span>

定位脚本:

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示例:

<ul>

         <li><a href="https://www.google.com">谷歌</a></li>

        <li><a href="https://www.bing.com">必应</a></li>

        <li><a href="https://www.yahoo.com">雅虎</a></li>

</ul>

定位上面的所有的链接:

links = driver.find_elemets(By.TAG_NAME,  "a")

5、Link Text定位

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

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

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

html示例:

<a href="/home">首页</a>

定位脚本:

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

home_link.click()

6、Partial Link Text定位

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

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

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

html示例:

<a href="/download">下载最新版本软件</a>

定位脚本:

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

find_link.click()

7、CSS选择器定位

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

缺点:语法复杂

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

html示例:

<span CLASS=t-checkbox__label>运营角色</span>

定位脚本:
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 = """
<div class="parent">
    <input type="text" />           <!-- 前面兄弟 -->
    <input type="checkbox" />       <!-- 前面兄弟 -->
    <span>运营角色</span>           <!-- 当前元素 -->
    <button>确定</button>           <!-- 后面兄弟 -->
</div>
"""

# 各种轴的使用:
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示例:

<!-- 实际的HTML结构可能是这样的: -->
<div class="t-popup__content">
    <div class="popup-header">...</div>
    <div class="popup-body">
        <ul class="option-list">
            <li class="option-item">
                <input type="checkbox" tabindex="-1" />  <!-- 这是目标 -->
                <span>运营角色</span>
            </li>
            <li class="option-item">
                <input type="checkbox" tabindex="0" />   <!-- 不是目标 -->
                <span>管理角色</span>
            </li>
        </ul>
    </div>
</div>

定位脚本:

"//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

<button 
   class="t-button t-button--variant-base t-button--theme-primary t-size-l !mt-[60px] !w-full"
   type="submit"
   tabindex="0">
  <span class="t-button__text">登录</span>
</button>
定位脚本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 文本或层级,能保证定位长期可用

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值