本篇是根据学习网站和网课结合自己做的学习笔记,后续会一边学习一边补齐和整理笔记
官方学习网站在这获取:
https://selenium-python.readthedocs.io/getting-started.html#simple-usage
WEB UI自动化环境配置
(推荐靠谱的博客文章来进行环境配置,具体的我就不写了)
下载和安装 Python+下载和安装 PyCharm+安装 Selenium 库+下载浏览器驱动程序:
具体操作还得是看这两篇文章:
Selenium web UI自动化测试简介与环境搭建_selenium webui-CSDN博客
PyCharm 搭建 Selenium + Python 的自动化测试环境_pycharm自动化测试-CSDN博客
然后安装selenium的时候出现了安装不成功的问题,那就参考这篇文章:
安装selenium(超级详细)_selenium安装-CSDN博客
Chorme Driver安装链接在这,非常全了:
Chrome for Testing availability (googlechromelabs.github.io)
Anaconda安装教程参考这篇很实用:
Anaconda安装教程傻瓜教程_anaconda下没有usr目录-CSDN博客
定位元素
eg:拿测试百度网页来看:
通过ID定位
在网页上通过 ID 定位一个元素(通常是一个输入框),然后向这个输入框中输入 "Selenium",最后打印出这个输入框的当前值。
# 1. By ID - 定位搜索输入框
search_box_by_id = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "kw"))
)
search_box_by_id.send_keys("Selenium") # 在输入框中输入"Selenium"
print("Located by ID:", search_box_by_id.get_attribute("value"))
-
WebDriverWait(driver, 10)
:- 这个部分表示对
driver
(Selenium 的浏览器控制对象)进行最多 10秒 的等待时间。Selenium 中有隐式和显式等待,此处使用的是显式等待,即在指定时间内等待某个条件满足。
- 这个部分表示对
-
until(EC.presence_of_element_located((By.ID, "kw")))
:until
方法的作用是在指定的条件被满足前一直等待,或者直到超时。这里的条件是EC.presence_of_element_located
,它会等待页面上某个元素(通过指定的定位方法,如ID)被找到并存在。(By.ID, "kw")
表示通过 ID 属性定位页面上的元素,ID 的值是"kw"
。这个ID通常用于唯一标识页面中的某个元素。
-
search_box_by_id.send_keys("Selenium")
:send_keys
方法用于在找到的输入框中模拟键盘输入。这里它向页面上的搜索框输入了 "Selenium" 这个字符串。
-
print("Located by ID:", search_box_by_id.get_attribute("value"))
:get_attribute("value")
是获取输入框当前的值。它会打印出输入框中已经填入的内容,以确认"Selenium"
已经正确输入。
按名称定位
通过 Name 或 ID 属性定位页面上的搜索按钮(最终是通过 ID "su"
定位),并模拟点击操作。
# 2. By Name - 定位搜索按钮
# 定位搜索按钮(名称为wd),并点击按钮(百度按钮的ID实际为su,所以切换成用ID定位)。
search_button_by_name = driver.find_element(By.NAME, "wd")
search_button_by_name = driver.find_element(By.ID, "su") # 百度搜索按钮的ID为 "su"
search_button_by_name.click()
print("Located by Name: 搜索按钮点击成功")
-
search_button_by_name = driver.find_element(By.NAME, "wd")
:- 尝试通过按钮的 Name 属性来定位搜索按钮。
find_element(By.NAME, "wd")
意思是寻找网页中name
属性为"wd"
的元素。但百度的搜索按钮并没有这个 name 属性,因此这段代码应该是示例中的注释部分,可能是最初的尝试。
- 尝试通过按钮的 Name 属性来定位搜索按钮。
-
search_button_by_name = driver.find_element(By.ID, "su")
:- 由于百度的搜索按钮的实际ID为
"su"
,所以在这里使用 ID 来重新定位元素。find_element(By.ID, "su")
表示通过元素的 ID(即"su"
)来找到这个元素。
- 由于百度的搜索按钮的实际ID为
-
search_button_by_name.click()
:click()
方法用于模拟用户点击该按钮。这意味着一旦找到搜索按钮,Selenium 将自动执行点击操作,触发搜索功能。
按类名查找元素
输出该元素的 class
属性值,以确认定位是否正确。
# 3. By Class Name - 定位搜索输入框的父级容器
parent_div_by_class_name = driver.find_element(By.CLASS_NAME, "s_form")
print("Located by Class Name:", parent_div_by_class_name.get_attribute("class"))
Class Name 是 HTML 元素的一个属性,用于标识多个元素共享的样式或功能,因此使用 Class Name 可以选择某些具有相同特征的元素。
按标签名称定位元素
输出找到的链接数量,方便确认是否正确定位了页面上的所有链接。
# 4. By Tag Name - 定位所有链接
all_links_by_tag_name = driver.find_elements(By.TAG_NAME, "a")
print(f"Located by Tag Name: 找到 {len(all_links_by_tag_name)} 个链接")
-
all_links_by_tag_name = driver.find_elements(By.TAG_NAME, "a")
:- 这行代码通过
TAG_NAME
定位页面中的所有<a>
标签。find_elements(By.TAG_NAME, "a")
方法会返回一个包含所有链接元素的列表(每个链接都是由<a>
标签定义的)。 - 这里的
find_elements
返回多个元素,因此用find_elements
而不是find_element
。即使页面上有多个<a>
标签,它也可以找到并返回所有的链接元素。
- 这行代码通过
-
print(f"Located by Tag Name: 找到 {len(all_links_by_tag_name)} 个链接")
:len(all_links_by_tag_name)
获取all_links_by_tag_name
列表的长度,也就是找到的<a>
标签的数量。- 使用
f-string
格式化输出信息,将找到的链接数量插入到打印语句中,向用户反馈已经定位到多少个链接。
通过 XPath 定位
- 通过 XPath 精确定位页面中的百度新闻链接,确保链接的
href
和class
属性满足指定条件。 - 使用 显式等待 确保在指定的时间内,等待元素的加载,适应动态网页。
# 5.使用XPath来进行定位元素 定位新闻
# CSSSelector中的href属性值需要使用引号包围
news_link_by_xpath = WebDriverWait(driver, 20).until(
EC.presence_of_element_located(
(By.XPATH, "//a[@href='http://news.baidu.com' and @class='mnav c-font-normal c-color-t']")
)
)
-
WebDriverWait(driver, 20).until(...)
:WebDriverWait
是 Selenium 提供的显式等待方法,用于等待某个条件成立。在这里,我们告诉 Selenium 最多等待 20 秒,直到元素被定位并可用为止。- 显式等待 是在特定条件下使用的,它可以等待某个元素出现或某个状态完成,适用于动态加载的页面。
-
EC.presence_of_element_located(...)
:EC
是expected_conditions
的缩写。presence_of_element_located
表示等待某个元素在 DOM 中存在,但不一定可见。这里通过 XPath 指定我们要寻找的元素。
-
By.XPATH
和 XPath 表达式:By.XPATH
指定使用 XPath 定位元素。XPath 是一种用于查找 XML 或 HTML 文档中特定元素的路径语言,特别适合用于复杂结构或需要多条件筛选的情况。"//a[@href='http://news.baidu.com' and @class='mnav c-font-normal c-color-t']"
://a
:表示在整个页面中查找<a>
标签(链接元素)。[@href='http://news.baidu.com']
:指定href
属性值必须是"http://news.baidu.com"
,也就是指向百度新闻的链接。[@class='mnav c-font-normal c-color-t']
:指定class
属性必须为'mnav c-font-normal c-color-t'
,确保只选择特定样式的链接。
通过链接文本查找超链接
- 通过部分链接文本定位包含“视频”一词的链接,并打印出该链接的完整文本。
- 适合用于无法预知链接的完整文本,但知道部分文本的场景。
# 6. By Partial Link Text - 定位部分文本包含"视频"的链接
video_link_by_partial_link_text = driver.find_element(By.PARTIAL_LINK_TEXT, "视频")
print("Located by Partial Link Text:", video_link_by_partial_link_text.text)
-
driver.find_element(By.PARTIAL_LINK_TEXT, "视频")
:- 这个方法使用 Partial Link Text 定位页面中的链接。
By.PARTIAL_LINK_TEXT
允许通过部分链接文本进行定位,而不要求完整匹配链接文本。 - 这里寻找的是文本部分包含 “视频” 的链接(
<a>
标签)。它只需要链接文本中含有 “视频” 这两个字,就可以定位到对应的元素。 find_element
方法返回页面中第一个匹配的元素对象。
- 这个方法使用 Partial Link Text 定位页面中的链接。
-
video_link_by_partial_link_text.text
:text
属性用于获取找到的链接元素的可见文本。在这个例子中,video_link_by_partial_link_text.text
会返回链接的完整文本内容。
通过 CSS 选择器定位元素
# 7. By CSS Selector - 定位百度logo
logo_by_css_selector = driver.find_element(By.CSS_SELECTOR, "#lg > img")
print("Located by CSS Selector: 百度Logo已找到")
-
driver.find_element(By.CSS_SELECTOR, "#lg > img")
:- 这行代码通过 CSS Selector 定位元素,使用的是
find_element
方法,它会返回页面中第一个符合条件的元素。 - CSS Selector 是一种灵活且强大的方式,允许我们通过 CSS 规则定位元素。它支持多种选择器类型,包括 ID、类、标签、属性等。
- 在这个例子中,
#lg > img
表示选择 ID 为lg
的元素下的 img 标签:#lg
:表示一个 ID 为lg
的元素(ID 选择器)。>
:表示选择其直接子元素。img
:表示一个 img 标签(图像元素)。
- 结合起来,这个选择器用于选择 ID 为
lg
的元素内的 img 元素(通常是百度主页上的 Logo 图片)。
- 这行代码通过 CSS Selector 定位元素,使用的是
总体代码如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 初始化 WebDriver
service = Service(executable_path="D:/Apython/chromedriver.exe")
driver = webdriver.Chrome(service=service)
# 打开百度主页
driver.get('https://www.baidu.com')
try:
# 1. By ID - 定位搜索输入框
search_box_by_id = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "kw"))
)
search_box_by_id.send_keys("Selenium") # 在输入框中输入"Selenium"
print("Located by ID:", search_box_by_id.get_attribute("value"))
# 2. By Name - 定位搜索按钮
# 定位搜索按钮(名称为wd),并点击按钮(百度按钮的ID实际为su,所以切换成用ID定位)。
search_button_by_name = driver.find_element(By.NAME, "wd")
search_button_by_name = driver.find_element(By.ID, "su") # 百度搜索按钮的ID为 "su"
search_button_by_name.click()
print("Located by Name: 搜索按钮点击成功")
# 3. By Class Name - 定位搜索输入框的父级容器
parent_div_by_class_name = driver.find_element(By.CLASS_NAME, "s_form")
print("Located by Class Name:", parent_div_by_class_name.get_attribute("class"))
# 4. By Tag Name - 定位所有链接
all_links_by_tag_name = driver.find_elements(By.TAG_NAME, "a")
print(f"Located by Tag Name: 找到 {len(all_links_by_tag_name)} 个链接")
# 5.使用XPath来进行定位元素 定位新闻
# CSSSelector中的href属性值需要使用引号包围
news_link_by_xpath = WebDriverWait(driver, 20).until(
EC.presence_of_element_located(
(By.XPATH, "//a[@href='http://news.baidu.com' and @class='mnav c-font-normal c-color-t']")
)
)
# 6. By Partial Link Text - 定位部分文本包含"视频"的链接
video_link_by_partial_link_text = driver.find_element(By.PARTIAL_LINK_TEXT, "视频")
print("Located by Partial Link Text:", video_link_by_partial_link_text.text)
# 7. By CSS Selector - 定位百度logo
logo_by_css_selector = driver.find_element(By.CSS_SELECTOR, "#lg > img")
print("Located by CSS Selector: 百度Logo已找到")
# 8. By XPath - 定位搜索输入框
search_box_by_xpath = driver.find_element(By.XPATH, "//input[@id='kw']")
search_box_by_xpath.clear() # 清空输入框内容
search_box_by_xpath.send_keys("XPath 选择器") # 再次输入
print("Located by XPath:", search_box_by_xpath.get_attribute("value"))
except Exception as e:
print("An error occurred:", str(e))
finally:
# 关闭浏览器
driver.quit()
等待页面加载完成
Selenium Webdriver 提供两种类型的waits - 隐式和显式。 显式等待会让WebDriver等待满足一定的条件以后再进一步的执行。 而隐式等待让Webdriver等待一定的时间后再才是查找某元素。
显式等待
在代码中定义等待一定条件发生后再进一步执行代码。
最糟糕的案例是使用time.sleep(),它将条件设置为等待一个确切的时间段。 这里有一些方便的方法让你只等待需要的时间。WebDriverWait结合ExpectedCondition 是实现的一种方式。
隐式等待
如果某些元素不是立即可用的,隐式等待是告诉WebDriver去等待一定的时间后去查找元素。 默认等待时间是0秒,一旦设置该值,隐式等待是设置该WebDriver的实例的生命周期。
eg,拿百度首页先在输入框输入Selenium之后,等待一会儿在跳转视频模块进行举例
from selenium import webdriver
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
# 自定义等待类:等待元素具有特定的CSS类
class element_has_css_class(object):
def __init__(self, locator, css_class):
self.locator = locator
self.css_class = css_class
def __call__(self, driver):
element = driver.find_element(*self.locator)
if self.css_class in element.get_attribute("class"):
return element
else:
return False
# 初始化Chrome WebDriver
driver = webdriver.Chrome()
try:
# 访问百度首页
driver.get("https://www.baidu.com")
# 等待百度首页的搜索框加载并可点击
search_box = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "kw"))
)
print("搜索框已加载并可点击")
# 在搜索框中输入关键词并提交
search_box.send_keys("Selenium")
search_box.submit()
# 等待搜索结果页面加载,并等待搜索结果元素加载完成
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "content_left"))
)
print("搜索结果页面已加载")
# 通过CSS类检查搜索按钮是否加载完成并可点击
# 使用自定的element_has_css_class 等待搜素按钮具备特定的CSS类 确保样式正确
search_button = WebDriverWait(driver, 10).until(
element_has_css_class((By.ID, "su"), "bg s_btn")
)
print("搜索按钮具备指定的CSS类")
# 点击“新闻”链接,使用CSS Selector定位
news_link = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.LINK_TEXT,"视频"))
)
news_link.click()
print("已点击视频链接")
# 等待新闻页面加载完成
WebDriverWait(driver, 10).until(
EC.title_contains("百度新闻")
)
print("百度新闻页面已加载")
# 等待某个新闻板块可见
news_section = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".news-nav-item"))
)
print("新闻板块已加载")
# 进一步操作,如点击具体的新闻标题等
finally:
# 等待几秒后关闭浏览器
time.sleep(20)
driver.quit()
eg,获取百度页面的 title 和 URL,并使用句柄方式切换窗口的例子:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
# 创建一个 WebDriver 实例
driver = webdriver.Chrome()
# 打开百度首页
driver.get("http://www.baidu.com")
# 获取当前窗口的句柄
current_window_handle = driver.current_window_handle
# 获取当前窗口的 title 和 URL
print("当前窗口的 title:", driver.title)
print("当前窗口的 URL:", driver.current_url)
# 点击百度首页上的 "新闻" 链接,打开一个新窗口
driver.find_element(By.LINK_TEXT, "新闻").click()
# 等待 2 秒,确保新窗口已经打开
time.sleep(2)
# 获取所有窗口的句柄
all_window_handles = driver.window_handles
# 遍历所有窗口的句柄
for window_handle in all_window_handles:
# 如果当前窗口的句柄不是第一个窗口的句柄
if window_handle != current_window_handle:
# 切换到当前窗口
driver.switch_to.window(window_handle)
# 获取当前窗口的 title 和 URL
print("当前窗口的 title:", driver.title)
print("当前窗口的 URL:", driver.current_url)
# 关闭所有窗口
driver.quit()
页面对象
一个页面对象表示在你测试的WEB应用程序的用户界面上的区域。
使用页面对象模式的好处:
- 创建可复用的代码以便于在多个测试用例间共享
- 减少重复的代码量
- 如果用户界面变化,只需要修改一处
项目目录结构:
pythonProject/
├── po/
│ ├── __init__.py # 初始化文件
│ ├── element.py # 页面元素封装
│ └── page.py # 页面对象类定义
│
├── tests/
│ ├── __init__.py # 初始化文件
│ └── test_search.py # 测试用例
└── requirements.txt # 依赖文件
eg1:要自动化测试 Python 官方网站的搜索功能。具体步骤如下:
打开 Python 官网。
输入搜索关键字,例如 "pycon"。
点击搜索按钮。
验证搜索结果页面是否正确加载。
页面元素
po/element.py
中定义页面元素封装类
# 页面元素封装 包含基本的操作方法 例如查找元素、点击、发送文本等。
# 定位元素
from selenium.webdriver.common.by import By
# 处理页面加载时间不确定的情况,确保在操作元素之前它已经存在或可见。
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions (EC): 一个预定义的条件集,可以结合 WebDriverWait 使用。
# 例如,等待某个元素出现、可点击、页面标题包含某些内容等。
from selenium.webdriver.support import expected_conditions as EC
# 封装了对页面元素的基本操作 查找 点击和输入文本
class BaseElement:
def __init__(self, driver, by, value):
# 与浏览器的交互
self.driver = driver
# 元素的定位方式
self.by = by
# 元素的定位值
self.value = value
def find_element(self):
# 等待最多10秒钟,直到满足条件。如果 10
# 秒内条件未满足,会抛出超时异常。
return WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((self.by, self.value))
)
# 通过find_element方法找到元素,然后执行点击操作。
def click(self):
self.find_element().click()
# 向页面上的输入框元素发送文本(例如输入搜索关键词)
def send_keys(self, text):
# 先通过find_element方法找到元素,然后将文本text输入到该元素中。
self.find_element().send_keys(text)
页面对象类
po/page.py
中创建页面对象类
# 页面对象类定义 代表 Python 官网的首页以及搜索结果页面。
from po.element import BaseElement
from selenium.webdriver.common.by import By
# 封装了主页上的操作:输入搜索关键词和点击搜索按钮。
class PythonOrgHomePage:
def __init__(self, driver):
self.driver = driver
# search_box和go_button:这两个是定位器,用于定位主页上的搜索框和搜索按钮。
# BaseElement类封装了元素的查找和操作逻辑,By.NAME, "q"和By.ID, "submit"指定了如何定位这些元素。
self.search_box = BaseElement(driver, By.NAME, "q")
self.go_button = BaseElement(driver, By.ID, "submit")
# 用于在搜索框中输入搜索词。 term: 要输入的搜索关键词。
def enter_search_term(self, term):
self.search_box.send_keys(term)
# term: 要输入的搜索关键词。找到搜索按钮并执行点击操作。
def click_go_button(self):
self.go_button.click()
# 封装了搜索结果页面的验证逻辑。通过检查页面标题,它可以确定搜索是否成功。
class SearchResultsPage:
def __init__(self, driver):
self.driver = driver
def is_result_found(self):
print("Current page title:", self.driver.title)
return "Search Python.org" in self.driver.title
测试用例
tests/test_search.py
中编写测试用例
# 测试用例
import unittest
from selenium import webdriver
from po.page import PythonOrgHomePage, SearchResultsPage
class PythonOrgSearchTest(unittest.TestCase):
# 在每个测试用例执行之前调用,用于初始化测试环境。
def setUp(self):
self.driver = webdriver.Chrome() # 使用 Chrome 浏览器
self.driver.get("https://www.python.org")
def test_search_in_python_org(self):
# 创建一个 PythonOrgHomePage实例,封装了主页上的操作。
home_page = PythonOrgHomePage(self.driver)
# 在搜索框中输入"pycon"
home_page.enter_search_term("pycon")
# 点击搜索按钮
home_page.click_go_button()
# 封装了搜索结果页面的操作。
search_results_page = SearchResultsPage(self.driver)
self.assertTrue(search_results_page.is_result_found())
# 每个测试用例执行之后调用,用于清理测试环境。
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
eg2,使用 Selenium WebDriver 和 unittest 框架,测试百度搜索功能
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class BaiduHomePage:
def __init__(self, driver):
self.driver = driver
# 元组,用于指定搜索框和搜索按钮的定位方式(ID)。
self.search_box = (By.ID, "kw")
self.search_button = (By.ID, "su")
# 在搜索框中输入搜索词
# 等待搜索框出现
# 超时时间为10s
# 向搜索框中输入搜索词
def enter_search_term(self, term):
WebDriverWait(self.driver, 10).until(EC.presence_of_element_located(self.search_box)).send_keys(term)
# 点击搜索按钮
# 等待搜索按钮可点击,超时时间为 10 秒
# 等待条件,元素可点击
# 点击搜索按钮
def click_search_button(self):
WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable(self.search_button)).click()
class BaiduSearchResultsPage:
def __init__(self, driver):
self.driver = driver
# 用于检查搜索结果页面是否正确加载
def is_result_found(self):
return "百度一下,你就知道" in self.driver.title
test_baidu_search.py(测试用例)
import unittest
from selenium import webdriver
from page import BaiduHomePage, BaiduSearchResultsPage
class TestBaiduSearch(unittest.TestCase):
# 在每个测试用例执行前执行一次,用于初始化测试环境。
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://www.baidu.com")
def test_baidu_search(self):
home_page = BaiduHomePage(self.driver)
home_page.enter_search_term("Python")
home_page.click_search_button()
search_results_page = BaiduSearchResultsPage(self.driver)
self.assertTrue(search_results_page.is_result_found())
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()