导语
本次通过执行业务修改个人资料,来记录在编写脚本时遇到的问题及解决方式,具体业务为:登录商城-->点击账号设置-->点击个人资料-->修改真实姓名-->选择性别-->选择生日-->输入QQ-->点击确认按钮。
一、submit按钮难以定位
在上一篇文章中基于selenium的web自动化学习之路总结(一)有讲到登录的定位方式,假如这里的“登录”按钮,使用常用的定位方式无法定位,这时候我们可以采用submit方法。
仔细看一下登录的html,会发现这其实是个表单,而submit方法,类似click,只能用于form表单中,在form表单中,所有数据一起提交,提交任何一个元素,就提交了整个表单。代码如下:
# 输入用户名、密码
chromedriver.find_element_by_id("username").send_keys("xiao")
chromedriver.find_element_by_id("password").send_keys("123456")
# submit方法来定位登录按钮并点击的操作
chromedriver.find_element_by_id("password").submit()
二、部分链接定位使用方法
可以注意到,“个人资料”前面还有个小图标,如果“个人资料”被图标隔断呢,这个时候就可以使用部分链接文本来定位,代码如下:
# 点击个人资料
chromedriver.find_element_by_partial_link_text("人资").click()
三、css_selector 用法二
在上一篇文章中基于selenium的web自动化学习之路总结(一)有讲到css_selector的一种用法,这里介绍第二种用法,观察HTML发现,性别这里的三个单选按钮,只有value属性不同,其他属性都一样,这样可以使用css_selector的另一种用法,可以采用任意的属性来定位元素,只需要在属性两边加一对中括号,代码如下:
# 选择性别
chromedriver.find_element_by_css_selector("[value='2']").click()
四、处理日历控件
4.1 定位日历控件的方法
日历控件的定位,可以一次一次的点击,去选择年月日,但是过于繁琐。通过观察发现(图4),这个日历控件input type="text" ,本质也是文本类型的输入框,只是后面还有一个readonly,只读。尝试在HTML中将这个readonly删掉后就会发现(图5),这个文本框就可以输入了,这样就有了一个想法,是不是可以想办法删除readonly属性,再去向日历控件中输入生日?
但是,selenium无法删除一个元素的属性,JavaScript可以做到,先在控制台尝试操作一下,输入以下内容:
document.getElementById("date")
document.getElementById("date").removeAttribute("readonly")
这样一来,我们只需要将此方法转换到Python中,便可以达到想要的效果了,代码如下:
# 删除readonly属性
script = 'document.getElementById("date").removeAttribute("readonly")'
chromedriver.execute_script(script)
# 输入新生日
chromedriver.find_element_by_id("date").send_keys("1999-01-01")
执行程序后,发现选择生日的问题解决了,但是,程序多次执行后,又发现了新的问题。
4.2 问题--旧数据与新数据并存
按照我们功能测试的经验,一般是先删除旧数据,再写入新数据,代码也可以如此操作,代码如下:
# 清除旧生日
chromedriver.find_element_by_id("date").clear()
# 输入新生日
chromedriver.find_element_by_id("date").send_keys("1999-01-01")
接下来的业务是输入 QQ,点击“确认”按钮,均可以采用常用定位方式解决,但是在多次执行程序后,“真实姓名”和“QQ”输入框均会出现上述的旧数据与新数据并存的问题,也可以在每一个send_keys的操作前加入clear操作,当然这样重复的代码是有优化方案的,在本次就不多说啦。
五、处理弹出框
5.1弹出框分析
弹出框alert,不是HTML的页面元素,而是JavaScript的控件,由于不能通过右键-检查来查看,所以不同于传统的方法操作,selenium提供了三个常用处理alert的方法:
(1)点击确定按钮:driver.switch_to.alert.accept()
(2)点击取消按钮:driver.switch_to.alert.dismiss()
(3)获取弹出框提示的文本信息:driver.switch_to.alert.text
在这里,用第一种方式来操作一下,代码如下:
# 点击确定,关闭弹出窗
chromedriver.switch_to.alert.accept()
5.2 时间等待问题分析
执行上述代码后,会发现网页中弹出窗的确定按钮并没有被点击,因此弹出窗没有关闭,查看代码,发现已经报错,报错如下:
程序执行的时候发现没有这个弹出框,这是什么原因呢,明明我们在页面中可以看到弹出框。再执行一次代码,发现弹出框的出现可能存在延迟,但是回顾代码发现,已经加入了隐式等待,代码如下 :
chromedriver = webdriver.Chrome()
chromedriver.implicitly_wait(5)
这里说明一下,在处理弹出框时,隐式等待不起作用,因为隐式等待判断的是页面的加载,点击确定按钮,弹出框出来后,页面没有刷新过,所以不会起作用,这样在处理弹出框前,加一个强制等待时间即可,代码如下:
# 关闭弹窗
time.sleep(3)
chromedriver.switch_to.alert.accept()
加入了时间等待后,果然可以正确执行,关闭弹出窗了,但是这样,可能很多时候不需要3秒,那有没有智能的方式呢?还有一种显示等待方式,代码如下:
# 关闭弹窗
WebDriverWait(chromedriver, 30, 0.5).until(expected_conditions.alert_is_present())
chromedriver.switch_to.alert.accept()
简单解释一下这个显示等待,针对chromedriver最长等待时间30s,每隔0.5s检查一下,如果弹出框已经出现,则不用再等待,如果没有找到弹出框,就隔0.5s检查一下,直到找到弹出框为止。
总结一下,目前已经使用过3种时间等待方式:
(1)强制等待:time.sleep(3)
(2)隐式等待:chromedriver.implicitly_wait(3)
(3)显示等待:WebDriverWait(chromedriver,30,0.5).until(expected_conditions.alert_is_present()) ,expected_conditions后有多种方式,根据需要选择即可。
六、总结
本次说明了submit方法、partial_link_text、css_selector的用法,并分析了日历控件和弹出框的处理方式,同时发现了时间等待的问题。
成长之路,道阻且长,后续会继续总结自己平时遇到的一些问题,加油!