软件

  • 下载地址https://pan.67an.com/
  • jetbrainspycharm-professional-2023.1
  • pythonpython-3.8.10-amd64
  • selenium4IEDriverServer_Win32_4.14.0edgechrome等驱动
  • DisableIEToEdge开启IE浏览器

Win10、11开启IE11

  • DisableIEToEdge下载打开点击修复(杀毒软件会杀,需加入白名单防拦截,非IE11不要使用)
  • 修复完成后弹窗修复成功咯,恭喜您可以继续使用IE11啦!祝您工作顺利,万事顺意
  • 桌面有Internet Explorer图标

Selenium4

  • html
  • Python面向对象
  • pytest
  • yaml数据驱动
  • allure报告
  • log日志
  • PO封装
  • jenkins

IE浏览器官方答复

必要的配置

  • IEDriverServer可执行文件必须已下载并放置在您的 PATH 中.
  • 在Windows Vista, Windows 7或Windows 10上的IE 7或更高版本上, 必须将每个区域的保护模式设置设置为相同的值. 该值可以打开或关闭, 只要每个区域的值相同. 要设置受保护模式设置, 请从“工具”菜单中选择“Internet选项…”, 然后单击“安全”选项卡. 对于每个区域, 标签底部将有一个复选框, 标记为“启用保护模式”.
  • 此外, IE 10及更高版本必须禁用“增强保护模式”. 此选项位于“Internet选项”对话框的“高级”选项卡中.
  • 浏览器缩放级别必须设置为100%, 以便将本机鼠标事件设置为正确的坐标.
  • 对于Windows 10, 您还需要在显示设置中将“更改文本、应用程序和其他项目的大小”设置为100%.
  • 仅对于IE 11, 您需要在目标计算机上设置一个注册表项, 以便驱动程序能够保持与它创建的Internet Explorer实例的连接. 对于32位Windows安装, 您必须在注册表编辑器中检查的项是HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BFCACHE. 对于64位Windows安装, 键为 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BFCACHE. 请注意, FEATURE_BFCACHE 子项可能存在, 也可能不存在, 如果不存在, 则应创建该子项. 要点: 在此键内, 创建一个名为iexplore.exe值为0的DWORD.

原生事件以及Internet Explorer

  • 由于 InternetExplorerDriver 仅适用于Windows, 因此它尝试使用所谓的“原生”或操作系统级事件 在浏览器中执行鼠标和键盘操作. 针对同样的操作, 与使用JavaScript模拟相比有明显的差异. 使用原生事件的优点是它不依赖于JavaScript沙箱, 并且可以确保在浏览器中正确传播JavaScript事件. 但是, 当IE浏览器窗口失焦, 以及当尝试将鼠标悬停在元素上时, 当前存在一些鼠标事件问题.

浏览器焦点

  • 难点在于, 如果窗口没有焦点, IE本身似乎没有完全尊重我们在IE浏览器窗口 (WM\_MOUSEDOWN 和 WM\_MOUSEUP) 上发送的Windows消息. 具体来说, 被单击的元素将在其周围接收一个焦点窗口, 但该元素不会处理该单击. 可以说, 我们根本不应该发送信息; 相反, 我们应该使用 SendInput() API, 但该API明确要求窗口具有焦点. WebDriver项目有两个相互冲突的目标.
  • 首先, 我们争取尽可能地模仿用户. 这意味着使用原生事件, 而不是使用JavaScript模拟事件.
  • 其次, 我们不希望浏览器窗口的焦点被自动化. 这意味着仅将浏览器窗口强制到前台是次优的.
  • 另一个考虑因素是 多个IE实例在多个WebDriver实例下运行的可能性, 这意味着任何此类“将窗口置于前台”解决方案 都必须包装某种同步结构 (互斥体?)到 IE驱动程序的C++代码中. 即使如此, 若用户将另一个窗口带到前台的操作, 介于驱动程序将IE带到前台和执行原生事件之间, 则此代码仍将受制于竞争条件.
  • 围绕驱动程序的需求, 以及如何对这两个相互冲突的目标进行优先排序的讨论正在进行中. 当前流行的观点是前者优先于后者, 并在使用IE驱动程序时, 将您的机器标记为无法执行其他任务. 然而, 这一决定远未最终确定, 实现这一决定的代码可能相当复杂.

