Selenium详解

selenium 自动化流程如下:

  1. 自动化程序调用Selenium 客户端库函数(比如点击按钮元素)
  2. 客户端库会发送Selenium 命令 给浏览器的驱动程序
  3. 浏览器驱动程序接收到命令后 ,驱动浏览器去执行命令
  4. 浏览器执行命令
  5. 浏览器驱动程序获取命令执行的结果,返回给我们自动化程序
  6. 自动化程序对返回结果进行处理

 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()
  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值