定位元素是任何与Web进行交互操作的基础,JavaScript
如是,对于Selenium
亦如是。只有定位到了元素,才能对元素进行操作。
Selenium
中的两个基础元素定位方法(find_element
与 find_elements
)
在Selenium
中使用find_element
与 find_elements
方法即可完成元素的定位。
我们先简单对比下这两个方法,再讲相关的细节:
find_element
:- 函数签名:
def find_element(self, by=By.ID, value=None):
- 函数参数:
by
为定位策略,value
为定位策略对应的定位器 - 调用对象:
WebDriver
实例或WebElement
对象 - 返回值:定位到元素时返回单个
WebElement
对象,没有定位到元素时抛出NoSuchElementException
异常
- 函数签名:
find_elements
:- 函数签名:
def find_elements(self, by=By.ID, value=None):
- 函数参数:
by
为定位策略,value
为定位策略对应的定位器 - 调用对象:
WebDriver
实例或WebElement
对象 - 返回值:定位到元素时返回
WebElement
对象列表,没有定位到元素时返回空列表
- 函数签名:
返回值的差异
从上述函数的基本特性可知,这两个方法的参数,调用对象完全一样,差别主要在返回值上。返回值上的差异跟JavaScript
中DOM的操作方法有些类似,element
返回单个对象,elements
返回对象列表,这是非常容易区别的差异。
find_element
定位到元素的话,仅返回单个WebElement
对象,没定位到元素就抛出异常。
find_elements
定位到元素时返回WebElement
对象列表,没有定位到元素时返回空列表。
调用对象
这两个方法的调用对象都可以为WebDriver
实例或WebElement
对象。
WebDriver
实例我们可以认为就是Selenium
启动的浏览器,这浏览器不单只是包含界面、控制等内容,最重要的是包含当前打开的页面。我们需要定位的元素(DOM 节点)就在这个页面中。因此,初始我们应该使用WebDriver
实例调用这两个元素定位方法定位元素,得到返回的页面元素WebElement
对象。由于页面元素是可以嵌套的,相应WebElement
对象应该也可以定位元素。
根据selenium\webdriver\remote\webdriver.py
和selenium\webdriver\remote\webelement.py
源码可知,WebDriver
对象和WebElement
对象都具有find_element
与 find_elements
方法。 在Selenium
中,这种设计方式被称为基于角色的接口。
Selenium
中的定位策略
在前面讲到的两个方法中,都具有By
参数,及定位策略 。Selenium
中的定位策略定义在selenium\webdriver\common\by.py
中。在使用定位策略时,可以导入By
类 from selenium.webdriver.common.by import By
class By(object):
"""
Set of supported locator strategies.
"""
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
定位器 Locator | 描述 |
---|---|
class name | 定位class属性与搜索值匹配的元素(不允许使用复合类名) |
css selector | 定位 CSS 选择器匹配的元素 |
id | 定位 id 属性与搜索值匹配的元素 |
name | 定位 name 属性与搜索值匹配的元素 |
link text | 定位link text可视文本与搜索值完全匹配的锚元素 |
partial link text | 定位link text可视文本部分与搜索值部分匹配的锚点元素。如果匹配多个元素,则只选择第一个元素。 |
tag name | 定位标签名称与搜索值匹配的元素 |
xpath | 定位与 XPath 表达式匹配的元素 |
在上述策略中:
id
、class name
、css selector
是比较推荐的策略,因为他们定位的范围较小。
xpath
定位在某些情况下可读性、灵活性不强,需要学习xpath
语法,但优势是大部分浏览器都支持复制元素的xpath
,这样就不用自己编写xpath
。
tag name
需要谨慎使用,因为按照标签名定位元素,往往返回大量元素。
link text
和 partial link text
官方都不太建议使用,使用场景狭窄,底层其实是使用xpath
实现的。
Selenium
中的快捷定位接口
虽然find_element
与 find_elements
方法已经可以实现元素的定位功能,但是操作来比较繁琐。
因此Selenium
根据8种不同的策略提供了16个快捷定位方法。
find_element_by_id(self, id_)
find_elements_by_id(self, id_)
find_element_by_name(self, name)
find_elements_by_name(self, name)
find_element_by_link_text(self, link_text)
find_elements_by_link_text(self, link_text)
find_element_by_partial_link_text(self, link_text)
find_elements_by_partial_link_text(self, link_text)
find_element_by_tag_name(self, name)
find_elements_by_tag_name(self, name)
find_element_by_xpath(self, xpath)
find_elements_by_xpath(self, xpath)
find_element_by_class_name(self, name)
find_elements_by_class_name(self, name)
find_element_by_css_selector(self, css_selector)
find_elements_by_css_selector(self, css_selector)
通过源码即可验证这些快捷方法与find_element
、find_elements
之间的关系。
def find_element_by_id(self, id_):
return self.find_element(by=By.ID, value=id_)
def find_elements_by_id(self, id_):
return self.find_elements(by=By.ID, value=id_)
简易案例
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
btn1 = driver.find_element(By.ID, "su")
print(type(btn1))
btns1 = driver.find_elements(By.ID, "su")
print(type(btns1), len(btns1), type(btns1[0]))
btn2 = driver.find_element_by_id("su")
print(type(btn2))
btns2 = driver.find_elements_by_id("su")
print(type(btns2), len(btns2), type(btns2[0]))