当前位置: 首页 > news >正文

软件测试——自动化测试常见函数

在上一篇文章软件测试——自动化测试概念篇-CSDN博客中,给大家演示了一下自动化程序,而本篇文章会带大家详细学习selenium库。

selenium库是python官方的库,里面包含了很多操控浏览器的函数。

本节重点

  • 元素定位
  • 操作测试对象
  • 窗口
  • 等待
  • 导航
  • 弹窗
  • 文件上传
  • 浏览器参数

0.自动化程序

上篇文章中的自动化程序代码如下:

#编写自动化脚本,具体步骤
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager# #1.打开浏览器---驱动管理
#下载和安装Edge浏览器对应的驱动
EdgeIns=EdgeChromiumDriverManager().install()
#创建浏览器驱动对象,打开浏览器
driver=webdriver.Edge(service=Service(EdgeIns))
time.sleep(2)
#2.输入百度网址:https://www.baidu.com(网址一定要写完整,不要写成www.baidu.com)
driver.get("https://www.baidu.com")
time.sleep(2)
#3.找到百度输入框,输入关键词“迪丽热巴”
driver.find_element(By.CSS_SELECTOR, "#kw").send_keys("迪丽热巴")
time.sleep(2)
#4.点击“百度一下”
driver.find_element(By.CSS_SELECTOR, "#su").click()
time.sleep(2)
#5.关闭浏览器
driver.quit()

1.元素定位

首先,我们要了解在一个web网页中包含很多的元素(以edge浏览器做演示)

我们可以点击键盘上的F12或者按shift+ctrl+i进入开发者工具,如下图所示(如果第一次打开不是这样的,就点击右上角的元素按钮)

然后我们需要点击开发者模式左上角的小箭头,让他变成黄色。

当打开这个后,我们鼠标放在左边的百度界面时,对应的区域就会变成蓝色,此时这个小区域就称之为元素。

对应web自动化测试的操作核心是能够找到页面的元素,然后才能对元素进行具体的操作。常见的元素定位方式非常多,如id,classname,tagname,xpath,cssSelector。常用的主要有cssSelector和xpath。

比如上一篇文章中,我们写的web自动化程序会在百度的输入框内输入“迪丽热巴”,就是因为能成功定位到输入框元素;能自动点击“百度一下”,也是因为可以定位到对应的元素。

代码中的#kw和#se分别代表的是输入框和“百度一下”按钮。

怎么证明呢?

点击百度的输入框后,开发者工具会自动跳转到其对应的代码。

然后鼠标右击黄色代码部分,点击复制,然后选择复制方式,这里选择复制selector。

而复制的内容就是:#kw,也就是搜索框对应的选择器定位方式,我们再回过头来看这个代码就很好理解了,后面的send_keys的意思就是输入文本,即“迪丽热巴”。

而“百度一下”按钮也是同理,click的意思是点击按钮。

1.1 cssSelector

cssSelector是一个选择器,选择器的功能:选中页面中指定的标签元素

选择器的种类分为基础选择器和复合选择器,常见的元素定位方式可以通过id选择器和子类选择器来进行定位。

在前面也介绍过了,可以通过cssSelector选择器来定位页面元素,我们使用的函数是find_element,而selenium库中还有一个find_elements函数,这个函数和find_element的区别在于他可以查找多个元素。

假如我们使用ctrl+f查找红框内的让元素,可以发现最终在整个页面中查找到了10个。

使用find_element只能查找其中一个,而使用find_elements则可以全部查找。

我们在最后打印以下查找的每个元素的文本信息,可以发现他可以对应到百度页面中的文本

而在这十条文本中,我们随便打开一条看一下他的元素定位,步骤还是和前面一样,选中文本,然后跳转到对应代码,鼠标右键选择复制,然后复制到selector。

  • 最终复制出来的就是:#hotsearch-content-wrapper > li:nth-child(1) > a。
  • 而我们刚刚搜索的是:#hotsearch-content-wrapper > li。

所以使用find_elements函数可以帮我们找到多个元素。

实际上刚刚的那十个文本处于同一个列表中,在前端中ul表示列表,而li标签表示的是列表中的每一个内容。

我们可以发现在第一行ul标签中有一个id="hostsearch-content-wrapper",其中的id表示他是一个id选择器,再来看我们刚刚查找的其中一个的元素定位:#hotsearch-content-wrapper > li:nth-child(1) > a。其中的li:表示的是子类选择器,他要找的是第一个li标签。

1.2 xpath

XML路径语言,不仅可以在XML文件中查找信息,还可以在HTML中选取节点。xpath使用路径表达式来选择xml文档中的节点。

