Selenium是一套web网站的程序自动化操作解决方案。我们通过编写自动化程序,使得自动完成浏览器界面的相关操作,除了能够自动化的完成相关操作,还能从web页面获取相关信息,然后通过程序进行分析处理,本质上就是提升从网页上输入和获取信息的能力 。
可以参考这个网站:www.byhy.net
一、selenium原理
selenium通过自动化脚本控制浏览器驱动,浏览器驱动控制浏览器,进而完成相应的自动化测试,整体来说就是程序控制。
二、selenium自动化环境搭建
2.1、pip安装
首先先下载pip,我用的mac本,在终端输入以下语句,因为后面要用该命令进行安装。
curl https://bootstrap.pypa.io/pip/get-pip.py -o get-pip.py
sudo python3 get-pip.py
安装成功,但是有warning,需要将其添加到path,将你的黄色警告的文件目录部分更换下面PATH=后的目录部分。
echo 'export PATH=/Users/hb24760/Library/Caches/pip:$PATH' >>~/.bashrc
输入指令是的文件生效,并验证pip是否安装成功。
source ~/.bashrc
pip -V
pip安装成功。
2.2、 安装Selenium客户端库
首先使用pip指令安装,在命令终端输入如下命令。
pip install selenium -i https://pypi.douban.com/simple/
安装成功,如下。
2.3、安装浏览器和浏览器驱动
浏览器首先chrome,正常下载安装就行了,这里不在赘述。
我们看一下如何安装浏览器驱动,首先看一下浏览器的版本,浏览器驱动的版本要和浏览器版本一致才可以。我的浏览器版本是114.
在下面的浏览器驱动地址中,选择114版本的chrome驱动进行安装就可以了,可以发现mac有两个版本,我是intel的,所以选上面的。
https://chromedriver.storage.googleapis.com/index.html
2.4、安装python环境与pychram集成开发环境
我是mac本,具体参考这个链接进行安装就可以了,我这边不再赘述,链接如下:
Mac安装python 环境& pycharm_mac pycharm 安装_程序员雷子的博客-CSDN博客
三、选择元素的基本方法
3.1、自动化脚本打开浏览器对应url
使用如下脚本可以自动打开chrome浏览器并打开百度的官网。
from selenium import webdriver
# 创建 WebDriver 对象,指明使用chrome浏览器驱动
# 这里现在可以指定路径,会自动寻找电脑上的chrome驱动
wd = webdriver.Chrome()
# 调用WebDriver 对象的get方法 可以让浏览器打开指定网址
wd.get('https://www.baidu.com')
3.2、选择元素
3.2.1、根据元素id选择元素
首先我们看一下根据元素id属性值选择元素,根据开发规范,正常一个HTML页面的元素id是唯一的,所以根据id寻找元素是很高效的。下面是根据元素id选择元素搜索框,然后输入通讯,然后根据id选择元素按钮,点击查询。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
# 创建 WebDriver 对象
wd = webdriver.Chrome()
# 调用WebDriver 对象的get方法 可以让浏览器打开指定网址
wd.get('https://www.byhy.net/_files/stock1.html')
# 根据id选择元素,返回的就是该元素对应的WebElement对象
try:
# 找到id为kw的元素并键入“通讯”
element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯')
# 通过该 WebElement对象,就可以对页面元素进行操作了
# 比如输入字符串到 这个 输入框里 并按回车键
# element.send_keys('通讯\n')
# 找到id为go的按钮元素,并点击
element = wd.find_element(By.ID, 'go')
element.click()
except NoSuchElementException:
print('元素id不存在!!!')
演示效果图如下:
3.2.2、根据class和tag属性选择元素
下面根据属性class和tag寻找元素,如下所示。
from selenium.common.exceptions import NoSuchElementException
from selenium import webdriver
from selenium.webdriver.common.by import By
# 创建 WebDriver 实例对象,指明使用chrome浏览器驱动
wd = webdriver.Chrome()
# WebDriver 实例对象的get方法 可以让浏览器打开指定网址
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')
# 根据 class name 选择元素,返回的是 一个列表
# 里面 都是class 属性值为 animal的元素对应的 WebElement对象
try:
elements = wd.find_elements(By.CLASS_NAME, 'animal')
# 取出列表中的每个 WebElement对象,打印出其text属性的值
# text属性就是该 WebElement对象对应的元素在网页中的文本内容
for element in elements:
print(element.text)
except NoSuchElementException:
print("元素不存在!!!")
try:
# wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')
# 根据 tag name 选择元素,返回的是 一个列表
# 里面 都是 tag 名为 div 的元素对应的 WebElement对象
elements = wd.find_elements(By.TAG_NAME, 'div')
# 取出列表中的每个 WebElement对象,打印出其text属性的值
# text属性就是该 WebElement对象对应的元素在网页中的文本内容
for element in elements:
print(element.text)
except NoSuchElementException:
print("元素不存在!!!")
3.2.3、隐式等待
Selenium 的 Webdriver 对象 有个方法叫
implicitly_wait
,可以称之为
隐式等待
,或者
全局等待
。该方法接受一个参数, 用来指定最大等待时长。下面通过打开网页,选择元素kw,输入通讯并回车,将查询出的id为1的元素取出来。
from selenium import webdriver
from selenium.webdriver.common.by import By
# 创建 WebDriver 实例对象,指明使用chrome浏览器驱动
wd = webdriver.Chrome()
# 设置查找不到元素等待时间
wd.implicitly_wait(10)
wd.get('https://www.byhy.net/_files/stock1.html')
element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')
# 返回页面 ID为1 的元素
element = wd.find_element(By.ID,'1')
3.2.4、操纵元素
我们如果想清空输入框,需要用clear方法,find_element方法可以根据属性寻找元素,get_attribute方法可以得到元素里面的属性。
from selenium import webdriver
from selenium.webdriver.common.by import By
# 创建 WebDriver 实例对象,指明使用chrome浏览器驱动
wd = webdriver.Chrome()
# 设置查找不到元素等待时间
wd.implicitly_wait(10)
wd.get('https://www.byhy.net/_files/stock1.html')
element = wd.find_element(By.ID, 'kw')
element.send_keys('通讯\n')
# 清除输入框已有的字符串
element.clear()
# 输入新字符串
element.send_keys('科技')
# 除了上面的find_elements外,也可以使用et_attribute获取元素
value = element.get_attribute('value')
element = wd.find_element(By.CLASS_NAME, 'name')
innerText = element.get_attribute('innerText')
outerHTML = element.get_attribute('outerHTML')
innerHTML = element.get_attribute('innerHTML')
print(value)
print(innerText)
print(outerHTML)
print(innerText)
四、CSS表达式
4.1、css选择器
如果我们要选择的 元素 没有id、class 属性,或者有些我们不想选择的元素 也有相同的 id、class属性值,怎么办呢?这时候我们通常可以通过
CSS selector
语法选择元素。
比如,我们想在
id 为 searchtext
的输入框中输入文本
你好。
根据class属性 选择元素的语法是在 class 值 前面加上一个点:
.class值
选择元素的直接子元素:
元素1 > 元素2 > 元素3 > 元素4
选择元素的后代元素:元素1 元素2
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')
# 根据CSS选择器选择id为searchtext的输入框,并键入你好
element = wd.find_element(By.CSS_SELECTOR, '#searchtext')
element.send_keys('你好')
wd.get('http://f.python3.vip/webauto/sample1.html')
# 选择id为top的非直接子元素为id是body,直接子元素class为container的
element = wd.find_element(By.CSS_SELECTOR, '#top #body > .container')
print(element.text)
当然,也可以根据通过css选择器,通过属性选择,如下所示。
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.implicitly_wait(10)
wd.get('http://f.python3.vip/webauto/sample1.html')
# 根据属性选择元素
element = wd.find_element(By.CSS_SELECTOR, '[href="https://beian.miit.gov.cn/"]')
print(element.text)
4.2、验证css选择器
我们可以在开发者环境,验证网页的css表达式是否有效,有效的表达式,我们才写到程序里面,这样可以避免程序bug。
按住ctr+f键盘,在如下弹出的输入框输入表达式,就可以验证css选择器的表达式是否合法。
4.3、css组选择
如果我们要 同时选择所有class 为 plant
和
class 为 animal 的元素。怎么办?
这种情况,css选择器可以 使用
逗号
,称之为 组选择 ,像这样
.plant , .animal
选择所有 id 为 t1 里面的
span 和 p 元素
,需要写两遍#t1,如下:
#t1 > span , #t1 > p
4.4、css选择器按次序选择
我们可以指定选择的元素
是父元素的第几个子节点
,使用
nth-child,
也就是说 选择的是 第2个子元素,并且是span类型,所以这样可以这样写
span:nth-child(2)
如果你不加节点类型限制,直接这样写
:nth-child(2),
就是选择所有位置为第2个的所有元素,不管是什么类型。
也可以反过来, 选择的是父元素的
倒数第几个子节点
,使用
nth-last-child
,比如:
p:nth-last-child(1)
我们可以指定选择的元素 是父元素的第几个
某类型的
子节点,使用
nth-of-type。
还可以这样思考,选择的是
第1个span类型
的子元素,所以也可以这样写
span:nth-of-type(1)
当然也可以反过来, 选择父元素的
倒数第几个某类型
的子节点,使用
nth-last-of-type
p:nth-last-of-type(2)
如果要选择的是父元素的
偶数节点
,使用
nth-child(even)
,比如:
p:nth-child(even)
如果要选择的是父元素的
奇数节点
,使用
nth-child(odd)
p:nth-child(odd)
如果要选择的是父元素的
某类型偶数节点
,使用
nth-of-type(even)
如果要选择的是父元素的
某类型奇数节点
,使用
nth-of-type(odd)
选择 h3
后面紧跟着的兄弟节点
span。这就是一种 相邻兄弟 关系,可以这样写
h3 + span
表示元素 紧跟关系的 是
加号,
如果要选择是 选择 h3
后面所有的兄弟节点
span,可以这样写
h3 ~ span
4.5、
frame切换
我们使用switch指令可以实现frame的切入和切出,具体如下。
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('https://cdn2.byhy.net/files/selenium/sample2.html')
# 切换到frame
'''
wd.switch_to.frame('frame1')
wd.switch_to.frame('innerFrame')
'''
wd.switch_to.frame(wd.find_element(By.TAG_NAME, "iframe"))
# 根据 class name 选择元素,返回的是 一个列表
elements = wd.find_elements(By.CLASS_NAME, 'plant')
for element in elements:
print(element.text)
# 再切回到html中
wd.switch_to.default_content()
# 然后再 选择操作 外部的 HTML 中 的元素
wd.find_element(By.ID,'outerbutton').click()
4.6、浏览器窗口
切换
我们依次获取 wd.window_handles 里面的所有 句柄 对象, 并且调用 wd.switch_to.window(handle) 方法,切入到每个窗口,然后检查里面该窗口对象的属性(可以是标题栏,地址栏),判断是不是我们要操作的那个窗口,如果是,就跳出循环。
因为我们一开始就在 原来的窗口里面,我们知道 进入新窗口操作完后,还要回来,可以事先 保存该老窗口的 句柄,使用如下方法。
# mainWindow变量保存当前窗口的句柄
mainWindow = wd.current_window_handle
切换到新窗口操作完后,就可以直接像下面这样,将driver对应的对象返回到原来的窗口。
#通过前面保存的老窗口的句柄,自己切换到老窗口
wd.switch_to.window(mainWindow)
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.implicitly_wait(10)
wd.get('https://cdn2.byhy.net/files/selenium/sample3.html')
# mainWindow变量保存当前窗口的句柄
mainWindow = wd.current_window_handle
# 点击打开新窗口的链接
link = wd.find_element(By.TAG_NAME, "a")
link.click()
for handle in wd.window_handles:
# 先切换到该窗口
wd.switch_to.window(handle)
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if 'Bing' in wd.title:
# 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
break
# wd.title属性是当前窗口的标题栏 文本
print(wd.title)
# 通过前面保存的老窗口的句柄,自己切换到老窗口
wd.switch_to.window(mainWindow)
4.7、mac selenium脚本启动打开已有浏览器
首先编辑~/.zshrc添加环境变量,并使其生效,终端键入:
export PATH="/Applications/Google Chrome.app/Contents/MacOS:$PATH"
source ~/.zshrc
终端执行命令打开google浏览器,如下:
Google\ Chrome --remote-debugging-port=9222 --user-data-dir="~/ChromeProfile"
我们可以先登陆好某个网站,下次就可以避免登陆校验了。
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
browser = webdriver.Chrome(options=options)
url = 'http://fat-hms.hellobike.cn/#/resource/theme'
browser.get(url)
五、选择框
5.1、radio框
radio框选择选项,直接用WebElement的click方法,模拟用户点击就可以了。
其中
#s_radio input[name="teacher"]:checked
里面的
:checked
是CSS伪类选择
表示选择
checked
状态的元素,对
radio
和
checkbox
类型的input有效
# 获取当前选中的元素
element = wd.find_element(By.CSS_SELECTOR,
'#s_radio input[name="teacher"]:checked')
print('当前选中的是: ' + element.get_attribute('value'))
# 点选 小雷老师
wd.find_element(By.CSS_SELECTOR,
'#s_radio input[value="小雷老师"]').click()
5.2、checkbox框
对checkbox进行选择,也是直接用 WebElement 的 click 方法,模拟用户点击选择。
需要注意的是,要选中checkbox的一个选项,必须
先获取当前该复选框的状态
,如果该选项已经勾选了,就不能再点击。否则反而会取消选择。
我们的思路可以是这样:
- 先把 已经选中的选项全部点击一下,确保都是未选状态
- 再点击 要选择的
# 先把 已经选中的选项全部点击一下
elements = wd.find_elements(By.CSS_SELECTOR,
'#s_checkbox input[name="teacher"]:checked')
for element in elements:
element.click()
# 再点击 小雷老师
wd.find_element(By.CSS_SELECTOR,
"#s_checkbox input[value='小雷老师']").click()
5.3、select选择框
对于Select 选择框, Selenium 专门提供了一个
Select类
进行操作。
对于 select单选框,操作比较简单:不管原来选的是什么,直接用Select方法选择即可。
# 导入Select类
from selenium.webdriver.support.ui import Select
# 创建Select对象
select = Select(wd.find_element(By.ID, "ss_single"))
# 通过 Select 对象选中小雷老师
select.select_by_visible_text("小雷老师")
对于select多选框,要选中某几个选项,要注意去掉原来已经选中的选项。
可以用select类 的deselect_all方法,清除所有 已经选中 的选项,然后再通过 select_by_visible_text方法 选择需要选择的。
# 导入Select类
from selenium.webdriver.support.ui import Select
# 创建Select对象
select = Select(wd.find_element(By.ID, "ss_multi"))
# 清除所有 已经选中 的选项
select.deselect_all()
# 选择小雷老师 和 小凯老师
select.select_by_visible_text("小雷老师")
select.select_by_visible_text("小凯老师")
六、Selenium实战技巧
6.1、ActionChains模拟鼠标操作
之前我们对web元素做的操作主要是:选择元素,然后 点击元素 或者 输入 字符串。除了这些写常见的操作,还有其他操作,比如 鼠标右键点击、双击、移动鼠标到某个元素、鼠标拖拽等。
这些操作,可以通过 Selenium 提供的
ActionChains
类来实现。ActionChains 类 里面提供了 一些特殊的动作的模拟,我们可以通过 ActionChains 类的代码查看到。
使用 ActionChains 来 模拟鼠标移动 操作的代码如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('https://www.baidu.com/')
from selenium.webdriver.common.action_chains import ActionChains
ac = ActionChains(driver)
# 鼠标移动到 元素上
ac.move_to_element(
driver.find_element(By.CSS_SELECTOR, '[name="tj_briicon"]')
).perform()
6.2、冻结页面
有些网站上面的元素, 我们鼠标放在上面,会动态弹出一些内容。但是 当我们的鼠标 从 图标 移开, 这个 栏目就整个消失了, 就没法 查看 其对应的 HTML。
在 开发者工具栏 console 里面执行如下js代码
setTimeout(function(){debugger}, 5000)
表示在 5000毫秒后,执行 debugger 命令,执行该命令会 浏览器会进入debug状态。 debug状态有个特性, 界面被冻住, 不管我们怎么点击界面都不会触发事件。
6.3、弹出框处理
6.3.1、Alert 弹出框
Alert 弹出框,目的就是显示通知信息,只需用户看完信息后,点击 OK(确定) 就可以了。
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('https://cdn2.byhy.net/files/selenium/test4.html')
# --- alert ---
driver.find_element(By.ID, 'b1').click()
# 打印 弹出框 提示信息
print(driver.switch_to.alert.text)
# 点击 OK 按钮
driver.switch_to.alert.accept()
6.3.2、Confirm弹出框
Confirm弹出框,主要是让用户确认是否要进行某个操作。比如:当管理员在网站上选择删除某个账号时,就可能会弹出 Confirm弹出框, 要求确认是否确定要删除。Confirm弹出框 有两个选择供用户选择,分别是 OK 和Cancel, 分别代表 确定 和 取消 操作。
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('https://cdn2.byhy.net/files/selenium/test4.html')
# --- confirm ---
driver.find_element(By.ID, 'b2').click()
# 打印 弹出框 提示信息
print(driver.switch_to.alert.text)
# 点击 OK 按钮
driver.switch_to.alert.accept()
driver.find_element(By.ID, 'b2').click()
# 点击 取消 按钮
driver.switch_to.alert.dismiss()
6.3.3、Prompt 弹出框
出现 Prompt 弹出框 是需要用户输入一些信息,提交上去。这边的弹出框都不是HTLML,要是HTML可以直接获取元素进行操作。
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('https://cdn2.byhy.net/files/selenium/test4.html')
# --- prompt ---
driver.find_element(By.ID, 'b3').click()
# 获取 alert 对象
alert = driver.switch_to.alert
# 打印 弹出框 提示信息
print(alert.text)
# 输入信息,并且点击 OK 按钮 提交
alert.send_keys('web自动化 - selenium')
alert.accept()
# 点击 Cancel 按钮 取消
driver.find_element(By.ID, 'b3').click()
alert = driver.switch_to.alert
alert.dismiss()
七、Xpath选择器
还有一种 灵活、强大 的选择元素的方式,就是使用
Xpath
表达式。XPath (XML Path Language) 是由国际标准化组织W3C指定的,用来在 XML 和 HTML 文档中选择节点的语言。
7.1、绝对路径选择器
从根节点开始的,到某个节点,每层都依次写下来,每层之间用
/
分隔的表达式,就是某元素的
绝对路径。
上面的xpath表达式
/html/body/div
,就是一个绝对路径的xpath表达式, 等价于 css表达式
html>body>div
自动化程序要使用Xpath来选择web元素,应该调用 WebDriver对象的方法
find_element_by_xpath
或者
find_elements_by_xpath
,像这样:
elements = driver.find_elements(By.XPATH, "/html/body/div")
7.2、相对路径选择器
我们需要选择网页中某个元素,
不管它在什么位置
。比如,选择示例页面的所有标签名为
div
的元素,如果使用css表达式,直接写一个
div
就行了。
xpath需要前面加
//
, 表示从当前节点往下寻找所有的后代元素,不管它在什么位置。所以xpath表达式,应该这样写:
//div
‘//’ 符号也可以继续加在后面,比如,要选择 所有的 div 元素里面的 所有的 p 元素 ,不管div 在什么位置,也不管p元素在div下面的什么位置,则可以这样写
//div//p
对应的自动化程序如下:
elements = driver.find_elements(By.XPATH, "//div//p")
如果使用CSS选择器,对应代码如下:
elements = driver.find_elements(By.CSS_SELECTOR,"div p")
如果,要选择 所有的 div 元素里面的 直接子节点 p , xpath,就应该这样写了
//div/p
如果使用CSS选择器,则为
div > p
通配符
如果要选择所有div节点的所有直接子节点,可以使用表达式
//div/*
*
是一个通配符,对应任意节点名的元素,等价于CSS选择器
div > *
代码如下:
elements = driver.find_elements(By.XPATH, "//div/*")
for element in elements:
print(element.get_attribute('outerHTML'))
7.3、属性选择
Xpath 可以根据属性来选择元素。
根据属性来选择元素 是通过 这种格式来的
[@属性名='属性值']
注意:属性名注意前面有个@,属性值一定要用引号, 可以是单引号,也可以是双引号
选择 id 为 west 的元素,可以这样
//*[@id='west']
选择所有 select 元素中 class为 single_choice 的元素,可以这样
//select[@class='single_choice']
同样的道理,我们也可以利用其它的属性选择
比如选择 具有multiple属性的所有页面元素 ,可以这样
//*[@multiple]
要选择 style属性值 包含 color 字符串的 页面元素 ,可以这样
//*[contains(@style,'color')]
要选择 style属性值 以 color 字符串
开头
的 页面元素 ,可以这样
//*[starts-with(@style,'color')]
7.4、按次序选择
和CSS选择器类似,具体参考这个网站:Xpath选择器 | 白月黑羽
7.5、组选择、父节点、兄弟节点
和CSS选择器类似,具体参考这个网站:Xpath选择器 | 白月黑羽
版权归原作者 nuist__NJUPT 所有, 如有侵权,请联系我们删除。