悬停在元素上

  • 当您尝试将鼠标悬停在元素上, 并且物理鼠标光标位于IE浏览器窗口的边界内时, 鼠标悬停将不起作用. 更具体地说, 悬停将在几分之一秒内工作, 然后元素将恢复到其以前的状态. 出现这种情况的普遍理论是, IE在其事件循环期间正在进行某种类型的命中测试, 这导致它在物理光标位于窗口边界内时响应物理鼠标位置. WebDriver开发团队仍未找到解决IE这种行为的方法.

点击元素选项或提交表单以及弹窗

  • IE驱动程序在两个地方不使用原生事件与元素交互. 这是在 <select> 元素中单击 <option> 元素. 在正常情况下, IE驱动程序根据元素的位置和大小计算单击位置, 通常由JavaScript getBoundingClientRect() 方法返回. 但是, 对于 <option> 元素, getBoundingClientRect() 返回一个位置为零、大小为零的矩形. IE驱动程序通过使用 click() 来处理这一场景, 它本质上设置了元素 .selected 的属性, 并在JavaScript中模拟 onChange 事件. 但是, 这意味着如果 <select> 元素的 onChange 事件 包含调用 alert()confirm() 或 prompt()的JavaScript代码, 则调用WebElement的 click() 方法将挂起, 直到手动取消模式对话框. 对于此行为, 仅使用WebDriver代码没有已知的解决方法.
  • 类似地, 在某些情况下, 通过WebElement的submit()方法提交HTML表单 可能会产生相同的效果. 如果驱动程序调用表单上的JavaScriptsubmit()函数, 并且有一个onSubmit事件处理程序调用 JavaScript alert()confirm() 或 prompt()函数, 则可能发生这种情况.
  • 该限制被记录为3508号问题 (谷歌代码).

设置选项

ie_options = Options()
ie_options.ignore_protected_mode_settings = True
ie_options.ignore_zoom_level = True
ie_options.require_window_focus = True
driver = webdriver.Ie(options=ie_options)
  • ignore_protected_mode_settings:忽略保护模式设置
  • ignore_zoom_level:忽略缩放级别
  • require_window_focus:要求窗囗获得焦点

打开浏览器

# 创建浏览器实例对象
driver = webdriver.Chrome()
# 浏览器最大化
driver.maximize_window()
# 打开网址
driver.get("https://www.67an.cn")
# 关闭当前窗口
driver.close()
# 关闭浏览器selenium4执行结束自动关闭(IE不适用)
driver.quit()

HTML

h、p、span标签

a、img标签

ul、li标签

div标签

form表单

iframe内联框架

css

js

ID定位 By.ID

# send_keys输入内容
driver.find_element(By.ID,"kw").send_keys('七安')
# click点击
driver.find_element(By.ID,"su").click()

类名定位 By.CLASS_NAME

#获取class属性的第一个元素
driver.find_element(By.CLASS_NAME,'list-goto')
#获取class属性的所有元素
driver.find_elements(By.CLASS_NAME,'list-goto')[4].click()  
for ele in driver.find_elements(By.CLASS_NAME, 'footer-widget-links'):  
    print(ele.text)

标签名定位 By.TAG_NAME

driver.find_element(By.TAG_NAME,"input")
document.getElementsByTagName("input")

名称定位 By.NAME

#只获取属性的第一个元素
driver.find_element(By.NAME,'wd')
#获取属性的所有元素
driver.find_elements(By.NAME,'wd')

链接文本定位 By.LINK_TEXT

driver.find_element(By.LINK_TEXT,'新闻')

链接部分文本定位 By.PARTIAL_LINK_TEXT

driver.find_element(By.PARTIAL_LINK_TEXT,'闻')

css_selector定位 By.CSS_SELECTOR

选择器格式示例示例说明
标签选择器html标签input选择所有元素
ID选择器#id属性值#kw选择所有id='kw'的元素
类选择器.class属性值.nav-search-input选择所有class='nav-search-input'的元素
属性选择器1[属性名][name="wd"]选择所有name等于"wd"的元素
组合选择器标签加属性描述input.s_ipt选择所有class='_ipt'的元素
父子关系元素1>元素2div>a选择所有父级是的元素
后代关系元素1 元素2div a选择中的所有元素
第一子元素:first-childa:first-child选择所有元素且该元素是其父级的第一个元素
最后一个元素:last-childa:last-child选择所有元素且该元素是其父级的最后一个元素
顺序选择器:nth-child(n)a:nth-child(2)选择所有元素且该元素是其父级的第二个子元素

xpath定位 By.XPATH