在xpath语法中:

  • 1.获取HTML页面所有的节点: //*   
  • 2.获取HTML页面指定结点://[指定结点]   (如://ul表示获取HTML页面所有的ul节点)
  • 3.获取一个结点中的子节点:/   (如://span/input表示input是span的子节点)
  • 4.获取一个结点的父结点:..   (如://input/...表示获取input结点的父结点)
  • 5.实现结点属性的匹配:[@.....]   (如://*[@id='kw']表示匹配HTML页面中id属性为kw的结点)
  • 6.使用索引的方式获取对应内容,索引从1开始。   (如百度首页://div/ul/li[3]表示定位到第三个百度热搜标签)

我们再以百度的输入框为例,选择复制方式为复制XPath。

百度输入框Xpath元素信息为://*[@id="kw"]

  • 其中的//*表示获取HTML页面所有的结点
  • [@id="kw"]表示获取id属性为kw的结点

“百度一下”按钮的id属性为su,能否通过//*[@id='su']找到“百度一下”呢?

我们打开开发者工具,使用ctrl+f进行搜索,输入//*[@id='su']。

按下回车后,可以发现,左边的“百度一下”按钮变成蓝色了,说明我们的搜索成功找到了。

通过这种方式,我们可以查找到页面中的所有元素。

如何理解//*[@id="hotsearch-content-wrapper"]/li[1]/a/span[2]这个xpath

这个xpath其实是前面提到过的li标签,在cssSelector中我们说他是一个子类选择器。

那么在xpath中如何理解他的元素信息://*[@id="hotsearch-content-wrapper"]/li[1]/a/span[2]

其中//*[@id="hotsearch-content-wrapper"]表示的是ul标签。

2.操作测试对象

获取到了页面的元素之后,接下来就是要对元素进行操作了。常见的操作有点击、提交、输入、清除、获取文本。


2.1 点击/提交对象

click()

我们在前一篇文章中写过的自动化程序中就有click函数,如下:

其中先找到百度的输入框然后输入"迪丽热巴",然后再找到"百度一下"按钮,并点击该对象成功查找目标信息。

这里的逻辑非常简单,我们找到"百度一下"按钮,并点击该对象的代码写成了一行,也可以写成两步,先查找再点击。

最终的效果是一样的。

点击是模拟鼠标的动作,也就是说页面中的任何一个元素都可以点击。

比如说我们现在要点击该新闻链接:

我们通过cssSelecor的方式查找该条新闻,代码如下:

运行程序,在打开百度页面的2秒后,果然跳转到了对应的链接中

所以说click的功能是非常强大的。

2.2 模拟按键输入

send_keys("")

还是以前面写的自动化程序为例,我们找到了百度的输入框,并调用了send_keys在该输入框内输入了文本。

同样的,这一行代码也可以写成两行,先查找输入框再输入文本。

输入是模拟键盘的动作,也就是说键盘可以输入的内容都可以填写上去。​​​​​​

比如键盘输入以下内容:

最终可以成功搜索

2.3 清楚文本信息

连续的send_keys会将多次输入的内容拼接在一起,要想重新输入,需要使用clear()

比如说我们想搜索"Linux"和"Python"这两个内容,如果按照下面的这种写法,那么第二次搜索的不是Python而是LinuxPython,第二次的内容直接拼接到第一次。

要想解决这个办法,就要在搜索玩之后使用clear进行清除。

运行后,首先会输入Linux

过了2秒后,会清除文本。

又过了2秒后,输入Python。

2.4 获取文本信息

如果判断获取到的元素对应的文本是否符合预期呢?获取元素对应的文本并打印一下。

获取文本信息: text,会返回一个字符串

就以下面的例子为例,我们想获得该新闻的文本信息。

代码如下:

运行后:

成功获取到了文本。

为什么我们肉眼能观察到文本是否有问题,还需要通过代码来判断呢?

别忘了我们介绍的内容是什么:自动化,自动化的目的就是为了代替人的工作,实际工作中,我们可以通过断言的方式判断目标文本和实际读到的文本是否一样,如果不一样就会出现错误。

比如我们输入的时候少了一个汉字“费”

最终可以通过断言找出来

如何获得“百度一下”按钮的文本信息?

我们还是按之前的步骤来试一下,编写如下代码:

但是最终运行的结果却是报错,并且我们的print也没有打印出任何信息。

这就说明了text为空,没有返回任何文本信息。

我们要了解一个概念:元素属性值 != 文本信息

这里的"百度一下"其实是元素的属性值,有属性值肯定就有属性。

那么到底什么是属性和属性值呢,我们再来查看“百度一下”按钮对应的代码,其中有type,id,vale和class这些就是该元素对应的属性,等号后面的就是属性值(key-value形式的键值对)

所以我们想获取“百度一下”就不能通过获取文本的方式了,需要通过获取属性值。

get_attribute(属性)

使用get_attribute()函数就能获取对应属性的属性值。

最终运行没有报错,并且成功打印了“百度一下”。

如何区分属性值和文本

  • 文本是直接写在标签内部的,如上图的<span>和</span>中间。
  • 属性值以键值对的方式,如上图vale=“百度一下”。

2.5 获取当前页面标题

页面的标题就在页面的左上角,如百度的标题就是“百度一下,你就知道”

通过title = driver.title获取

 title = driver.title

代码如下:

成功获取页面标题

2.6 获取当前页面URL

和获取页面标题的使用方法几乎是一样的,使用url = driver.current_url

url = driver.current_url

代码如下:

运行结果:

获取页面标题和获取页面的url的使用场景

页面元素可点击跳转的情况下,用来检测跳转的结果是否是正确的。

比如说,我想点击视频,我不知道点击后能否成功跳转到目标地址。

那么就可以获取点击后的url和标题与目标地址和标题进行对比,如果是一致的说明跳转就是正确的。

3.窗口

在讲解窗口之前,我们先来做一个练习,点击百度首页的图片,跳转到目标页面

代码如下:

运行结果:

最终能跳转到新的页面,并且跳转后的页面的url和原url是不一样的,但是打印的结果为什么还是和页面跳转之前的结果一样。

我们查找一个新页面中有的元素,但旧页面没有的来观察一下,以查找“热门搜索”为例

代码:

运行结果:

可以看到报错了,并且报错信息是:NoSuchElementException: Message: no such element: Unable to locate element,说明我们要查找的元素不存在。

也就是说虽然显示跳转到了新页面,但是我们的驱动对象driver还停留在旧的页面中

我们一开始创建的驱动对象在https://baidu.com这个标签页中,但是当跳转到新页面时,会出现多个标签页,而我们的driver还是指向的第一个标签页。

打开⼀个新的页面之后获取到的title和URL仍然还是前一个页面的?

当我们手工测试的时候,我们可以通过眼睛来判断当前的窗口是什么,但对于程序来说它是不知道当前最新的窗口应该是哪⼀个。对于程序来说它怎么来识别每⼀个窗口呢?每个浏览器窗口都有⼀个唯一的属性句柄(handle)来表示,我们就可以通过句柄来切换不同的窗口。

3.1 切换窗口

1)获取当前页面句柄:

driver.current_window_handle

3)获取所有页面句柄:

driver.window_handles

3)切换当前句柄为最新页面:

curWindow = driver.current_window_handle
allWindows = driver.window_handlesfor window in allWindows:if window != curWindow:driver.switch_to.window(window)

注意:执行了 driver.close() 之前需要切换到未被关闭的窗口

也就是说遍历所有的句柄,如果发现不是当前页的句柄就切换,这样就能保证可以切换成最新页的句柄了。

我们更新一下代码。

运行结果:

成功显示了新窗口的地址,并且find_element也查找成功。

如果有多个标签页怎么切换

我们切换标签页时的代码如下:

curWindow = driver.current_window_handle
allWindows = driver.window_handlesfor window in allWindows:if window != curWindow:driver.switch_to.window(window)

如果我们打开了3个标签页,这种方法就没法很好定位到第二个标签页或者是第三个标签页了。

  • 实际上打开多个标签页的情况不常见,通常情况下只会打开两个标签页,实现标签页的切换测试
  • 更多的情况下,我们可以直接输入对应页面的url在当前标签下进行测试。(直接将当前页面切换成目标页面通过driver.get()实现)

例如在百度首页搜索图片页面,则直接输入目标url

搜索后不会出现新的窗口

需要切换窗口的前提是:页面跳转产生了新的标签页

我们来看下面这种场景

我们点击百度首页的“文库”

然后就能看到该页面,注意此时页面的标题和url

我们再点击左边的智能助手

可以看到页面发生了跳转,但是没有产生新的标签页,新页面直接覆盖掉了原页面,我们通过编写代码来测试一下。

运行结果:

在页面切换后,我们没有切换窗口,而是直接测试跳转结果,结果表明跳转成功,并且find_element也查找成功。

总结:页面跳转产生了新的标签页时才需要进行窗口切换

3.2 窗口设置大小

1)窗口最大化

