文章目录
- 引入
- 一.选择元素的基本方法
- 1.根据id 选择元素
- 2.根据 class属性选择元素
- 当元素有 多个class类型 时
- 3.根据 tag名 选择元素
- 4.通过WebElement对象选择元素
- 5.find_element 和 find_elements 的区别
- 二.等待界面元素出现
- 1.隐式等待
- 2.显示等待
- 三.操控元素的基本方法
- 1.点击元素
- 2.输入框
- 3.获取元素信息
- (1)获取元素的文本内容
- (2)获取元素属性
- (3)获取整个元素对应的HTML
- (4)获取输入框里面的文字
- (5)获取元素文本内容2
- 4.CSS Selector 语法选择元素
- 验证CSS Selector
- 5.选择 子元素 和 后代元素
- 6.根据属性选择
- 7.选择语法联合使用
- 8.组选择
- 9.按次序选择子节点
- (1)父元素的第n个子节点
- (2)父元素的倒数第n个子节点
- (3)父元素的第几个某类型的子节点
- (4)父元素的倒数第几个某类型的子节点
- (5)奇偶数节点
- 10.兄弟节点选择
- (1)相邻兄弟节点选择
- (2)后续所有兄弟节点选择
- 四.frame切换/窗口切换
- 五.文件上传
- 六.Xpath选择器
- 绝对路径选择
- 相对路径选择
- 通配符
- 根据属性选择
- 笔记来源
引入
pip install selenium
- 保证机器上有Chrome浏览器,下载对应浏览器的驱动
- Chrome浏览器驱动下载地址: http://chromedriver.storage.googleapis.com/index.html
- Firefox浏览器驱动下载地址:https://github.com/mozilla/geckodriver/releases/
- IE浏览器驱动下载地址:http://selenium-release.storage.googleapis.com/index.html
from selenium import webdriver
from selenium.webdriver.common.by import By# 打开Chome浏览器
wd = webdriver.Chrome()wd.get('https://www.baidu.com')# 关闭浏览器
wd.quit()
一.选择元素的基本方法
1.根据id 选择元素
# 根据id选择元素,返回的就是该元素对应的WebElement对象
element = wd.find_element(By.ID, 'kw')# 通过该 WebElement对象,就可以对页面元素进行操作了
# 比如输入字符串到 这个 输入框里
element.send_keys('通讯\n')
2.根据 class属性选择元素
举例:
<body> <div class="plant"><span>土豆</span></div><div class="plant"><span>洋葱</span></div><div class="plant"><span>白菜</span></div><div class="animal"><span>狮子</span></div><div class="animal"><span>老虎</span></div><div class="animal"><span>山羊</span></div></body>
如果我们要选择 所有的 动物, 就像下面可以这样写
【注意element后面多了个s】
wd.find_elements(By.CLASS_NAME, 'animal')
当元素有 多个class类型 时
<span class="chinese student">张三</span>
我们要用代码选择这个元素,可以指定任意一个class 属性值,都可以选择到这个元素,如下
element = wd.find_elements(By.CLASS_NAME,'chinese')
或者
element = wd.find_elements(By.CLASS_NAME,'student')
而不能这样写
element = wd.find_elements(By.CLASS_NAME,'chinese student')
3.根据 tag名 选择元素
类似的,我们可以通过指定 参数为 By.TAG_NAME
,选择所有的tag名为 div的元素,如下所示
from selenium import webdriver
from selenium.webdriver.common.by import Bywd = 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)
4.通过WebElement对象选择元素
WebElement对象 也可以调用 find_elements
, find_element
之类的方法。
WebDriver 对象 选择元素的范围是 整个 web页面, 而WebElement 对象 选择元素的范围是 该元素的内部。
element = wd.find_element(By.ID,'container')# 限制 选择元素的范围是 id 为 container 元素的内部。
spans = element.find_elements(By.TAG_NAME, 'span')
for span in spans:print(span.text)
5.find_element 和 find_elements 的区别
使用 find_elements
选择的是符合条件的 所有
元素, 如果没有符合条件的元素, 返回空列表
使用 find_element
选择的是符合条件的 第一个
元素, 如果没有符合条件的元素, 抛出 NoSuchElementException 异常
二.等待界面元素出现
在我们进行网页操作的时候, 有的元素内容不是可以立即出现的, 可能会等待一段时间,这时候找不到元素就会报错。
import time
while True:try:element = wd.find_element(By.ID,'1')print(element.text)breakexcept:time.sleep(1)
Selenium提供了一个更合理的解决方案,是这样的:
当发现元素没有找到的时候, 并不立即返回 找不到元素的错误。
而是周期性(每隔半秒钟)重新寻找该元素,直到该元素找到,
或者超出指定最大等待时长,这时才 抛出异常(如果是 find_elements
之类的方法, 则是返回空列表)。
1.隐式等待
Selenium 的 Webdriver 对象 有个方法叫 implicitly_wait
,可以称之为 隐式等待
,或者 全局等待
。
该方法接受一个参数, 用来指定 最大等待时长。
如果我们 加入如下代码
wd.implicitly_wait(10)
那么后续所有的 find_element
或者 find_elements
之类的方法调用 都会采用上面的策略:
如果找不到元素, 每隔 半秒钟 再去界面上查看一次, 直到找到该元素, 或者 过了10秒 最大时长。
完整案例如下
from selenium import webdriver
from selenium.webdriver.common.by import Bywd = 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')print(element.text)
2.显示等待
如果某个控件比较特殊,需要更长的时间加载,比如十几秒或者更长,就可以使用显示等待对其进行单独处理。
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
-
driver:浏览器驱动
-
timeout:最长超时时间,默认以秒为单位
-
poll_frequency:检测的间隔步长,默认为0.5s
-
ignored_exceptions:超时后的抛出的异常信息,默认抛出NoSuchElementExeception异常。
需要引入
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait()中的until()和until_not()
#调用该方法提供的驱动程序作为参数,直到返回值为True
WebDriverWait(driver,10).until(method,message="")
#调用该方法提供的驱动程序作为参数,直到返回值为False
WebDriverWait(driver,10).until_not(method,message="")
until是当某元素出现或什么条件成立则继续执行,
until_not是当某元素消失或什么条件不成立则继续执行,参数也相同。
实例:等待图片元素加载完成再进行点击关闭操作
wait = WebDriverWait(driver, 20)element = wait.until(EC.visibility_of_element_located((By.XPATH, '//img[@src="https://static.cdninstagram.com/rsrc.php/v3/yb/r/sHkePOqEDPz.gif"]')))time.sleep(1)driver.find_element(by=By.CSS_SELECTOR, value='svg[aria-label="Close"]').click()
三.操控元素的基本方法
操控元素通常包括
- 点击元素
- 在元素中输入字符串,通常是对输入框这样的元素
- 获取元素包含的信息,比如文本内容,元素的属性
1.点击元素
当我们调用 WebElement 对象的 click 方法去点击 元素的时候, 浏览器接收到自动化命令,点击的是该元素的
中心点
位置 。
2.输入框
element = wd.find_element(By.ID, "input1")element.clear() # 清除输入框已有的字符串
element.send_keys('alkaid') # 输入新字符串
3.获取元素信息
(1)获取元素的文本内容
通过WebElement对象的 text
属性,可以获取元素 展示在界面上的
文本内容。
比如
element = wd.find_element(By.ID, 'animal')
print(element.text)
(2)获取元素属性
通过WebElement对象的 get_attribute
方法来获取元素的属性值
比如要获取元素属性class的值,就可以使用 element.get_attribute('class')
如下:
element = wd.find_element(By.ID, 'input_name')
print(element.get_attribute('class'))
(3)获取整个元素对应的HTML
要获取整个元素对应的HTML文本内容,可以使用 element.get_attribute('outerHTML')
如果,只是想获取某个元素 内部
的HTML文本内容,可以使用 element.get_attribute('innerHTML')
(4)获取输入框里面的文字
对于input输入框的元素,要获取里面的输入文本,用text属性是不行的,这时可以使用 element.get_attribute('value')
比如
element = wd.find_element(By.ID, "input1")
print(element.get_attribute('value')) # 获取输入框中的文本
(5)获取元素文本内容2
通过WebElement对象的 text
属性,可以获取元素 展示在界面上的
文本内容。
但是,有时候,元素的文本内容没有展示在界面上,或者没有完全完全展示在界面上。 这时,用WebElement对象的text属性,获取文本内容,就会有问题。
出现这种情况,可以尝试使用 element.get_attribute('innerText')
,或者 element.get_attribute('textContent')
使用 innerText 和 textContent 的区别是,前者只显示元素可见文本内容,后者显示所有内容(包括display属性为none的部分)
4.CSS Selector 语法选择元素
通过 CSS Selector 选择单个元素的方法是
find_element(By.CSS_SELECTOR, CSS Selector参数)
选择所有元素的方法是
find_elements(By.CSS_SELECTOR, CSS Selector参数)
-
根据tag名选择元素:
比如 要选择 所有的tag名为div的元素,就可以是这样
elements = wd.find_elements(By.CSS_SELECTOR, 'div')
等价于
elements = wd.find_elements(By.TAG_NAME, 'div')
-
根据id属性选择元素:
语法是在id号前面加上一个井号:
#id值
element = wd.find_element(By.CSS_SELECTOR, '#id名')
-
根据class属性选择元素:
语法是在 class 值 前面加上一个点:
.class值
比如 这个网址 https://cdn2.byhy.net/files/selenium/sample1.html
要选择所有 class 属性值为 animal的元素 动物 除了这样写
elements = wd.find_elements(By.CLASS_NAME, 'animal')
还可以这样写
elements = wd.find_elements(By.CSS_SELECTOR, '.animal')
因为是选择
所有
符合条件的 ,所以用find_elements
而不是find_element
验证CSS Selector
F12,点击 Elements 标签后, 同时按 Ctrl 键 和 F 键
5.选择 子元素 和 后代元素
- 如果
元素2
是元素1
的 直接子元素, CSS Selector 选择子元素的语法是这样的
元素1 > 元素2
中间用一个大于号 (我们可以理解为箭头号)
注意,最终选择的元素是 元素2, 并且要求这个 元素2 是 元素1 的直接子元素
也支持更多层级的选择, 比如
元素1 > 元素2 > 元素3 > 元素4
就是选择 元素1
里面的子元素 元素2
里面的子元素 元素3
里面的子元素 元素4
, 最终选择的元素是 元素4
- 如果
元素2
是元素1
的 后代元素, CSS Selector 选择后代元素的语法是这样的
元素1 元素2
中间是一个或者多个空格隔开
6.根据属性选择
css 选择器支持通过任何属性来选择元素,语法是用一个方括号 []
。
举例
from selenium import webdriver
from selenium.webdriver.common.by import Bywd = webdriver.Chrome()wd.get('https://cdn2.byhy.net/files/selenium/sample1.html')# 根据属性选择元素
element = wd.find_element(By.CSS_SELECTOR, '[href="http://www.miitbeian.gov.cn"]')# 打印出元素对应的html
print(element.get_attribute('outerHTML'))
CSS 还可以选择 属性值 包含
某个字符串 的元素
比如, 要选择a节点,里面的href属性包含了 miitbeian 字符串,就可以这样写
a[href*="miitbeian"]
还可以 选择 属性值 以某个字符串 开头
的元素
比如, 要选择a节点,里面的href属性以 http 开头 ,就可以这样写
a[href^="http"]
还可以 选择 属性值 以某个字符串 结尾
的元素
比如, 要选择a节点,里面的href属性以 gov.cn 结尾 ,就可以这样写
a[href$="gov.cn"]
如果一个元素具有多个属性
<div class="misc" ctype="gun">沙漠之鹰</div>
CSS 选择器 可以指定 选择的元素要 同时具有多个属性的限制,像这样 div[class=misc][ctype=gun]
7.选择语法联合使用
比如, 我们要选择 网页 html 中的元素 <span class='copyright'>版权</span>
<div id='bottom'><div class='footer1'><span class='copyright'>版权</span><span class='date'>发布日期:2018-03-03</span></div><div class='footer2'><span>备案号<a href="http://www.miitbeian.gov.cn">苏ICP备88885574号</a></span></div>
</div>
CSS selector 表达式 可以这样写:
div.footer1 > span.copyright
就是 选择 一个class 属性值为 copyright 的 span 节点, 并且要求其 必须是 class 属性值为 footer1 的 div节点 的子节点
也可以更简单:
.footer1 > .copyright
就是 选择 一个class 属性值为copyright 的节点(不限类型), 并且要求其 必须是 class 属性值为 footer1 的节点的 子节点
当然 这样也是可以的:
.footer1 .copyright
因为子元素同时也是后代元素
8.组选择
如果我们要 同时选择所有class 为 plant 和
class 为 animal 的元素。怎么办?
这种情况,css选择器可以 使用 逗号
,称之为 组选择 ,像这样
.plant , .animal
再看一个例子,比如选择所有 id 为 t1 里面的 span 和 p 元素
我们是不是应该这样写呢?
#t1 > span,p
不行哦,这样写的意思是 选择所有 id 为 t1 里面的 span
和 所有的 p 元素
只能这样写
#t1 > span , #t1 > p
9.按次序选择子节点
(1)父元素的第n个子节点
我们可以指定选择的元素 是父元素的第几个子节点
使用 nth-child
如, 选择的是 第2个子元素,并且是span类型
所以这样可以这样写 span:nth-child(2)
,
如果你不加节点类型限制,直接这样写 :nth-child(2)
就是选择所有位置为第2个的所有元素,不管是什么类型
(2)父元素的倒数第n个子节点
选择的是父元素的 倒数第几个子节点
,使用 nth-last-child
比如:
p:nth-last-child(1)
就是选择第倒数第1个子元素,并且是p元素、
(3)父元素的第几个某类型的子节点
我们可以指定选择的元素 是父元素的第几个 某类型的
子节点
使用 nth-of-type
<div id='t1'><h3> 唐诗 </h3><span>李白</span><p>静夜思</p><span>杜甫</span><p>春夜喜雨</p> </div>
比如,
我们要选择 唐诗 和宋词 的第一个 作者,
可以像上面那样思考:选择的是 第2个子元素,并且是span类型
所以这样可以这样写 span:nth-child(2)
,
还可以这样思考,选择的是 第1个span类型
的子元素
所以也可以这样写 span:nth-of-type(1)
(4)父元素的倒数第几个某类型的子节点
使用 nth-last-of-type
像这样
p:nth-last-of-type(2)
(5)奇偶数节点
如果要选择的是父元素的 偶数节点
,使用 nth-child(even)
比如
p:nth-child(even)
如果要选择的是父元素的 奇数节点
,使用 nth-child(odd)
p:nth-child(odd)
如果要选择的是父元素的 某类型偶数节点
,使用 nth-of-type(even)
如果要选择的是父元素的 某类型奇数节点
,使用 nth-of-type(odd)
10.兄弟节点选择
(1)相邻兄弟节点选择
<h3> 唐诗 </h3><span>李白</span>
选择 h3 后面紧跟着的兄弟节点
span。
这就是一种 相邻兄弟 关系,可以这样写 h3 + span
表示元素 紧跟关系的 是 加号
(2)后续所有兄弟节点选择
如果要选择是 选择 h3 后面所有的兄弟节点
span,可以这样写 h3 ~ span
四.frame切换/窗口切换
暂略
五.文件上传
使用selenium自动化上传文件,我们只需要定位到该input元素,然后通过 send_keys 方法传入要上传的文件路径即可。
如下所示:
# 先定位到上传文件的 input 元素
ele = wd.find_element(By.CSS_SELECTOR, 'input[type=file]')# 再调用 WebElement 对象的 send_keys 方法
ele.send_keys(r'h:\g02.png')
但是,有的网页上传,是没有 file 类型 的 input 元素的。
【Selenimu+AutoIT】非input标签上传文件(带参数)
六.Xpath选择器
绝对路径选择
从根节点开始的,到某个节点,每层都依次写下来,每层之间用 /
分隔的表达式,就是某元素的 绝对路径
/html/body/div
,就是一个绝对路径的xpath表达式, 等价于 css表达式 html>body>div
相对路径选择
有的时候,我们需要选择网页中某个元素, 不管它在什么位置
。
xpath前面加 //
, 表示从当前节点往下寻找所有的后代元素,不管它在什么位置。
‘//’ 符号也可以继续加在后面,比如,要选择 所有的 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/*")
根据属性选择
根据属性来选择元素 是通过 这种格式来的 [@属性名='属性值']
注意:
- 属性名注意前面有个@
- 属性值一定要用引号, 可以是单引号,也可以是双引号
如:
elements = driver.find_element(by=By.XPATH, value='//div[@role="textbox"]')