Python + Selenium 小技巧之元素定位
<待完善>
在介绍元素定位之前,我们先来看看HTML的结构。以bilibili网站为例,来做说明。
我们通过浏览器自带的开发者工具
- HTML结构都是由标签对组成的
如:meta、html等都是标签名 - 标签有各种属性
如:type、name等都是属性名 - 标签对之间可以有文本数据
如:<title>哔哩哔哩 (゜-゜)つロ 干杯~-bilibili</title>
- 标签有层级关系
Selenium中的WebDriver,为我们提供了8种元素定位的方式,对应于Python中的方法如下:
定位方式 | Python中与之对应的方法 |
---|---|
id 定位 |
find_element_by_id() |
name 定位 |
find_element_by_name() |
class name 定位 |
find_element_by_class_name() |
tag name 定位 |
find_element_by_tag_name() |
link text 定位 |
find_element_by_link_text() |
partial link 定位 |
find_element_by_partial_link_text() |
XPath 定位 |
find_element_by_xpath() |
CSS Selector 定位 |
find_element_by_css_selector() |
八种定位方式及实践
01 id 定位
元素的id,就是身份证一样,在一个HTML页面中是唯一的,这将是最简单的定位方式。
示例:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
time.sleep(1)
cc = browser.find_element_by_id('su')
cc.click()
但是这里有一点要注意,虽然ID是唯一,但有时候它是动态变化的,如下就是一个动态 id 的例子。
这里的id值就是随机的,那么我们就得换一种定位方式了。
02 name 定位
示例:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
cc = browser.find_element_by_name('wd')
cc.send_keys('hello python')
03 class name 定位
示例:
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
cc = browser.find_element_by_class_name('s_ipt')
cc.send_keys('hello python')
04 tag name 定位
HTML通过tag来定义不同页面的元素。例如通常是用来定义输入框的,标签用来定义超链接的。
我们还是以百度为例,利用tag定位百度搜索框
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.find_element_by_tag_name('input')
这里有一点值得注意的是,一个页面中同一标签名的元素,可能会有很多,我们在定位时很难定位到符合我们需要的元素。
05 link text 定位
示例:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
cc = browser.find_element_by_link_text('新闻')
cc.click()
06 partial link 定位
示例:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
cc = browser.find_element_by_partial_link_text('闻')
cc.click()
07 XPath 定位
在XML文档中,XPath是一种定位元素的语言。因为HTML可以看作XML的一种实现,所以WebDriver提供了这种在Web应用中定位元素的方法。
7.1 绝对路径定位
示例:
如果你使用的是Chrome,可以按上图这个方法,把该元素的XPath信息拷贝出来。
第二处参考:https://www.kancloud.cn/guanfuchang/python_selenium/710818
7.2 利用元素属性定位
7.3 层级与属性结合
7.4 使用逻辑运算符
7.5 使用 contains 方法
7.6 使用 text() 方法
08 CSS Selector 定位
CSS是一种语言,用来描述HTML和XML文档的呈现样式。CSS使用选择器为页面元素绑定属性。
8.1 通过 class 定位
8.2 通过 id 定位
8.3 通过标签名定位
8.4 通过标签层级关系定位
8.5 通过属性定位
8.6 组合定位
更多定位用法
在元素定位之后,可以在开发者工具中的Elements页面,进行搜索,用相同的条件查询,以确保是唯一的。
利用 By 定位元素
针对上述的八种定义方法,WebDriver为我们提供了另一套写法,统一调用find_element()
方法,这需要借助By
来声明定位并传入与之对应的参数:
find_element(By.ID, )
find_element(By.NAME, )
find_element(By.CLASS_NAME, )
find_element(By.TAG_NAME, )
find_element(By.LINK_TEXT, )
find_element(By.PARTIAL_LINK_TEXT, )
find_element(By.XPATH, )
find_element(By.CSS_SELECTOR, )
当然了,在使用这种调用方式之前,需要导入By
:
from selenium.webdriver.common.by import By
以百度搜索输入框为例,具体说明各个定位方式的用法:
(通过chrome浏览器查看元素或者搜狐浏览器的firebug查看,即可看到html源码)
注意点:第三行的元素是灰色的,该元素是不可定位到的,下方会说明。
复制代码
1
2
3
4
5
6
7
8
复制代码
2.通过class_name定位元素
点击返回目录
classname有可能重复哦。
使用:find_element_by_class_name(“class_name_vaule”)
实例:find_element_by_class_name(“s_ipt”)
3.通过tag_name定位元素
点击返回目录
标签名字最容易重复,不过,当定位一组数据时,可使用。
使用:find_element_by_tag_name(“tag_name_vaule”)
实例:find_element_by_tag_name(“input”)
注意点:当定位一组元素时:可勾选一组复选框。如下:
find_element_by_tag_name(“input”)
复制代码
checkbox
4.通过name定位元素
点击返回目录
name有可能会重复哦。
使用:find_element_by_name(“name_vaule”)
实例:find_element_by_name(“wd”)
5.通过link文字精确定位元素
点击返回目录
登录
使用:find_element_by_link_text(“text_vaule”)
实例:find_element_by_link_text(“登录”)
6.通过link文字模糊定位元素
点击返回目录
使用:find_element_by_partial_link_text(“部分text_vaule”)
实例:find_element_by_partial_link_text(“登”)
7.通过CSS定位元素
点击返回目录
可查看我的另外一篇博文:w3school之CSS学习笔记 学习css知识,更加有助于定位。
CSS(Cascading Style Sheets)是一种语言,它用来描述HTML和XML文档的表现。CSS可以较为灵活的选择控件的任意属性,一般情况下会比XPath快。且语法也比较简洁。
不过CSS对于初学者而言比较复杂。
使用:find_element_by_css_selector(“CSS”)
实例:
7.1通过id属性定位元素
#号表示通过id属性来定位元素
find_element_by_css_selector(“#kw”)
7.2通过class属性定位元素
.号表示通过class属性来定位元素
find_element_by_css_selector(“.s_ipt”)
7.3通过标签名定位元素
find_element_by_css_selector(“input”)
7.4通过属性定位元素(挺常用的)
find_element_by_css_selector(“[name=’wd’]”)
find_element_by_css_selector(“[maxlength=’255’]”)
属性值包含某个值
属性值包含wd:适用于由空格分隔的属性值。
find_element_by_css_selector(“[name~=’wd’]”)
7.5父子定位元素
查找有父亲元素的标签名为span,它的所有标签名叫input的子元素
find_element_by_css_selector(“span>input”)
7.6组合定位元素
标签名#id属性值:指的是该input标签下id属性为kw的元素
find_element_by_css_selector(“input#kw”)
标签名.class属性值:指的是该input标签下class属性为s_ipt的元素
find_element_by_css_selector(“input.s_ipt”)
标签名[属性=’属性值‘]:指的是该input标签下name属性为wd的元素
find_element_by_css_selector(“input[name=’wd’]”)
父元素标签名>标签名.class属性值:指的是span下的input标签下class属性为s_ipt的元素
find_element_by_css_selector(“span>input.s_ipt”)
多个属性组合定位元素(挺常用的)
指的是input标签下id属性为kw且name属性为wd的元素
find_element_by_css_selector(“input.s_ipt[name=’wd’]”)
指的是input标签下name属性为wd且maxlength为255的元素
find_element_by_css_selector(“input[name=’wd’][maxlength=’255’]”)
比较复杂的CSS定位可查看
http://www.360doc.com/content/13/1105/10/11675837_326750173.shtml
http://www.360doc.com/content/13/1105/10/11675837_326750240.shtml
比较懒惰的方法:
使用搜狐浏览器的firebug工具,复制CSS路径,不过这种方式对层级要求高,到时候自己再修改下。
8.通过XPath定位元素
点击返回目录
XPath是一种XML文档中定位元素的语言。该定位方式也是比较常用的定位方式。
使用:find_element_by_xpath(“XPath”)
实例:
8.1通过属性定位元素
find_element_by_xpath(“//标签名[@属性=’属性值’]”)
id属性:
find_element_by_xpath(“//input[@id=’kw’]”)
class属性:
find_element_by_xpath(“//input[@class=’s_ipt’]”)
name属性:
find_element_by_xpath(“//input[@name=’wd’]”)
maxlength属性:
find_element_by_xpath(“//input[@maxlength=’255’]”)
8.2通过标签名定位元素
指所有input标签元素
find_element_by_xpath(“//input”)
8.3父子定位元素
查找有父亲元素的标签名为span,它的所有标签名叫input的子元素
find_element_by_xpath(“//span/input”)
8.4根据元素内容定位元素(非常实用)
find_element_by_xpath(“//p[contains(text(),’京公网’)]”)
京公网安备11000002000001号
注:contains的另一种用法//input[contains(@class,’s’)]
说明class属性包含s的元素。
8.5组合定位元素
//父元素标签名/标签名的属性值:指的是span下的input标签下class属性为s_ipt的元素
find_element_by_xpath(“//span/input[@class=’s_ipt’]”)
多个属性组合定位(挺常用的)
指的是input标签下id属性为kw且name属性为wd的元素
find_element_by_xpath(“//input[@class=’s_ipt’ and @name=’wd’]”)
指的是p标签下内容包含“京公网”且id属性为jgwab的元素
find_element_by_xpath(“//p[contains(text(),’京公网’) and @id=’jgwab’]”)
比较懒惰的方法:
使用搜狐浏览器的firebug工具,复制XPath路径,不过这种方式对层级要求高,到时候自己再修改下。
9.通过By定位元素
点击返回目录
使用:find_element(定位的类型,具体定位方式)
定位的类型包括By.ID,By.NAME,By.CLASS_NAME,By.TAG_NAME,By.LINK_TEXT,By.PARTIAL_LINK_TEXT,By.XPATH,By.CSS_SELECTOR
具体定位方式参考上方1-8的说明。
实例:find_element(By.ID,’kw’)
注意:使用By定位方式,需先导入By类。
from selenium.webdriver.common.by import By
10.具体实例说明
点击返回目录
下方例子是登陆126邮件,然后发送邮件。
复制代码
1 # coding=utf-8
2 ‘’’
3 Created on 2016-7-27
4 @author: Jennifer
5 Project:发送邮件
6 ‘’’
7 from selenium import webdriver
8 import time
9
10 from test_5_2_public import Login #由于公共模块文件命名为test_5_2_public
11 driver=webdriver.Firefox()
12 driver.implicitly_wait(30)
13 driver.get(r’http://www.126.com/') #字符串加r,防止转义。
14 time.sleep(3)
15 driver.switch_to.frame(‘x-URS-iframe’)
16 #调用登录模块
17 Login().user_login(driver)
18 time.sleep(10)
19 #发送邮件
20 #点击发件箱
21 #mail_component_61_61是动态id,所以不能用于定位
22 #driver.find_element_by_css_selector(‘#mail_component_61_61>span.oz0’).click()
23 #不能加u”//span[contains(text(),u’写 信’)]”,否则定位不到。
24 #以下定位是查找span标签有个文本(text)包含(contains)’写 信’ 的元素,该定位方法重要
25 driver.find_element_by_xpath(“//span[contains(text(),’写 信’)]”).click()
26 #填写收件人
27 #driver.find_element_by_class_name(‘nui-editableAddr-ipt’).send_keys(r’xxx@doov.com.cn’)
28 driver.find_element_by_class_name(‘nui-editableAddr-ipt’).send_keys(r’xxx@163.com’)
29 #填写主题
30 #通过and连接更多的属性来唯一地标志一个元素
31 driver.find_element_by_xpath(“//input[@class=’nui-ipt-input’ and @maxlength=’256’]”).send_keys(u’自动化测试’)
32 #填写正文
33 #通过switch_to_frame()将当前定位切换到frame/iframe表单的内嵌页面中
34 driver.switch_to_frame(driver.find_element_by_class_name(‘APP-editor-iframe’))
35 #在内嵌页面中定位邮件内容位置
36 emailcontext=driver.find_element_by_class_name(‘nui-scroll’)
37 #填写邮件内容
38 emailcontext.send_keys(u’这是第一封自动化测试邮件’)
39 #通过switch_to().default_content()跳回最外层的页面
40 #注:不要写成switch_to().default_content(),否则报AttributeError: SwitchTo instance has no __call method
41 driver.switch_to.default_content()
42 #driver.switch_to.parent_frame()
43 #点击发送
44 time.sleep(3)
45 #有可能存在元素不可见(查看元素是灰色的),会报ElementNotVisibleException错误
46 #包含发送二字的元素很多,所以还得再加上其他限制
47 #sendemails=driver.find_element_by_xpath(“//span[contains(text(),’发送’)]”)
48 sendemails=driver.find_element_by_xpath(“//span[contains(text(),’发送’) and @class=’nui-btn-text’]”)
49 time.sleep(3)
50
51 #校验邮件是否发送成功
52 try:
53 assert ‘发送成功’ in driver.page_source
54 except AssertionError:
55 print ‘邮件发送失败’
56 else:
57 print ‘邮件发送成功’
58
59 #调用退出模块
60 Login().user_logout(driver)
复制代码
元素定位说明:
1.代码22行,定位不到是因为id是动态的,所以需采取其他方式定位元素。
2.代码25行,是根据元素内容来定位的,具体用法详看8.4.
3.代码28行,是根据class名来定位元素的,由于该值在该页面上是唯一的,所以可以用它来定位。
4.代码31行,是使用逻辑运算符and连接更多的属性从而唯一的标志一个元素,具体用法详看8.5.
5.代码34行,由于使用内嵌的iframe框架,所以需要先使用switch_to_frame()移到该表单上,才能定位该表单上的元素,非常重要,否则无论怎么定位都会报“NoSuchElementException”,找不到该元素。
6.代码41行,跳出iframe框架,当框架内的动作操作完毕后,需要使用switch_to.default_content跳出iframe框架,非常重要。
7.代码47行,由于内容包括“发送”的元素中包含不可见元素(html查看元素可以看到此行是灰色的),这样有可能定位到不可见元素,会报“ElementNotVisibleException”。
8.代码48行,是使用逻辑运算符and连接更多的属性从而唯一的标志一个元素,具体用法详看8.5.这样可以排除掉那个不可见元素。
https://www.cnblogs.com/yufeihlf/p/5717291.html
定位一组元素
定位一组元素,与定位单个元素,唯一的差别,所使用的方法中element单词有没有加s
| id
定位 | find_elements_by_id()
|
| name
定位 | find_elements_by_name()
|
| class name
定位 | find_elements_by_class_name()
|
| tag name
定位 | find_elements_by_tag_name()
|
| link text
定位 | find_elements_by_link_text()
|
| partial link
定位 | find_elements_by_partial_link_text()
|
| XPath
定位 | find_elements_by_xpath()
|
| CSS Selector
定位 | find_elements_by_css_selector()
|