driver.maximize_window()

2)窗口最小化

driver.minimize_window()

3)窗口全屏

driver.fullscreen_window()

4)手动设置窗口大小

driver.set_window_size(1024,768)


我们在使用浏览器时,经常会用到窗口最大化以及窗口最小化,这个按钮通常在浏览器右上角位置。窗口全屏可以按F11进入。

接下来我们通过代码的方式来实现上面功能。

运行代码后

第一个2秒会运行窗口最大化

第二个2秒会进入最小化,但是我们无法观察到

第三个2秒会进入全屏

第四个2秒会进入手动设置的大小

3.3 屏幕截图

我们的自动化脚本⼀般部署在机器上自动的去运行,如果出现了报错,仅仅通过终端的错误提示给到的有用信息是一定的,可以通过抓拍来记录当时的错误场景,能更好的定位问题并解决问题

driver.save_screenshot('图片名称')

save_screenshot的参数是屏幕截屏保存下来的图片名称(路径+名字)

  • 比如('test.png')表示:保存在脚本文件所在路径下,图片名称为test.png
  • ('C:/images/image.png')表示:保存在C盘的images目录下,图片名称为image.png

我们在运行下列代码后

可以看到项目中多了一个文件

该文件就是我们刚刚打开的百度首页

如果我们不想创建在当前路径下,我们可以创建一个文件夹images,然后将所有的截屏保存在该文件夹中。

sava_screenshot的参数就可以修改成指定路径。

最终也是成功显示出来了


指定文件名后,多次截屏会覆盖掉旧图,如何保证每次生成的都是唯一的

当我们指定好了文件名为test.png后,第一次截图没有问题,但是在后面的截图中,会覆盖掉上一次的图,所以我们需要修改一下代码使每次生成的图片名字都不一样。

最好的名称是以当前时间来命名,这样每个名称都不一样,并且还能帮助我们定位错误的时间,去查看对应的错误日志。

python中有一个datetime.now()函数可以打印当前的时间,但是这个函数打印出来的结果中包含空格,而文件名中是不能有空格的。

所以我们让他以指定形式打印。

再给文件名添加一下前缀和后缀。

最终代码如下:

此时我们运行三次程序,就会生成3个不同名称的图片。

3.4 关闭窗口

  • driver.close()表示:退出一个窗口
  • driver.quit()表示:退出浏览器,会关闭所有的标签页

注意:driver.close()退出的是driver指向的标签页。

比如下面代码:

代码的逻辑就是,打开百度首页面,点击"图片"跳转到新的标签页并切换句柄,然后退出当前窗口,最后退出整个浏览器。

在退出窗口后

如果在代码中没有切换句柄,那么关闭的就是百度首页面了。

4.弹窗

弹窗我们并不模式,比如当我们在网页中登陆时,会出现一个弹窗

此时弹窗中的元素都是可以定位到的。

我们今天要学的弹窗是在页面中找不到任何元素的,这种情况如何处理。

假如说有当前这个页面,点击左边的See_an_example_alert后会出现一个弹窗

我们页面右上角的小箭头打开后,可以定位左边的元素

但是当出现弹窗后,我们将鼠标放在弹窗位置,此时无法定位到左边的元素了。

既然无法定位到弹窗,我们就无法通过代码去关闭他。

我们将上面问题写成代码,如下:

启动程序后,出现如下页面:

也就是说运行到find_element时会出现一个弹窗,如果此时我们不去管他,再次点击See_an_example_alert会发生什么

最后出现了报错,错误原因是UnexpectedAlertPresentException,表示未期望的弹窗出现了。

如果我们不解决这个弹窗,我们就不能定位其他元素。

具体步骤:

  • 1.切换到弹窗
  • 2.关闭弹窗(点击确认/取消)

不同的弹窗类型,具体的操作方法不同,但是他们都有共同特点:

  • 1.页面上定位不到弹窗元素
  • 2.出现了弹窗后,页面其他元素都无法定位了

