Selenium Locating

Feb 26th, 2020 - Now

根据xxx查找元素

在浏览器上查找一处元素,使用 webdriver.find_element_by_xxx 的形式,具体而言有如下几种(按照自己的使用频率排序):

find_element_by_xpath()

原称之为最强大最傻瓜式的查找方式,一招毙命,实在想不到为什么还有其他的方式存在(误 在 chrome 中定位到想要的对象,右键 copy->copy full XPath 作为参数即可 这里注意 copy 中有两个选择,一个是 copy XPath 一个是 copy full XPath 由于有一些网页上可能会存在除了功能什么都一样的元素,如:一个搜索框搜索 Project,一个搜索框搜索 Owner 这时候使用单纯的 copy XPath 可能两者是一样的,都是 xxx_search ,这就导致会去定位第一个找到的搜索框 所以 copy full XPth 是最保险的选择,直接返回从 html 开始的 XPath e.g. copy XPath->//*[@id="rightmenu"]/ul[2]/li[2] copy full XPath->/html/body/div[3]/ul[2]/li[2]

那么为什么还需要其他方式呢?自己想了两点: 1. 查找一类元素,如爬贴吧的每个分类里面的帖子,肯定就不能每次定位一个确切的 XPath 了,而是要根据 class 或者 tag 找到一个 list 然后逐个爬取。 2. 效率慢,XPath 是直接逐级往下进行查找,每次查找(估计)都要将里面的所有tag整理出来,导致进度缓慢。

find_element_by_css_selector()

首先看懂 CSS 语句:

<div id='inner'>呵呵呵</div> : <type> 是 <div>,其 <id> 为 'inner'
<a href='http://www.baidu.com'>百度一下</a> : <type> 是 <a>,其中有个 [href] 的属性值是 'http://www.baidu.com'  
<li class='two three four'>Two</li> : <type> 是 <li>,其属于 'two' 'three' 'four' 三种 <class>

基本CSS选择器

选择器

描述

举例

*

通配选择器,选择所有的元素

*

<type>

选择特定类型的元素,支持基本HTML标签

h1

.<class>

选择具有特定class的元素。

.class1

<type>.<class>

特定类型和特定class的交集。 直接将多个选择器连着一起表示交集

h1.class1

#<id>

选择具有特定id属性值的元素

#id1

属性选择器

选择器

描述

举例

[attr]

选取定义attr属性的元素,即使该属性没有值

[placeholder]

[attr="val"]

选取attr属性等于val的元素

[placeholder="请输入关键词"]

[attr^="val"]

选取attr属性开头为val的元素

[placeholder^="请输入"]

[attr$="val"]

选取attr属性结尾为val的元素

[placeholder$="关键词"]

[attr*="val"]

选取attr属性包含val的元素

[placeholder*="入关"]

[attr~="val"]

选取attr属性包含多个空格分隔的属性,其中一个等于val的元素

[placeholder~="关键词"]

关系选择器

选择器

描述

举例

<selector> <selector>

第二个选择器为第一个选择器的后代元素 选取第二个选择器匹配结果

.class1 h1

<selector> > <selector>

第二个选择器为第一个选择器的直接子元素 选取第二个选择器匹配结果

.class1 > *

<selector> + <selector>

第二个选择器为第一个选择器的兄弟元素 选取第二个选择器的下一兄弟元素

.class1 + [lang]

<selector> ~ <selector>

第二个选择器为第一个选择器的兄弟元素 选取第二个选择器的全部兄弟元素

.class1 ~ [lang]

联合选择器与反选择器

选择器

描述

举例

<selector>,<selector>

属于第一个选择器的元素 或者是属于第二个选择器的元素

h1, h2

:not(<selector>)

不属于选择器选中的元素

:not(html)

find_element_by_tag_name()

find_element_by_class_name()

find_element_by_name()

find_elements_by_xxx()

每种方法还有对应的 find_elements_by_xxx 的查找多元素的方法,可以找到整个html页面中满足搜索条件的元素并返回一个 list[]。

查找元素是否存在

有两种方法: 1. 通过 find_elements_by_xxx() 寻找并返回一个数组,如果数组长度为0则没有找到 2. 通过 find_element_by_xxx() 是否抛出异常来判断是否存在

无法找到元素

找不到自己想要的元素的时候可以通过:

elements = b.find_elements_by_xxx() # 注意是 elements
for i in elements:  
    print(elements)
    print(elements.text)

来寻找所有有 xxx 属性的元素,检查自己的元素是否在内,如果元素都不在内,说明很大问题,接着下面。

特殊样式的查找

iframe 框架

查看要寻找的元素前后,是否存在一个 <iframe> 的东西,如果是,可能就是被 iframe 阻挡了.

也就是说,当前你的 browser 只能看到一个最外部的框架,可能可以读到 iframe,但是 iframe 内部的内容被遮挡了,这种框架通常出现在SAP系统,QQ邮箱等地方。 解决方法

driver.switch_to_frame('iframe标签的name或id') (*)
driver.find_element_by_xxx('what u need')

通过加一个 switch_to_frame() 的方式就可以进入到框架内去查找了。

嵌套 iframe

嵌套:f1中嵌套着f2

driver.switch_to_frame("f1")  
driver.switch_to_frame("f2")

退出 iframe

# 第一种方式:跳出所有iframe,回到主界面
driver.switch_to_default_content()

# 第二种方式:回到f1(返回上一级)
driver.switch_to.parent_frame()

table 类

对于表格而言,我们是难以直接定位到里面的元素的,因为可能一个 <table> 中的多个 <td><tr> 都没有id,只有顺序,所以这个时候我们要先定位到 <table> 然后根据当前的 <table> 定位查找其子元素。

# 定位到table,并获得table中所有得tr元素
menu_table = self.driver.find_element_by_xpath("xxx/table")
rows = menu_table.find_elements_by_tag_name('tr')

# python 的len()函数返回对象(字符、列表、元组)的长度或者元素得个数
before_add_numbers = len(rows)
print(before_add_numbers)
pos=0 # 正确点个数
neg=0 # 错误点个数
# 等待测试点的表出现
element = wait.until(
    EC.presence_of_element_located((
        By.XPATH, '//*[@id="app"]/div[2]/div/div/div/div[2]/div[1]/div/table')))  

# 获取测试点的表
menu_table=b.find_element_by_xpath(
    '//*[@id="app"]/div[2]/div/div/div/div[2]/div[1]/div/table')

rows=menu_table.find_elements_by_tag_name('tr')

# 对表的每一行进行遍历
for ii in rows:
    tds=ii.find_elements_by_css_selector('tr td pre') # 根据css深层定位
    for j in tds:
        # 正确加一个
        if j.text=='ACCEPTED': # j.text 就是元素的文字
            pos += 1
        elif j.text=='WRONG ANSWER':
            neg += 1

Reference

Last updated