浏览器copy selector
我们选择元素有一个方法可以快速生成,右键点击元素点击检查定位到元素后,右键点击元素有个Copy
,选择Copy selector
![](https://img.haomeiwen.com/i15646290/fb5532cd4d631ca3.png)
Copy selector
是Css
的写法,我们看到也有XPath
大家也可以试一下,这种方法其实是非常有限的,这种方式是以一个有id
的元素为瞄点往下找,如果有id的元素不是本身而是上层节点他就要依赖上层节点和他的相对关系来找,如果上层节点跟他隔得很远,他也会一层层的找打他有id
的上层节点,路径会很长如果他中间的任何一个环节发生变化就容易出问题健壮性不好,他不会根据别的方法比如class
,这种方法我们了解一下就好很鸡肋。
异常捕获,确保chrom进程退出
我们做练习的时候不可能一次就把作业做出来,总归要做一些调试出错调试出错,肯定遇到过出错浏览器就没法关闭的状况,有的同学会想不关就不关呗我们手动关上就好了,调试的时候是可以的,假如我们做系统自动化的时候有很多的用例上百个web自动化用例在执行,如果遇到报错浏览器没有关闭,第二天我们去看的话机器就像卡死了一样,因为很多用例遇到报错比如找不到元素的错误导致浏览器开了二三十个在那甚至更多,我们可以把自动化逻辑放在异常捕获try
里面`,看下面例子
from selenium import webdriver
import time
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.implicitly_wait(10)
driver.get('https://www.baidu.com/')
print(driver.title)
driver.find_element_by_id('kk').send_keys('杭州')
driver.quit()
百度的输入框id
为kw
我这里改为kk
这时候,由于不能执行到driver.quit,浏览器就不能自动关闭,解决方法
import traceback
from selenium import webdriver
import time
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.implicitly_wait(10)
try:
driver.get('https://www.baidu.com/')
print(driver.title)
driver.find_element_by_id('kk').send_keys('杭州')
except:
print(traceback.format_exc())
finally:
driver.quit()0
写在try
里面,finally
后面需要driver.quit()
我们操作界面的时候不需要点击他,把鼠标移动到上面就会导致页面的变化,比如我们打开华为官网https://www.vmall.com/
![](https://img.haomeiwen.com/i15646290/fc17842b6d95af5c.png)
HTML
当中即使光标不放在上面,我们能不能不模拟光标放在上面,可以找到直接去选择元素(笔记本电脑之类的)吗?像这些界面元素如果没有把光标停在上面让界面显示出来,通常是不能操作他的会出错,因为当前这个元素如果处于没有显示出来的状态你就想试着去操作他,其实这个元素有个属性
![](https://img.haomeiwen.com/i15646290/a36d5e8fa85ce74f.png)
class
等于none
的这种属性他的display
是none
![](https://img.haomeiwen.com/i15646290/62aa8a930dfaeb36.png)
display
元素是none
的意思是他当前在界面放在HTML里面但是他不显示出来不显示在界面上,Selenium是高度模拟用户点击操作的,因为他没有显示出来这个时候你点击他会出错的,我们可以把它冻结
![](https://img.haomeiwen.com/i15646290/ccc75cb859a45c18.png)
Selenium
怎么模拟这个移动鼠标到某个元素的动作呢?通过ActionChains
类,ActionChains
类 里面提供了 一些特殊的动作, 比如移动鼠标到某个元素,就是其中之一,ActionChains
本身有个ActionChains
模块文件本身实现了一个ActionChains
类,我们查看这个类的放方法
![](https://img.haomeiwen.com/i15646290/841150d7f8bd26c2.png)
![](https://img.haomeiwen.com/i15646290/5c661f74a1edd008.png)
click
点击,click_and_hold
点击按住不动不要松,context_click
右键点击,double_click
双击等这里不一一介绍大家自己去研究,我们这里用到的就是move_to_element
悬停就使用他
from selenium import webdriver
import time
executable_path = r"d:\tools\webdrivers\chromedriver.exe"
driver = webdriver.Chrome(executable_path)
driver.get('https://www.vmall.com/')
# ---------------------------------------
# 导入ActionChains这个类
from selenium.webdriver.common.action_chains import ActionChains
# 创建实例对象
ac = ActionChains(driver)
#移动不点击 .perform()执行
ac.move_to_element(driver.find_element_by_id('zxnav_1')).perform()
ele= driver.find_element_by_css_selector(
'#zxnav_1 > div.category-panels.relative > ul > li:nth-child(1) > a')
ele.click()
# ---------------------------------------
input('...')
driver.quit()
下面我们看一段HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>定位网页元素</title>
</head>
<body style="width:1600px">
<div>
<span>输入框</span> <input type="text" style="margin-top:2200px">
</div>
</body>
</html>
可以看到这段HTML很简单,body
里面有个div
,div
里面有个span
里面有个input
输入框,里面有个很奇怪的属性margin-top
他的意思是
![](https://img.haomeiwen.com/i15646290/857c6cf7a56f493f.png)
2200px
像素,这个间隔是很高的,大家复制这段html
看一下,比如做自动化的时候web
页面很长,他的内容在很下面,我们需不要把这个页面滚动到下方让他出来再去操作这个元素呢?大家注意华为官网的看不到是因为元素所在的区域已经有了,只是你没有操作他,它属于不可见属性的看不到,但是我们现在讲的这种其实可见状态只是你滚动条没有拉下来,通长这种情况不需要你滚动下来的,它本身在视图上是有的只是没呈现滚动区域里面
from selenium import webdriver
executable_path = r"d:\tools\webdrivers\chromedriver.exe"
driver = webdriver.Chrome(executable_path)
driver.implicitly_wait(10)
driver.get('file:///D:/gsync/workspace/sq/selenium/samples_selenium/wd/lesson07/winsize.html')
searchbox = driver.find_element_by_tag_name('input')
searchbox.send_keys('你好啊\n')
input('...')
driver.quit()
大家自己拿代码试一下。
如果确实需要改变窗口大小,
- 有时确实让元素可见,才能点击(有时候确实是这样,不知道什么原因)
- 或者觉得这样看起来更清楚一些
size = driver.get_window_size()#返回是字典格式
driver.set_window_size(1100,size['height'])
下面是对网易云音乐写的代码,可拿去试一下
from selenium import webdriver
driver = webdriver.Chrome(r"E:\ChromDriver\chromedriver.exe")
driver.implicitly_wait(10)
driver.get('http://music.163.com')
# 结果像这样 {'width': 855, 'height': 922}
size = driver.get_window_size()
print(size)
# 只改变宽度
driver.set_window_size(1300, size['height'])
#最大化
driver.maximize_window()
searchbox = driver.find_element_by_css_selector('#srch')
searchbox.send_keys('张学友\n')
driver.quit()
假如还一种情况要找的元素他在特别的右边或特别的下边窗口最大化都显现不出来,那就需要滚动元素的方案,selenium
没有直接的方法,可以使用最后一招, 直接让浏览器执行javascript
脚本浏览器执行的语言是js
, 如果我们能直接传入js
代码让浏览器执行,就得到了最大的灵活性去控制浏览器。可以算是终极武器。 比如滚动屏幕,就可以使用js
语言
driver.execute_script('window.scrollBy(250,0)')
第一个参数250是横向滚动就是x坐标滚动,往右滚250个像素,如果有们想往左滚
driver.execute_script('window.scrollBy(-250,0)')就滚回去了
第二个参数是下滚
driver.execute_script('window.scrollBy(0,300)')
上滚加个负号就好了
界面重新绘制
接下来说一下界面里面元素出现动态改变的这个情况,我们看一个例子,下面截图是一个教管系统!
![](https://img.haomeiwen.com/i15646290/df1af5807d5e9c8a.png)
假如我们要实现一个自动化,要把所有的课程信息删除掉,如果按照之前的方法我们点击“删除”然后点击“确定”,把所有的删除按钮都找到,看似很简单我们按照这个思路去写代码,根据我们的思路要把所有的删除按钮找出来
![](https://img.haomeiwen.com/i15646290/17f413791778b2ea.png)
btn-green
看名字就可以看出来按钮是绿色的btn-outlined
是外面有一个方框,根据这个class是不好去找的因为编辑也有同样的属性,这里根据ng-click
这个属性去找比较好,他这个属性对应删除的动作,点了这个删除之后会执行一段JavaScript
代码或函数,删除是跟这个紧密相关的,点击删除之后这里还有个确定,
![](https://img.haomeiwen.com/i15646290/4b0fd8ac42853d45.png)
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('http://localhost/mgr/login/login.html')
#登录
driver.find_element_by_id('username').send_keys('auto')
driver.find_element_by_id('password').send_keys('sdfsdfsdf')
driver.find_element_by_tag_name('button').click()
time.sleep(1)
#根据ng-click去找删除按钮,这里是个list
delButtons = driver.find_elements_by_css_selector(
'*[ng-click^=delOne]')
for button in delButtons:
button.click()
time.sleep(1)
driver.find_element_by_css_selector(
'.modal-footer .btn-primary').click()
运行会发现删除第一个之后就不动了,报错了报错信息如下
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
(Session info: chrome=74.0.3729.157)
(Driver info: chromedriver=74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}),platform=Windows NT 10.0.17134 x86_64)
我们分析一下报错WebDriver
报的Exception
,unknown error
不知道什么类型,我们看下error的报错Element <button >
对应的是这个webelement对象,看后面的就是我们删除按钮web的写法<button type="button" class="btn btn-green btn-outlined btn-xs ng-scope" ng-click="delOne(one)"
,报is not clickable at point
是不可点击的,Other element would receive the click
另外一个元素接收到点击的动作,这个元素为什么不可点击呢。大家想一下刚才的运行结果,确实已经删除了一个元素了到第二个删除操作的时候就报错了,大家以后做自动化的时候会经常遇到这种事情,因为现在web前端的开发很多开发人员使用的方法都会动态的更新的前端界面,之前最早的web界面的呈现,比如导致web界面出现了变化,都是发起http请求,后端返回一个完整的http页面给你,以前都是这样,随着前端开发衍进觉得这种效率太低,因为有的时候并不需要后端重新产生一个完整的界面,比如这个删除操作,删除一个课程只需要告诉后端我把这个课程删了,服务器处理一下在数据库把这个课程清除掉,没有必要让服务端再返回一个完整html的界面给前端,对于我们来说只需要在代码里动态的把课程清除掉就可以,所以这个时候前端的开发可以动态改变前端的内容,可以通过JavaScript
代码更新界面,或者一些框架,这样就产生了一个问题就像之前这样看似点击删除按钮,点击确定好像界面只少了一个课程,但实际上有的框架就不是简单的把这一个元素删了,他有可能把整个表格获取一次重新产生了,重新产生意思是原来是4条记录现在重新产生了眼睛看起来就少了一条ji记录,实际上页面上所有的元素都重新创建了一遍,这就带来我们删除一门课程之后导致现在界面剩下来3个删除按钮已经不是刚才4个中的3个了,就是这个原因导致的,我们可以这样既然你之后界面刷新了那我们每次删除之后就重新获取当前界面的元素就可以了
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('http://localhost/mgr/login/login.html')
driver.find_element_by_id('username').send_keys('auto')
driver.find_element_by_id('password').send_keys('sdfsdfsdf')
driver.find_element_by_tag_name('button').click()
time.sleep(1)
driver.implicitly_wait(1)
while True:
#找删除按钮
delButtons = driver.find_elements_by_css_selector(
'*[ng-click^=delOne]')
#判断有没有删除按钮
if delButtons == []:
break
#如果有就找到第一个元素,点击他
delButtons[0].click()
#点确定
driver.find_element_by_css_selector('.modal-footer .btn-primary').click()
time.sleep(1)
driver.implicitly_wait(5)
这样就没有问题,因为我们每次删除按钮都会重新获取当前页面,大家会不会有个疑惑循环前有个implicitly_wait(1)
循环后又把implicitly_wait(1)
改成implicitly_wait(5)
呢,主要是因为循环删除总有一次删光了,删光了最后一次循环执行delButtons = driver.find_elements_by_css_selector('*[ng-click^=delOne]')
的时候,因为删光了就没有元素,就会等待全局的等待时间比如5秒,就会等待5秒,临时的把时间改短了点这样比较好。这里的time.sleep(1)
很重要,因为你点击确定删除的时候就会执行删除操作,服务端就会删除数据,界面刷新会花一段时间,如果没有sleep(1)
就会立即获取页面,就会获取到没有更新的页面元素
看一个练习:
Selenium 作业 6
作业1
登录华为官网 https://www.vmall.com/,
点击 "华为官网" 链接
查 "华为官网" 页面上是否 有如下主菜单
智能手机
笔记本
平板
穿戴设备
智能家居
更多产品
软件应用
服务与支持
最后再回到主窗口, 检查鼠标停留在 "笔记本&平板" 处的时候, 是否显示的菜单有
"平板电脑 笔记本电脑 笔记本配件"
怎么模拟鼠标停留事件,请大家自行网上搜索,看看能不能自己解决问题。
from selenium import webdriver
import time
from selenium.webdriver import ActionChains
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.get('https://www.vmall.com/')
driver.implicitly_wait(10)
# print(driver.title)
#主窗口handle
main_window=driver.current_window_handle
#点击进入华为官网
driver.find_element_by_css_selector('a[href="http://consumer.huawei.com/cn/"]').click()
for handle in driver.window_handles:
driver.switch_to.window(handle)
if '华为消费者业务官网' in driver.title:
# print(handle)
break
#找到主菜单
orders_eles = driver.find_elements_by_css_selector('ul.clearfix.nav-cnt a.a-common.products-name')
orders_txt = [ele.text for ele in orders_eles]
expect_orders='''智能手机
笔记本
平板
穿戴设备
智能家居
更多产品
软件应用
服务与支持
'''
expect_text = [order.strip() for order in expect_orders.split('\n')]
if orders_txt == expect_text:
print('匹配菜单成功')
else:
print('匹配失败')
# print(orders_txt)
# print(expect_text)
#回到主页面
driver.switch_to.window(main_window)
# print(driver.title)
#鼠标停留在笔记本菜单
ele = driver.find_element_by_id('zxnav_1')
ActionChains(driver).move_to_element(ele).perform()
#检查菜单项
css='li#zxnav_1 div.category-panels.category-panels-1 span'
orders = driver.find_elements_by_css_selector(css)
order_text = [order.text for order in orders]
# print(order_txt)
expect_txt = u'''平板电脑|笔记本电脑|笔记本配件'''
order_txt='|'.join(order_text)
if expect_txt == order_txt:
print('匹配菜单成功')
else:
print('匹配失败')
print(expect_txt)
print(order_txt)
driver.quit()
作业2
写一个程序实现如下的自动化过程
- 登录 https://tinypng.com/
- 点击 上传文件的虚线框
- 选择 插图,在本地目录中选择一张准备好的图片 , 查看是否能够上传图片成功
from selenium import webdriver
import time
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.implicitly_wait(10)
driver.get('https://tinypng.com/')
print(driver.title)
#点击上传图标
driver.find_element_by_css_selector("figure.icon").click()
# 直接发送键盘消息给 当前应用程序,
# 前提是浏览器必须是当前应用
# pip install pypiwin32
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
# 有的系统要加 '\r'
# 有的系统要加 '\r\n'
img_name='1.jpg'
shell.Sendkeys('e:\\' + img_name + '\n'+ '\n')#在当前的焦点应用程序发送一个字符串
time.sleep(3)
file_ele = driver.find_element_by_css_selector('div.before:nth-of-type(1)')
print(file_ele.text)
file_name = file_ele.text.split('\n')[1]
if img_name.upper() == file_name.upper():
print('上传成功')
else:
print('上传失败')
input('...')
driver.quit()
网友评论