4.1 警告弹窗

  • 警告弹窗中只有一个确认按钮
//切换到弹窗(返回一个弹窗对象)
alert = driver.switchTo.alert
//确认
alert.accept()
//取消
alert.dismiss()

注意:

  • 对于警告弹窗,accept()和dismiss()都可以使用,这两个函数都是作用在同一个按钮上的

下面我们编写代码,将上面的弹窗关闭。

程序运行后,会出现一个警告弹窗,但是2秒过后就会关闭该弹窗。

我们将accept()切换成dismiss(),最终的结果一模一样,验证了警告弹窗中accept()和dismiss()作用于同一个按钮的结论。

4.2 确认弹窗

确认弹窗和警告弹窗比较像。

  • 确认弹窗中包含一个确认键和一个取消键
//切换到弹窗(返回一个弹窗对象)
alert = driver.switchTo.alert
//确认
alert.accept()
//取消
alert.dismiss()

注意:

  • 对于确认弹窗,accept()作用于确认键,dismiss()作用于取消键

假设现在有这样一个页面,点击"Display a confirm box"就会出现一个确认弹窗

点击“确定”会显示“You pressed OK!”

点击“取消”会显示“You pressed Cancel!”

现在我们编写代码,分别使用accept()和dismiss()观察现象:

运行程序:

调用accept()时,指向了“确定”按钮,最终显示出了“You pressed OK!”

现在我们修改一下代码,改成dismiss()

运行程序:

结果和我们预期的一模一样。

总结:

  • 警告弹窗只包含一个确认键,而确认弹窗包含一个确认键一个取消键
  • 对于警告弹窗,accept()和dismiss()作用在同一个按钮(确认键)
  • 对于确认弹窗,accept()和dismiss()作用在不同按钮上(accept()作用于确认键,dismiss()作用于取消键)

4.3 提示弹窗

提示弹窗比确认弹窗多了一个文本框。

#切换弹窗(返回一个弹窗对象)
alert = driver.switchTo.alert
#向文本框中输入文本
alert.send_keys("hello")
#确认
alert.accept()
#取消
alert.dismiss()

注意:

  • send_keys()用于向提示弹窗中的文本框输入内容
  • accept()用于点击提示弹窗中的“确定”键
  • dismiss()用于点击提示弹窗中的“取消”键

现在有这样一个网页,点击左边的“请点击”按钮后,就会出现一个提示弹窗。

当向文本框输入内容并点击确定时,就会将输入的内容显示出来。

而点击取消,或者文本框为空时点击确认都会直接关闭提示弹窗。

现在我们编写代码来测试一下

先测试输入文本+确认

运行结果:

再测试一下输入文本+取消

两次的运行结果都是符合预期的。

5. 等待

通常代码执行的速度比页面渲染的速度要快,可能会出现因为渲染过慢出现的自动化误报问题。

例如,我们前面写过这样的代码:

如果我们在第四步之后添加一个查找新页面中的某个元素的代码,就以搜索“早年经历”为例。

代码如下:

运行程序后:

直接报了下面这个错误,这个错误我们在前面也遇到过,他的意思是没找到对应的资源。

我们在这个代码之前添加一个sleep函数再次测试。

运行程序:

此时程序正常退出。

  • 之所以出现上面的原因,就是因为代码的速度非常快,而页面需要加载的资源较多,因此当脚本执行到该代码处时页面还没有渲染完成,因此无法找到该元素。
  • 当添加了time sleep(3)之后,页面已经在3秒内加载完成,此时就可以找到该元素了。

5.1 强制等待

强制等待就是我们上面使用的方法:

#单位为秒
time.sleep()
  • 优点:使用简单,调试的时候比较有效
  • 缺点:影响运行效率,浪费大量的时间

当测试脚本数量较少时,添加强制等待消耗的时间较少,但是实际工作中的业务复杂,添加的自动化脚本非常多,则会浪费大量时间。

强制等待大多数情况下只适用于测试脚本时,当测试完毕之后会更换为隐式等待或者显示等待。

5.2 隐式等待

隐式等待是一种智能等待,他可以规定在查找元素时,在指定时间内不断查找元素。如果找到则代码继续执行,直到超时没找到元素才会报错。

#参数为秒
implicitly_wait()

我们将time.sleep()修改成implicitly_wait()

运行代码,可正常执行。

为什么implicitly_wait()放到了创建driver对象之后,而不是步骤5之前?

首先,我们要了解一些隐式转换的生命周期。

隐式等待作用域是整个脚本的所有元素。即只要driver对象没有被释放掉( driver.quit() ),隐式等待就⼀直生效。

也就是说只要有implicitly_wait()的代码,后面的所有查找都会等待指定秒数,如果指定秒数内能等到则继续执行代码,等不到才会报错

  • 优点:智能等待,作用于全局

5.3 显示等待

显示等待也是一种智能等待,在指定超时时间范围内只要满足操作的条件就会继续执行后续代码

WebDriverWait(driver,sec).until(functions)
  • driver:浏览器驱动对象
  • sec:需要等待的秒数
  • functions:涉及到selenium.support.ui.ExpectedConditions包下的ExpectedConditions类

示例:

from selenium.webdriver.support import expected_conditions as ECwait = WebDriverWait(driver,2)
wait.until(EC.invisibility_of_element((By.XPATH,'//[@id="2"]/div/div/div[3]/div[1]/div[1]/div')))

其中的invisibility_of_element(locator)函数用于检查元素的不可见性,同样也可以使用visibility_of_element(locator)来检查元素的可见性。

接下来我们将自动化程序的代码修改成显示等待

使用显示等待时,我们就不需要再调用find_element()了,直接使用visibility_of_element()来帮我们查找即可。

ExpectedConditions 预定义方法的一些示例:

  • 优点:显示等待是智能等待,可以自定义显示等待的条件,操作灵活,相较于隐式等待速度快(隐式等待中每一个查找元素都会等待)
  • 缺点:写法复杂