说明举例
从根节点开始选取(绝对路径)/html/div/
从任意节点开始选取(相对路径)//div,列举出所有div标签
选取当前节点的父节点//input/.. 会选取 input 的父节点
选取属性,或者根据属性选取
使用id属性定位//div[@id='id_value']
使用class属性定位//a[@class="mnav"]
使用name属性定位//div[@name='wd']
多个属性定位//input[@name="wd" and @class="s_ipt"]
第n个元素,使用index定位//div[@id="s-top-left"]/a[3]
最后一个元素//a[@class="mnav"][last()]
属性包含某字段//div[contains(@title,'text')]
属性以某字段开头//div[starts-with(@title,'text')]
属性以某字段结尾//div[ends-with(@title,'text')]
文本包含//a[contains(text(),"网盘")]
文本等于//span[text() = "菜单"]
同级弟弟元素//div[@id=='id']/following-sibling::div
同级哥哥元素//div[@id=='id']/preceding-sibling::div

使用Chrome(谷歌浏览器)定位

使用PyCharm定位

Select 选择器

Select类的常用方法:

select_by_index(index):通过索引选择下拉列表中的选项。索引从0开始。

select_by_value(value):通过选项的value属性选择下拉列表中的选项。

select_by_visible_text(text):通过选项的可见文本选择下拉列表中的选项。

options:获取所有选项的列表,每个选项是一个WebElement对象。

all_selected_options:获取所有已选中的选项,返回一个列表,每个选项是一个WebElement对象。

first_selected_option:获取第一个已选中的选项,返回一个WebElement对象。

driver.get('https://sahitest.com/demo/selectTest.htm')
select = Select(driver.find_element_by_id("s1"))
#根据index下标进行选择,从0开始
select.select_by_index(1)
time.sleep(2)
# 根据value进行定位
select.select_by_value("48")
time.sleep(2)
# 根据展示的内容定位
select.select_by_visible_text("Home Phone")

frame框架

frame包括(frameset标签、frame标签、iframe标签)

iframe 是个内联框架,是在页面里生成个内部框架。可以嵌套多个html页面。大多网页使用的是iframe框架。

切换iframe的方法为:driver.switch_to.frame(),frame()中参数可以为id,name或者index,也可以为iframe元素

driver.get('https://sahitest.com/demo/iframesTest.htm')
driver.find_element(By.ID, 'checkRecord').clear()
driver.find_element(By.ID, 'checkRecord').send_keys("6666")
time.sleep(2)
#切换至第一个iframe
driver.switch_to.frame(0)
driver.find_element(By.ID, 'open-self').click()
driver.switch_to.frame("iframe2")
# 切换到上一级
driver.switch_to.parent_frame()
# 切换到主界面
driver.switch_to.default_content()

三种弹框

Alert弹框演示

driver.implicitly_wait(10)
driver.get('https://sahitest.com/demo/alertTest.htm')
# 根据name定位并点击
driver.find_element(By.NAME, 'b1').click()
# 使用alert.text打印确定按钮的文字
print(driver.switch_to.alert.text)
time.sleep(2)
# 使用accept进行确认,不使用click函数
driver.switch_to.alert.accept()

Confirm弹框演示

driver.implicitly_wait(10)
driver.get('https://sahitest.com/demo/confirmTest.htm')
driver.find_element(By.NAME, 'b1').click()
print(driver.switch_to.alert.text)
time.sleep(2)
# 使用accept进行确认,不使用click函数
driver.switch_to.alert.accept()
# 使用dismiss进行取消操作
# driver.switch_to.alert.dismiss()
time.sleep(2)

Prompt弹框演示

driver.implicitly_wait(10)
driver.get('https://sahitest.com/demo/promptTest.htm')
driver.find_element(By.NAME, 'b1').click()
time.sleep(2)
# alert基础上使用send_keys输入内容
driver.switch_to.alert.send_keys("七安")
driver.switch_to.alert.accept()

# 也可以用下面语法
# 先把弹框获取为一个对象
driver.implicitly_wait(10)
driver.get('http://sahitest.com/demo/promptTest.htm')
driver.find_element(By.NAME, 'b1').click()
time.sleep(2)
alert = driver.switch_to.alert
alert.send_keys("七安")
alert.accept()
time.sleep(2)
driver.close()

selenium的等待机制

影响元素加载的因素

  • 计算机的性能,cpu,内存执行速度,一定程度上影响页面加载速度
  • 服务器的性能,接口的响应速度,带宽一定程度上影响资源的传输时间
  • 浏览器的性能,不同浏览器针对不同的网页,加载速度有区别
  • 网络因素,本地网络的好差一定程度影响页面的加载速度(墙或者不墙)

等待机制包含强制等待、隐性等待、显性等待

