- 自动化程序调用Selenium 客户端库函数(比如点击按钮元素)
- 客户端库会发送Selenium 命令 给浏览器的驱动程序
- 浏览器驱动程序接收到命令后 ,驱动浏览器去执行命令
- 浏览器执行命令
- 浏览器驱动程序获取命令执行的结果,返回给我们自动化程序
- 自动化程序对返回结果进行处理
Selenium环境的安装主要就是安装两样东西:
客户端库
和
浏览器驱动
。
pip install selenium
安装浏览器驱动需要根据浏览器的大版本选择,下载好后将驱动放在python根目录下即可,网上都有教程。
Selenium选择元素
根据元素id选择元素
如果取不到会抛出
selenium.common.exceptions.NoSuchElementException
异常
from selenium import webdriver
from selenium.webdriver.common.by import By
# 创建 WebDriver 对象
wd = webdriver.Chrome()
# 调用WebDriver 对象的get方法 可以让浏览器打开指定网址
wd.get('https://www.byhy.net/_files/stock1.html')
# 根据id选择元素,返回的就是该元素对应的WebElement对象
element = wd.find_element(By.ID, 'kw')
# 通过该 WebElement对象,就可以对页面元素进行操作了
# 比如输入字符串到 这个 输入框里
element.send_keys('通讯\n')
根据class属性选择元素
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对象
elements = wd.find_elements(By.CLASS_NAME, 'animal')
# 取出列表中的每个 WebElement对象,打印出其text属性的值
# text属性就是该 WebElement对象对应的元素在网页中的文本内容
for element in elements:
print(element.text)
根据tag名选择元素
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
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)
CSS Selector 语法选择元素
CSS Selector 语法 天生就是浏览器用来选择元素的,selenium自然就可以使用它用在自动化中,去选择要操作的元素了。只要 CSS Selector 的语法是正确的, Selenium 就可以选择到该元素。
利用css语法根据tag名选元素
elements = wd.find_elements(By.CSS_SELECTOR, 'div')
根据id属性
选择元素的语法是在id号前面加上一个井号: **
#id值
**
<input type="text" id='searchtext' />
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')
element = wd.find_element(By.CSS_SELECTOR, '#searchtext')
element.send_keys('你好')
根据class属性选择元素
选择元素的语法是在 class 值 前面加上一个点: **
.class值
**
elements = wd.find_elements(By.CSS_SELECTOR, '.animal')
选择子元素和后代元素
如果
元素2
是
元素1
的 直接子元素, CSS Selector 选择子元素的语法是这样的:
元素1 > 元素2
也支持更多层级的选择, 比如:
元素1 > 元素2 > 元素3 > 元素4
如果
元素2
是
元素1
的 后代元素, CSS Selector 选择后代元素的语法是这样的(也支持多层)
元素1 元素2
根据class,id等属性选择元素
css 选择器支持通过任何属性来选择元素,语法是用一个方括号
[]
。
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')
# 根据属性选择元素 选择属性href值为 http://www.miitbeian.gov.cn 的元素。
element = wd.find_element(By.CSS_SELECTOR, '[href="http://www.miitbeian.gov.cn"]')
# 打印出元素对应的html
print(element.get_attribute('outerHTML'))
也可以加上标签名作为限制,例如
#选择所有标签名为div,且class属性值为SKnet的元素。属性值用单引号,双引号都可以。
div[class='SKnet']
CSS 还可以选择属性值包含某个字符串的元素
#要选择a节点,里面的href属性包含了 miitbeian 字符串
a[href*="miitbeian"]
#选择a节点,里面的href属性以 http 开头
a[href^="http"]
#选择a节点,里面的href属性以 gov.cn 结尾
a[href$="gov.cn"]
如果一个元素具有多个属性,CSS选择器可以指定选择的元素要同时具有多个属性的限制。
div[class=misc][ctype=gun]
验证CSS Selector 语法
按ctrl+f可验证CSS表达式是否正确
选择语法可以联合使用
div.footer1 > span.copyright
.footer1 .copyright
CSS Selector组选择
同时选择所有class 为 plant
和
class 为 animal 的元素, 使用 “,”分割
.plant , .animal
CSS Selector按次序选择子节点
1.父元素的第n个子节点
span类型的第二个子节点
span:nth-child(2)
每个类型的第二个子节点
:nth-child(2)
2.父元素的倒数第n个子节点
p:nth-last-child(1)
3.父元素第n个某个类型的节点
span类型的第一个子节点
span:nth-of-type(1)
4.父元素倒数第n个子节点
p:nth-last-of-type(2)
5.奇数节点和偶数节点
偶数节点
p:nth-child(even)
奇数节点
p:nth-child(odd)
6.兄弟节点选择
相邻兄弟节点(与h3相邻的span)
h3 + span
后续所有兄弟节点选择(h3后面所有span兄弟节点)
h3 ~ span
radio框元素选择
radio框即单选按钮,在选择时直接用WebElement的click方法,模拟用户点击就可以了。
<div id="s_radio">
<input type="radio" name="teacher" value="小江老师">小江老师<br>
<input type="radio" name="teacher" value="小雷老师">小雷老师<br>
<input type="radio" name="teacher" value="小凯老师" checked="checked">小凯老师
</div>
# 获取当前选中的元素
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()
其中
#s_radio input[name="teacher"]:checked
里面的
:checked
是CSS伪类选择
表示选择
checked
状态的元素,对
radio
和
checkbox
类型的input有效。
checkbox框元素选择
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()
select框元素选择
select框即下拉列表,可以单选或多选,与以上两种不同,对于Select 选择框, Selenium 专门提供了一个Select类进行操作。
select_by_value
根据选项的value属性值 ,选择元素。
select_by_index
根据选项的次序(从0开始),选择元素。
select_by_visible_text
根据选项的可见文本 ,选择元素。
deselect_by_value
根据选项的value属性值, 去除选中元素
deselect_by_index
根据选项的次序,去除选中元素
deselect_by_visible_text
根据选项的可见文本,
去除
选中元素
deselect_all
去除
选中所有元素
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多选框,要选中某几个选项,要注意去掉原来已经选中的选项。
可以用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("小凯老师")
Xpath选择器
XPath (XML Path Language) 是由国际标准化组织W3C指定的,用来在 XML 和 HTML 文档中选择节点的语言。
目前主流浏览器 (chrome、firefox,edge,safari) 都支持XPath语法,xpath有 1 和 2 两个版本,目前浏览器支持的是 xpath 1的语法。
既然已经有了CSS,为什么还要学习 Xpath呢? 因为
- 有些场景 用 css 选择web 元素 很麻烦,而xpath 却比较方便。
- 另外 Xpath 还有其他领域会使用到,比如 爬虫框架 Scrapy, 手机App框架 Appium。
同样可以按f12打开调试窗口,点击 Elements标签,按组合键 Ctrl + F ,就会出现搜索框,在其中验证css语法是否正确。
xpath 语法中,整个HTML文档根节点用'/'表示,如果我们想选择的是根节点下面的html节点,则可以在搜索框输入:
/html
#选择html下面的body下面的div元素,/有点像CSS中的>,表示直接子节点关系。
/html/body/div
绝对路径选择
#每层之间用 / 分隔的表达式,就是某元素的绝对路径
elements = driver.find_elements(By.XPATH, "/html/body/div")
相对路径选择
选择示例页面的所有标签名为
div
的元素,如果使用css表达式,直接写一个
div
就行了。
那xpath怎么实现同样的功能呢? xpath需要前面加
//
, 表示从当前节点往下寻找所有的后代元素,不管它在什么位置。
所以xpath表达式,应该这样写:**
//div
**
要选择所有的 div元素里面的所有的 p 元素 ,不管div 在什么位置,也不管p元素在div下面的什么位置,则可以这样写 **
//div//p
**
#Xpath选择器
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'))
根据属性选择
Xpath 可以根据属性来选择元素。
根据属性来选择元素是通过这种格式来的**
[@属性名='属性值']
**
注意:
- 属性名注意前面有个@
- 属性值一定要用引号, 可以是单引号,也可以是双引号
** 根据id属性选择**
选择 id 为 west 的元素:可以这样:
//*[@id='west']
根据class属性选择
选择所有 select 元素中 class为 single_choice 的元素:
//select[@class='single_choice']
如果一个元素class 有多个,比如:
<p id="beijing" class='capital huge-city'>
北京
</p>
如果要选它, 对应的 xpath 就应该是
//p[@class="capital huge-city"]
不能只写一个属性,像这样 **
//p[@class="capital"]
** 则不行。
根据其他属性
同样的道理,我们也可以利用其它的属性选择
比如选择 具有multiple属性的所有页面元素 ,可以这样 **
//*[@multiple]
**
按次序选择
某类型 第几个 子元素
#要选择 p类型第2个的子元素,就是
//p[2]
#选取父元素为div 中的 p类型 第2个 子元素
//div/p[2]
#选择第2个子元素,不管是什么类型,采用通配符
//div/*[2]
选择的是p类型的第二个子元素,不是第二个子元素,并且是p类型。
某类型 倒数第几个 子元素
#选取p类型倒数第1个子元素
//p[last()]
#选取p类型倒数第2个子元素
//p[last()-1]
#选择父元素为div中p类型倒数第3个子元素
//div/p[last()-2]
范围选择
#选取option类型第1到2个子元素
//option[position()<=2]
//option[position()<3]
#选择class属性为multi_choice的前3个子元素
//*[@class='multi_choice']/*[position()<=3]
#选择class属性为multi_choice的后3个子元素
//*[@class='multi_choice']/*[position()>=last()-2]
为什么不是 last()-3 呢? 因为
last() 本身代表最后一个元素
last()-1本身代表倒数第2个元素
last()-2 本身代表倒数第3个元素
组选择
css 组选择,表达式之间用 逗号 隔开
xpath也有组选择, 是用 竖线 隔开多个表达式
#要选所有的option元素 和所有的 h4 元素,可以使用
//option | //h4
#等同于CSS选择器
option , h4
#要选所有的 class 为 single_choice 和 class 为 multi_choice 的元素,可以使用
//*[@class='single_choice'] | //*[@class='multi_choice']
#等同于CSS选择器
.single_choice , .multi_choice
选择父节点
xpath可以选择父节点, 这是css做不到的。
某个元素的父节点用**
/..
** 表示
比如,要选择 id 为 china 的节点的父节点,可以这样写:
//*[@id='china']/..
当某个元素没有特征可以直接选择,但是它有子节点有特征, 就可以采用这种方法,先选择子节点,再指定父节点。
还可以继续找上层父节点,比如:
//*[@id='china']/../../..
兄弟节点选择
前面学过 css选择器,要选择某个节点的后续兄弟节点,用波浪线
xpath也可以选择后续兄弟节点,用这样的语法**
following-sibling::
**
#要选择 class 为 single_choice 的元素的所有后续兄弟节点
//*[@class='single_choice']/following-sibling::*
#等同于CSS选择器
.single_choice ~ *
xpath还可以选择
前面的
兄弟节点,用这样的语法 **
preceding-sibling::
**
#要选择 class 为 single_choice 的元素的所有前面的兄弟节点
//*[@class='single_choice']/preceding-sibling::*
#要选择 class 为 single_choice 的元素的前面最靠近的兄弟节点
//*[@class='single_choice']/preceding-sibling::*[1]
而 CSS选择器 目前还没有方法选择前面的兄弟节点
这里注意:用Xpath在WebElement对象内部选择元素时,应在路径最前面加一个点“.”,如下:
elements = china.find_elements(By.XPATH, './/p')
frame切换
在html语法中,frame 元素 或者iframe元素的内部 会包含一个 被嵌入的 另一份html文档。
在我们使用selenium打开一个网页是, 我们的操作范围 缺省是当前的 html , 并不包含被嵌入的html文档里面的内容。
如果我们要操作被嵌入的 html 文档 中的元素, 就必须切换操作范围到被嵌入的文档中。
wd.switch_to.frame(frame_reference)
frame_reference 可以是 frame 元素的属性 name 或者 ID 。
wd.switch_to.frame('frame1')
wd.switch_to.frame('innerFrame')
也可以填写frame 所对应的 WebElement 对象。
wd.switch_to.frame(wd.find_element(By.TAG_NAME, "iframe"))
如果我们已经切换到某个iframe里面进行操作了,那么后续选择和操作界面元素 就都是在这个frame里面进行的。
这时候,如果我们又需要操作 主html(我们把最外部的html称之为主html) 里面的元素了呢?
wd.switch_to.default_content()
全部代码如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('https://cdn2.byhy.net/files/selenium/sample2.html')
# 先根据name属性值 'innerFrame',切换到iframe中
wd.switch_to.frame('innerFrame')
# 根据 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()
wd.quit()
窗口切换
在网页上操作的时候,我们经常遇到,点击一个链接或者按钮,就会打开一个新窗口。
可以使用Webdriver对象的switch_to属性的 window方法,如下所示:
wd.switch_to.window(handle)
其中,参数handle需要传入什么呢?
WebDriver对象有window_handles 属性,这是一个列表对象, 里面包括了当前浏览器里面所有的窗口句柄。
所谓句柄,大家可以想象成对应网页窗口的一个ID,
可以根据如下代码取到需要的handle:
for handle in wd.window_handles:
# 先切换到该窗口
wd.switch_to.window(handle)
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if 'Bing' in wd.title:
# 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
break
如果我们在新窗口操作完之后还要跳转回来,可以事先记录好当前窗口的handle,然后再做切换。
# mainWindow变量保存当前窗口的句柄
mainWindow = wd.current_window_handle
#通过前面保存的老窗口的句柄,自己切换到老窗口
wd.switch_to.window(mainWindow)
操控元素的基本方法
1.点击元素(click方法)
2.文本框输入(send_keys方法)
3.获取元素信息(元素.text属性)
5.获取元素属性值(元素的get_attribute(‘属性名’))
6.获取输入框中的文字(get_attribute('value'))
此外,Selenium 提供的
ActionChains
类来实现鼠标右键点击、双击、移动鼠标到某个元素、鼠标拖拽。
鼠标悬停
如小爱同学官网,如果想点击智能家居中的智能车载,必须先把鼠标移动到智能家居上,然后再下滑查看:
使用 ActionChains 来 模拟鼠标移动 操作的代码如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('https://xiaoai.mi.com/')
from selenium.webdriver.common.action_chains import ActionChains
ac = ActionChains(driver)
# 鼠标移动到 元素上
ac.move_to_element(
driver.find_element(By.CSS_SELECTOR, ' div.ant-col.heights > div > ul > li:nth-child(2)')
).perform()
版权归原作者 遇安♧ 所有, 如有侵权,请联系我们删除。