比如我们在前面说过三类弹窗,而弹窗不是页面中的元素,所以隐式等待无法等待弹窗,那么需要等待弹窗的场景下,我们就需要使用显示等待。

注意:隐式等待和显示等待不建议一起使用

我们来看下面这个代码,隐式等待和显示等待一起使用,记录起始时间,然后去页面中查找一个不存在的元素,既然不存在查找就会抛异常,所以我们将该异常捕获,并记录抛异常的时间,两个时间之差就是本次等待的时间。

隐式等待了15秒,显示等待15秒,那么最终等待多少秒?

运行程序:

最终等待的时间既不是显示等待也不是隐式等待,也不是两者之和。

总结:不要混合隐式和显式等待,可能会导致不可预测的等待时间。

强制等待可以任意配合隐式等待或者显示等待。

6. 浏览器导航

浏览器导航就是浏览器左上角的部分,包括后退,前进,刷新,跳转页面等功能。

6.1 跳转页面

driver.get("https://tool.lu/")

这个代码我们前面用到过很多次,就是使用浏览器上面的搜索框进行搜索。

我们现在再来重新理解上面的代码,第一句就是下载并安装Edge浏览器对应的驱动,第二句是打开浏览器,此时浏览器中不包含任何内容。

第三句就是通过上面的搜索框搜索对应的url。

6.2 浏览器的前进、后退、刷新

#后退
driver.back()
#前进
driver.forward()
#刷新
driver.refresh()

我们来编写如下代码进行测试

运行结果:

1)打开迪丽热巴页面

2)后退到百度首页

3)前进到迪丽热巴页面

4)刷新页面

7. 文件上传

点击文件上传的场景下会弹窗系统窗口,进行文件的选择。

点击“选择文件”按钮后,会跳出一个window下的界面

selenium无法识别非web的控件,上传文件窗口为系统自带,无法识别窗口元素。

但是可以使用send_keys来上传指定路径的文件,达到的效果是一样的,因为在选择文件页面时,会将选中文件的路径保存起来,当点击“上传”按钮时,文件才会被真正的上传,也就是说选择文件选的是文件的路径

那么我们只要将文件的路径上传上去,就能达到一样的效果。

运行程序后成功找到对应文件。


8. 浏览器参数设置

在写自动化程序中,我们会使用webdriver.Edge函数,该函数中我们只设置了service这一个选项,这个选项的意思是打开浏览器。

先来看一下Edge函数的声明

接下来,我们介绍一下options参数。

options

在创建浏览器对象时可以传递必要的参数,如浏览器的名字,打开方式,版本,加载策略等等。

这里主要介绍两个重要参数。

8.1 设置无头模式

  • 我们肉眼能看到浏览器被打开,看到浏览器中各种元素,如:文字,图片,视频等元素的方式叫做有头模式(我们前面演示的内容都是有头模式,能看到浏览器中的内容)。
  • 而无头模式即为程序在后端运行,我们看不到任何界面的表现。

自动化打开浏览器默认为有头模式,需要设置无头模式需要手动设置。

#创建浏览器参数配置对象
options = webdriver.ChromeOptions()
#设置无头模式,不添加默认为有头模式
options.add_argument("-headless")
#创建浏览器驱动对象,传递options参数
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),options=options)

代码:

当运行改代码时,并不会显示打开浏览器。

那浏览器到底有没有被打开?

我们用一段代码来验证一下。

运行结果:

所以浏览器是被打开了,只不过所有的操作我们都看不到了。

8.2 页面加载策略

当一个页面资源过大时,可能导致加载速度较慢,其中主要的页面框架已经加载完成了,还有一些视频/图片资源还在下载。

driver.get默认情况下等待所有资源加载完成之后才能继续往下执行代码,但是实际上主要的页面框架加载完成后我们就可以继续执行自动化代码了,若一直等待的话可能会造成页面加载超时、元素找不到的问题.......

浏览器左上角显示X就表示页面元素还没加载完。

#创建浏览器参数配置对象
options = webdriver.ChromeOptions()
#将浏览器加载方式设置为eager
options.page_load_strategy = 'eager'
#创建浏览器驱动对象,传递options参数
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),options=options)

页面加载方式主要有三种:

编写代码进行测试,以访问csdn主页面为例:

1)normal,即等待页面加载完毕

运行结果:

页面中所有元素都加载完毕之后,才会执行下一步代码(退出)

2)eager,页面主体框架出来后就执行下一步

运行结果:

当出现到该页面时(页面还没有完全加载完)就执行下一步代码了

 

3)none,完全不阻塞

运行结果:

甚至都没有看到他打开csdn就退出了

相关文章:

软件测试——自动化测试常见函数

在上一篇文章软件测试——自动化测试概念篇-CSDN博客中&#xff0c;给大家演示了一下自动化程序&#xff0c;而本篇文章会带大家详细学习selenium库。 selenium库是python官方的库&#xff0c;里面包含了很多操控浏览器的函数。 本节重点 元素定位操作测试对象窗口等待导航弹…...

SEO网站都用哪里的服务器

在当今这个信息爆炸的时代&#xff0c;网站的加载速度已经成为衡量其质量的重要指标之一。对于SEO网站来说&#xff0c;速度不仅关乎用户体验&#xff0c;更是影响搜索引擎排名的重要因素。在众多服务器提供商中&#xff0c;鼎峰新匯凭借其卓越的性能和优质的服务&#xff0c;成…...

【从零开始的LeetCode-算法】3233. 统计不是特殊数字的数字数量

给你两个 正整数 l 和 r。对于任何数字 x&#xff0c;x 的所有正因数&#xff08;除了 x 本身&#xff09;被称为 x 的 真因数。 如果一个数字恰好仅有两个 真因数&#xff0c;则称该数字为 特殊数字。例如&#xff1a; 数字 4 是 特殊数字&#xff0c;因为它的真因数为 1 和…...