强制等待 time.sleep(3)

优点:语法简单,粗暴。方便调试

缺点:用例中使用太多的sleep,影响执行速度。而且具体设置多少时间不好把握

import time
# 当前进程暂停3秒钟
time.sleep(3)

隐性等待 implicitly_wait()

会在约定好的时间内持续检测元素,一般找到目标元素就执行后续的操作,如果超过了约定时间未找到就报错

隐性等待需要当前页面元素全部加载完成才会执行下一步

driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(5)
driver.get('http://www.baidu.com')
# 5秒内没找到就报错
driver.find_element(By.ID, 'kw1').send_keys("666")
time.sleep(2)

显性等待 WebDriverWait

显性等待更适合UI自动化,它比隐性等待更灵活,提供多种方法供使用

WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时后返回的信息)

locate = (By.XPATH,'/html/body/table/tbody/tr[156]/td[2]/a')
# element = WebDriverWait(driver,3).until(EC.visibility_of_element_located(locate),"找不到这个元素")
element = WebDriverWait(driver, 3).until(EC.url_contains("registry.npmmirror.com1"),"找不到这个元素")
# element.click()
判断语法描述
title_is(title)判断页面title和预期title是否一致
title_contains(title)判断页面title是否包含预期title是否一致
presence_of_element_located(locator)用于检查某个元素是否出现,元素不一定可见
presence_of_all_elements_located(locator,locator2)用于检查所有元素是否出现
url_contains(url)传入url,包含时返回true
url_matches(url)传入url,包含时返回true
url_to_be(url)传入正则表达式
url_changes(url)传url,不匹配时返回true
visibility_of_element_located(locator)参数是 locator,判断元素是否在页面DOM 中,如果在并且可见返回 True,否则返回 False
visibility_of(WebElement)参数是元素,判断元表是否在页面 DOM 中,如果在并且可见返回 True,否则返回 False
visibility_of_any_elements_located(locator)参数是locator,根据定位器至少应该能定位到一个可见元素,返回值是列表,如果定位不到则报错
visibility_of_all_elements_located(locator)参数是locator,判断根据定位器找到的所有符合条件的元素是否都是可见素,如果都是的话返回值是列表,定位不到或者不全是的话则报错
invisibility_of_element_located(locator)判断这个 locator的元素是否不存在或者不可见,满足条件返回 True,否则返回 False
invisibility_of_element(locator or element)判断这个 locator 或者 element 是否不存在或者不可见,满足条件返回 True,否则返回 False
frame_to_be_available_and_switch_to_it(frame_locator)判断frame_ locator 是否存在,存在的话切换到这个frame中,成功返回 True。不存在的话返回 False
text_to_be_present_in_element(locator, text)判断text 是否出现在元素中,两个参数,返回一个布尔值
text_to_be_present_in_element_value(locator, text)判断text 是否出现在元素的属性value 中,两个参数,返回一个布尔值
element_to_be_clickable(locator)判断这个元素是否可见并且可单击,满足条件返回 True,否则返回 False
element_to_be_selected(element)判断元素是否被选中,传入的参数是element,如果被选中,那么返回值是这个元素
alert_is_present(driver)判断是否有alert,有切换到该alert,没有返回False

浏览器操作

打开、关闭、刷新浏览器

# 打开Chrome浏览器
driver = webdriver.Chrome()
# 关闭当前窗口
driver.close()
# 退出浏览器进程
driver.quit()
# 刷新浏览器
driver.refresh()

切换窗口

# 获取当前窗口句柄
driver.current_window_handle
# 获取所有窗口句柄
driver.window_handles
# 切换窗口
driver.switch_to.window()
# 打开一个标签页
driver.switch_to.new_window('tab')

driver.find_element(By.CSS_SELECTOR, 'a[href="http://news.baidu.com"]').click()
# 打印当前句柄
current_handle = driver.current_window_handle
# 循环切换,先切换第一个窗口,再切换第二个窗口
# for handle in driver.window_handles:
#     if handle != current_handle:
#         driver.switch_to.window(handle)
#         print(handle)
#         time.sleep(2)
# all_handles = driver.window_handles
# # 根据下标去取
# driver.switch_to.window(all_handles[1])
# driver.find_element(By.CSS_SELECTOR, 'a[href="//help.baidu.com"]').click()
# 打开新标签
driver.switch_to.new_window("tab")
driver.get("https://www.bilibili.com")

浏览器窗口最大化,最小化

  • maximize_window() 窗口最大化
  • minimize_window() 窗口最小化