shell脚本(五)

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…...

Windows中指定路径安装DockerDesktop

Windows中指定路径安装DockerDesktop 文章目录 Windows中指定路径安装DockerDesktop1. 先卸载干净(如果已安装过的话)2. 指定路径安装1. 新建需要安装的文件目录2. 指定路径安装 3. WSL子系统下载1. GitHub下载地址2. 指定版本直接下载 Widnows中直接安装docker desktop&#x…...

阿里云私服地址

1.解压apache-maven-3.6.1-bin 2.配置本地仓库&#xff1a;修改conf/dettings.xml中的<localReoisitory>为一个指定目录。56行 <localRepository>D:\apache-maven-3.6.1-bin\apache-maven-3.6.1\mvn_repo</localRepository> 3.配置阿里云私服&#xff1a;…...

深入探究 Vue 实例挂载过程与场景 —— 代码实例详解

Vue 实例挂载过程及使用场景分析 Vue 实例的挂载过程是 Vue 应用启动的核心,它决定了 Vue 组件如何与 DOM 进行绑定。在理解 Vue 实例挂载的过程后,我们可以根据不同的使用场景来选择合适的挂载方式。下面详细讲解 Vue 实例的挂载过程、常见使用场景,并通过实际项目示例进行…...

特征交叉-MaskNet文章总结代码实现

MaskNet 这个模型是微博21年提出的&#xff0c;23年twitter(X)开源的推荐系统排序模块使用的backbone结构。 核心思想是认为DNN为主的特征交叉是addictive&#xff0c;交叉效率不高&#xff1b;所以设计了一种multiplicatvie的特征交叉 如何设计muliplicative特征交叉呢&#x…...

【第八课】Rust中的函数与方法

目录 前言 函数指针 函数当作另一个函数的参数 函数当作另一个函数的返回值 闭包 方法 关联函数 总结 前言 在前面几课中&#xff0c;我们都或多或少的接触到了rust中的函数&#xff0c;rust中的函数和其他语言的并没有什么不同&#xff0c;简单的语法不在这篇文章中赘…...

PyQt飞机大战游戏(附下载地址)

欢迎下载体验&#xff01; 文件大小&#xff1a;22.9 M 下载地址&#xff1a;链接&#xff1a;https://wwrr.lanzoul.com/iybV22frvcng pyqt5-飞机大战 一&#xff0e;前言 up主最近高产&#xff0c;再给大家分享一个博主开发的小游戏-飞机大战&#xff0c;这是一款飞行射击游…...

代替Spinnaker 的 POINTGREY工业级相机 FLIR相机 Python编程案例

SpinnakerSDK_FULL_4.0.0.116_x64 是一个用于FLIR相机的SDK&#xff0c;主要用于图像采集和处理。Spinnaker SDK主要提供C接口&#xff0c;无法直接应用在python环境。本文则基于Pycharm2019python3.7的环境下&#xff0c;调用opencv,EasySpin,PySpin,的库实现POINTGREY工业级相…...

redis模糊匹配key内存分析的脚本

效果&#xff1a; 脚本 与 redis-cli 命令放在同一路径下执行脚本 注意&#xff1a; 1、SCAN 命令仅扫描当前节点的键&#xff0c;若要扫描整个集群中的所有节点&#xff0c;建议在各个从节点上分别执行&#xff1b; 2、为避免扫描对业务产生影响&#xff1a; 可以在从节点或…...

STM32设计学生宿舍监测控制系统-分享

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 本项目旨在利用STM32单片机为核心&#xff0c;结合传感器技术、无线通信技…...

Python爬虫案例八:抓取597招聘网信息并用xlutils进行excel数据的保存

excel保存数据的三种方式&#xff1a; 1、pandas保存excel数据&#xff0c;后缀名为xlsx; 举例&#xff1a; import pandas as pddic {姓名: [张三, 李四, 王五, 赵六],年龄: [18, 19, 20, 21],住址: [广州, 青岛, 南京, 重庆] } dic_file pd.DataFrame(dic) dic_file…...

Mybatis-Day3

规则&#xff1a; 定义与SQL映射文件同名的Mapper接口&#xff0c;并且将Mapper接口和SQL映射文件放置在同一目录下 设置SQL映射我呢见的namespace属性为Mapper接口的全限定名 在Mapper接口中定义方法&#xff0c;方法名就是SQL映射文件中sql语句的id&#xff0c;并保持参数类…...

第六节-AppScan扫描报告

第六节-AppScan扫描报告 1.加载扫描结果 1.点击【打开】 2.选择之前保存过的扫描结果 3.等待加载完成 2.领导查看的报告 1.点击【报告】 2.模板选择为【缺省值】 3.最低严重性选择为【中】&#xff0c;测试类型选择为【应用程序】 4.点击【布局】 5.选择【其他徽标】&#x…...

多模MPO的测试套件

MultiFiber™Pro光功率计及光纤测试工具包 首款支持单模和多模MPO光纤认证的MPO光纤测试仪 利用“扫描全部”功能自动扫描和测试MPO连接器中的所有光纤 支持多模和单模MPO光纤干线 在测试光纤干线时无需使用扇形跳线 以最小的界面显示易懂的结果 用户界面上显示所有12光纤 自动…...

使用php和Xunsearch提升音乐网站的歌曲搜索效果

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…...

Idea忽略提交文件、Idea设置文件隐藏、Idea提交时隐藏部分文件、git提交时忽略文件

文章目录 一、在idea中commit文件时隐藏文件方式一&#xff1a;创建.gitignore文件&#xff08;推荐&#xff09;方式二&#xff1a;‌通过File Types设置隐藏文件方式三&#xff1a;通过Git配置忽略文件‌&#xff08;不推荐&#xff09;总结 二、可能遇到的问题2.1、.gitigno…...

菜鸟驿站二维码/一维码 取件识别功能

特别注意需要引入 库文 ZXing 可跳转&#xff1a; 记录【WinForm】C#学习使用ZXing.Net生成条码过程_c# zxing-CSDN博客 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Net.…...

MQ核心作用、解耦、削峰使用场景详解

说在前面 在如今的高并发互联网应用中&#xff0c;如何确保系统在巨大的流量冲击下还能稳定运行&#xff0c;是每个技术团队都会遇到的挑战。说到这&#xff0c;消息队列&#xff08;MQ&#xff09;就是背后的“大功臣”了。无论是异步处理请求、平滑应对流量高峰&#xff0c;…...

【从零开始的LeetCode-算法】3232. 判断是否可以赢得数字游戏

给你一个 正整数 数组 nums。 Alice 和 Bob 正在玩游戏。在游戏中&#xff0c;Alice 可以从 nums 中选择所有个位数 或 所有两位数&#xff0c;剩余的数字归 Bob 所有。如果 Alice 所选数字之和 严格大于 Bob 的数字之和&#xff0c;则 Alice 获胜。 如果 Alice 能赢得这场游…...

使用LLaMA-Factory微调时的问题与解决方案记录

文章目录 如何指定微调使用的显卡如何解决显卡通信导致的报错模型微调的实际epoch和step如何计算如何实现多卡全量微调模型微调后的结果如何查看模型测试后的指标如何理解如何指定微调使用的显卡 启动网页时使用这种执行命令 CUDA_VISIBLE_DEVICES=5,6,7 llamafactory-cli we…...

一文读懂埋阻埋容工艺

PCB 埋阻埋容工艺是一种在 PCB 板内部埋入电阻和电容的工艺。通常情况下&#xff0c; PCB 上电阻和电容都是通过贴片技术直接焊接在板面上的&#xff0c;而埋阻埋容工艺则将电 阻和电容嵌入到 PCB 板的内部层中&#xff0c;这种印制电路板,其自下而上依次包括第一介电 层,隐埋电…...

What is a Tensor?

WTF is a Tensor? What is the difference between tensors and matrixes?...

提升性能测试效率与准确性:深入解析JMeter中的各类定时器

在软件性能测试领域&#xff0c;Apache JMeter是一款广泛使用的开源工具&#xff0c;它允许开发者模拟大量用户对应用程序进行并发访问&#xff0c;从而评估系统的性能和稳定性。在进行性能测试时&#xff0c;合理地设置请求之间的延迟时间对于模拟真实用户行为、避免服务器过载…...

从繁琐到优雅:用 PyTorch Lightning 简化深度学习项目开发

从繁琐到优雅&#xff1a;用 PyTorch Lightning 简化深度学习项目开发 在深度学习开发中&#xff0c;尤其是使用 PyTorch 时&#xff0c;我们常常需要编写大量样板代码来管理训练循环、验证流程和模型保存等任务。PyTorch Lightning 作为 PyTorch 的高级封装库&#xff0c;帮助…...

Python学习32天

Self #比较两个人信息&#xff0c;完全相等输出True,否则输出False class Person(): nameNone ageNone def compare_to(self,other): return self.nameother.name and self.ageother.age man1Person() man1.name"tim" man1.age3 man2Person man…...

云原生学习

1、云原生学习 文章目录 1、云原生学习1. 介绍2. Docker容器化 1. 介绍 什么是云原生&#xff1f;原生指使用JAVA等语言编写的项目&#xff0c;云是指将项目部署到云服务器上云平台&#xff1a;公有云、私有云 本地平台是指直接部署在自己计算机&#xff0c;而开发的应用一定要…...

django从入门到精通(六)——auth认证及自定义用户

Django 提供了一个强大的用户认证系统&#xff0c;允许开发者轻松管理用户的注册、登录、权限和组等功能。以下是对 Django 用户认证系统的详细介绍&#xff0c;包括默认的用户认证、自定义用户认证和权限设置。 1. 默认用户认证 1.1 用户模型 Django 默认提供了一个用户模型…...

影响电阻可靠性的因素

一、影响电阻可靠性的因素&#xff1a; 影响电阻可靠性的因素有温度系数、额定功率&#xff0c;最大工作电压、固有噪声和电压系数 &#xff08;一&#xff09;温度系数 电阻的温度系数表示当温度改变1摄氏度时&#xff0c;电阻阻值的相对变化&#xff0c;单位为ppm/C.电阻温度…...

大数运算(加减乘除和输入、输出模块)

为什么会有大数呢&#xff1f;因为long long通常为64位范围约为 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807&#xff0c;最多也就19位&#xff0c;那么超过19位的如何计算呢&#xff1f;这就引申出来大数了。 本博客适合思考过这道题&#xff0c;但是没做出来或…...

HTML5超酷响应式视频背景动画特效(六种风格,附源码)

文章目录 1.设计来源1.1 大气蓬勃动态背景界面效果1.2 星空闪闪动态背景界面效果1.3 眼神深眸动态背景界面效果1.4 星空银河动态背景界面效果1.5 花开花落动态背景界面效果1.6 海底世界动态背景界面效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开…...

堆优化版本的Prim

prim和dijkstra每轮找最小边的松弛操作其实是同源的&#xff0c;因而受dijkstra堆优化的启发&#xff0c;那么prim也可以采用小根堆进行优化。时间复杂度也由 O ( n 2 ) O(n^2) O(n2)降为 O ( n l o g n ) O(nlogn) O(nlogn)。 测试一下吧&#xff1a;原题链接 #include <i…...

【视觉SLAM】4b-特征点法估计相机运动之PnP 3D-2D

文章目录 0. 前言1. PnP求解1.1 直接线性变换DLT1.2 P3P1.3 光束平差法BA2. 实现0. 前言 透视n点(Perspective-n-Point,PnP)问题是计算机视觉领域的经典问题,用于求解3D-2D的点运动。换句话说,当知道 N N N个世界坐标系中3D空间点的坐标以及它们在图像上的投影点像素坐标…...