driver = webdriver.Chrome()
driver.get('https://www.bilibili.com/')
driver.maximize_window()  # 窗口最大化
time.sleep(2)
driver.minimize_window()  # 窗口最小化
time.sleep(2)
driver.close()

获取浏览器窗口大小,设置窗口大小

  • get_window_size() # 获取浏览器窗口大小
  • set_window_size(width=1000, height=500) # 设置浏览器窗口
driver = webdriver.Chrome()
driver.get('https://www.bilibili.com/')
size = driver.get_window_size() # 获取浏览器窗口大小 {'width': 1200, 'height': 829}
print(size)
driver.set_window_size(width=1000, height=500) # 设置浏览器窗口
time.sleep(2)
driver.close()

获取页面title,url,源代码

  • driver.title 页面title
  • driver.current_url 页面url地址
  • driver.page_source 页面源代码
driver = webdriver.Chrome()
driver.get('https://www.bilibili.com/')
title = driver.title # 页面title
url = driver.current_url # 页面url地址
page = driver.page_source # 页面源代码

获取元素的相关信息

获取元素的信息可以为执行用例后进行断言或者作为前置条件

  • 获取元素的文本
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.baidu.com/")
element1 = driver.find_element(By.CSS_SELECTOR, 'a[href="http://news.baidu.com"]')
element2 = driver.find_element(By.ID, 'su')
element3 = driver.find_element(By.XPATH, '//span[@class="title-content-title"]')
# a标签
print(element1.text)
# button标签要使用accessible_name
print(element2.accessible_name)
# span标签
print(element3.text)
  • 获取元素是否可用
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://sahitest.com/demo/clicks.htm")
element3 = driver.find_element(By.XPATH, '/html/body/form/input[5]')
# disabled返回False,否则返回True
print(element3.is_enabled())
  • 判断元素是否选中
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://sahitest.com/demo/clicks.htm")
element2 = driver.find_element(By.XPATH, '/html/body/form/input[6]')
# 没选中为False
print(element2.is_selected())
element2.click()
# 选中为True
print(element2.is_selected())

网页的前进和后退

  • driver.back() 后退
  • driver.forward() 前进

鼠标操作

selenium提供模拟鼠标操作的功能,常见的鼠标操作有:单击、右键点击、双击、移动鼠标、拖拽鼠标

selenium工具中全局鼠标操作语法如下:

第1步:初始化ActionChians类(动作链条): actions = ActionChains(driver)

第2步:找到要操作的元素: find_element

第3步:调用鼠标操作方法: actions.move_to_element(element)

第4步:执行鼠标操作方法: actions.perform()

具体用法:ActionChains(driver).click(element).perform()

初始化ActionChians→找到对应元素element→调用鼠标操作方法click()→执行鼠标操作方法perform()

鼠标操作关键字解释
单击click单击鼠标左键在元素上。
双击double_click双击鼠标左键在元素上。
右击context_click单击鼠标右键在元素上。
鼠标悬停move_to_element将鼠标悬停在指定的元素上。
拖放drag_and_drop将一个元素拖放到另一个元素上。
拖放到坐标点drag_and_drop_by_offset将一个元素拖放到指定的坐标点上。
移动到坐标点move_by_offset将鼠标移动到指定的坐标点上。
鼠标按下click_and_hold按下鼠标左键在元素上,但不释放。
鼠标释放release释放鼠标左键,用于与click_and_hold一起使用。
双击并按住double_click_and_hold双击鼠标左键在元素上并按住,用于与release一起使用。

JavaScript应用

Selenium提供了execute_script方法,用来执行JavaScript,从而完成一些特殊的操作

操作页面元素

driver.get('https://www.baidu.com/')
driver.execute_script('document.getElementById("kw").value="selenium"')
driver.execute_script('document.getElementById("su").click()')

操作滚动条

driver.get('https://news.baidu.com/')
# 向下滑动200像素
driver.execute_script("window.scrollTo(0,200)")
time.sleep(2)
# 滑动到顶部
driver.execute_script("window.scrollTo(0,0)")
time.sleep(2)
#滑动到底部
driver.execute_script("window.scrollTo(0,document.body.scrollHeight)")

JS处理元素不可见解决方式

element = driver.find_element_by_xpath("表达式")
driver.execute_script("arguments[0].click();", element)
element = driver.find_element_by_xpath("表达式")
driver.execute_script("arguments[0].scrollIntoView();", element)
element = driver.find_element_by_xpath("表达式")
driver.execute_script("arguments[0].scrollIntoViewIfNeeded(true);", element)
作者设置了回复可见