JDK1.8中JVM堆内存等参数配置

在JDK 8中&#xff0c;JVM内存模型主要包括堆内存&#xff08;Heap Memory&#xff09;、元空间&#xff08;Metaspace&#xff09;以及直接内存&#xff08;Direct Memory&#xff09;。以下是一些常用的JVM内存参数配置建议&#xff0c;特别是在JDK 8环境下&#xff1a; 1. …...

【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!

文章目录 修改哈希表模板参数迭代器HashTable 的默认成员函数HashTable 迭代器相关函数HashTable 的 Insert 函数HashTable 的 Find函数HashTable 的 Erase函数 封装 unordered_set封装 unordered_map测试 unordered_set 和 unordered_map 修改哈希表 我们基于链地址法实现的哈…...

蓝桥杯模拟

【问题描述】 如果一个数 p 是个质数&#xff0c;同时又是整数 a 的约数&#xff0c;则 p 称为 a 的一个质因数。 请问 2024 有多少个质因数。 【答案提交】 这是一道结果填空的题&#xff0c;你只需要算出结果后提交即可。本题的结果为一个整数&#xff0c;在提交答案时只…...

16. 【.NET 8 实战--孢子记账--从单体到微服务】--汇率获取定时器

这篇文章我们将一起编写这个系列专栏中第一个和外部系统交互的功能&#xff1a;获取每日汇率。下面我们一起来编写代码吧。 一、需求 根据文章标题可知&#xff0c;在这片文章中我们只进行汇率的获取和写入数据库。 编号需求说明1获取每日汇率1. 从第三方汇率API中获取汇率信…...

移动充储机器人“小奥”的多场景应用(上)

一、高速公路服务区应用 在高速公路服务区&#xff0c;新能源汽车的充电需求得到“小奥”机器人的及时响应。该机器人配备有储能电池和自动驾驶技术&#xff0c;能够迅速定位至指定充电点&#xff0c;为待充电的新能源汽车提供服务。得益于“小奥”的机动性&#xff0c;其服务…...

【Android】Service使用方法:本地服务 / 可通信服务 / 前台服务 / 远程服务(AIDL)

1 本地Service 这是最普通、最常用的后台服务Service。 1.1 使用步骤 步骤1&#xff1a;新建子类继承Service类&#xff1a;需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法步骤2&#xff1a;构建用于启动Service的Intent对象步骤3&#xff1a;调用st…...

Qt文件目录操作

文件目录操作相关类 Qt 为文件和目录操作提供了一些类&#xff0c;利用这些类可以方便地实现一些操作。Qt 提供的与文件和目录操作相关的类包括以下几个&#xff1a; QCoreApplication&#xff1a;用于提取应用程序路径&#xff0c;程序名等文件信息&#xff1b;QFile&#x…...

刷题-1122

1. 蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。 例如&#xff0c;当输入5时&#xff0c;应该输出的三角形为&#xff1a; 1 3 6 10 15 2 5 9 14 4 8 13 7 12 11 import sys def generate_snake_matrix(n):matrix [[0]*n for _ in range(n)]curent_num 1…...

【通俗理解】Jensen不等式与变分分布q(z)在积分计算中的应用

【通俗理解】Jensen不等式与变分分布q(z)在积分计算中的应用 关键词提炼 #Jensen不等式 #变分分布 #积分计算 #期望 #凸函数 #优化问题 #下界估计 #机器学习 第一节&#xff1a;Jensen不等式与变分分布的类比与核心概念【尽可能通俗】 Jensen不等式就像是一个“积分计算器”…...

微信小程序2-地图显示和地图标记

一、index修改页面&#xff0c;让页面能够显示地图和一个添加标记的按钮。 index.wxml <scroll-view class"scrollarea" scroll-y type"list"><view class"index_container"><map id"map" style"width: 100%; h…...

webpack配置和打包性能优化

文章目录 webpack基础配置loaderpluginloader 和 plugin 的区别devServer打包性能优化1、按需引入组件2、externals 属性3、给定文件匹配范围4、noParse 属性5、cacheDirectory 缓存属性6、happyPack 多个子进程并行 webpack基础配置 mode:development&#xff1a;设置webpack…...

iframe嵌入踩坑记录

iframe嵌入父子页面token问题 背景介绍 最近在做在平台A中嵌入平台B某个页面的需求&#xff0c;我负责的是平台B这边&#xff0c;使这个页面被嵌入后能正常使用。两个平台都实现了单点登录。 其实这是第二次做这个功能了&#xff0c;原本以为会很顺利&#xff0c;但没想到折腾…...

FreeRTOS——消息队列

目录 一、概念及其作用 1.1概念 1.2特点 1.3工作原理 二、相关API 2.1创建队列 2.2任务中写队列 2.3任务中读队列 2.4中断中写队列 2.5中断中读队列 三、实现原理 3.1消息队列控制块 3.2消息队列的创建 3.3消息的发送 3.3.1任务中发送 3.3.2中断中发送 3.4消息的…...

c++11的动态类型

c17引入了any 和 variant&#xff0c;可以将任意数据类型统一用any或variant类型表示&#xff0c;在开发中还是能够带来很多便利的。在c11版本中&#xff0c;可以用下面这个例子&#xff0c;仿照实现一个Any类型。 #include <iostream> #include <stdexcept> #inc…...

大语言模型---Llama模型文件介绍;文件组成

文章目录 1. 概要2. 文件组成 1. 概要 在使用 LLaMA&#xff08;Large Language Model Meta AI&#xff09;权重时&#xff0c;通常会涉及到与模型权重存储和加载相关的文件。这些文件通常是以二进制格式存储的&#xff0c;具有特定的结构来支持高效的模型操作。以下以Llama-7…...