定位器策略
定位器是识别页面上元素的一种方法。它是传递给查找元素方法的参数。
查看我们的推荐的测试实践,获取关于定位器的提示,包括何时使用哪个定位器以及为什么要将定位器与查找方法分开声明。
传统的定位器
Selenium 在 WebDriver 中为这 8 种传统的定位策略提供支持
定位器 | 描述 |
---|---|
类名 | 定位类名包含搜索值的元素(不允许复合类名) |
CSS 选择器 | 定位与 CSS 选择器匹配的元素 |
ID | 定位 ID 属性与搜索值匹配的元素 |
名称 | 定位 NAME 属性与搜索值匹配的元素 |
链接文本 | 定位可见文本与搜索值匹配的锚元素 |
部分链接文本 | 定位可见文本包含搜索值的锚元素。如果多个元素匹配,则只选择第一个元素。 |
标签名 | 定位标签名与搜索值匹配的元素 |
xpath | 定位与 XPath 表达式匹配的元素 |
创建定位器
要使用 Selenium 处理 Web 元素,我们需要首先在网页上定位它。Selenium 为我们提供了上述方法,我们可以使用这些方法来定位页面上的元素。为了理解和创建定位器,我们将使用以下 HTML 代码段。
<html>
<body>
<style>
.information {
background-color: white;
color: black;
padding: 10px;
}
</style>
<h2>Contact Selenium</h2>
<form>
<input type="radio" name="gender" value="m" />Male
<input type="radio" name="gender" value="f" />Female <br>
<br>
<label for="fname">First name:</label><br>
<input class="information" type="text" id="fname" name="fname" value="Jane"><br><br>
<label for="lname">Last name:</label><br>
<input class="information" type="text" id="lname" name="lname" value="Doe"><br><br>
<label for="newsletter">Newsletter:</label>
<input type="checkbox" name="newsletter" value="1" /><br><br>
<input type="submit" value="Submit">
</form>
<p>To know more about Selenium, visit the official page
<a href ="www.selenium.dev">Selenium Official Page</a>
</p>
</body>
</html>
类名
HTML 页面 Web 元素可以具有类属性。我们可以在上面显示的 HTML 代码段中看到一个示例。我们可以使用 Selenium 中提供的类名定位器来识别这些元素。
WebDriver driver = new ChromeDriver();
driver.findElement(By.className("information"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.CLASS_NAME, "information")
var driver = new ChromeDriver();
driver.FindElement(By.ClassName("information"));
driver.find_element(class: 'information')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.className('information'));
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.className("information"))
CSS 选择器
CSS 是用于设置 HTML 页面样式的语言。我们可以使用 css 选择器定位策略来识别页面上的元素。如果该元素具有 id,我们将定位器创建为 css = #id。否则,我们遵循的格式是 css =[attribute=value]。让我们看一个上面 HTML 代码段的示例。我们将使用 css 为名字文本框创建定位器。
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("#fname"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.CSS_SELECTOR, "#fname")
var driver = new ChromeDriver();
driver.FindElement(By.CssSelector("#fname"));
driver.find_element(css: '#fname')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.css('#fname'));
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.css("#fname"))
ID
我们可以使用网页上元素的 ID 属性来定位它。通常,ID 属性对于网页上的每个元素都应该是唯一的。我们将使用它来识别姓氏字段。
WebDriver driver = new ChromeDriver();
driver.findElement(By.id("lname"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.ID, "lname")
var driver = new ChromeDriver();
driver.FindElement(By.Id("lname"));
driver.find_element(id: 'lname')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.id('lname'));
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.id("lname"))
名称
我们可以使用网页上元素的 NAME 属性来定位它。通常,NAME 属性对于网页上的每个元素都应该是唯一的。我们将使用它来识别新闻通讯复选框。
WebDriver driver = new ChromeDriver();
driver.findElement(By.name("newsletter"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.NAME, "newsletter")
var driver = new ChromeDriver();
driver.FindElement(By.Name("newsletter"));
driver.find_element(name: 'newsletter')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.name('newsletter'));
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.name("newsletter"))
链接文本
如果要定位的元素是一个链接,我们可以使用链接文本定位器在网页上识别它。链接文本是链接显示的文本。在共享的 HTML 代码段中,我们有一个可用的链接,让我们看看如何定位它。
WebDriver driver = new ChromeDriver();
driver.findElement(By.linkText("Selenium Official Page"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.LINK_TEXT, "Selenium Official Page")
var driver = new ChromeDriver();
driver.FindElement(By.LinkText("Selenium Official Page"));
driver.find_element(link_text: 'Selenium Official Page')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.linkText('Selenium Official Page'));
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.linkText("Selenium Official Page"))
部分链接文本
如果要定位的元素是一个链接,我们可以使用部分链接文本定位器在网页上识别它。链接文本是链接显示的文本。我们可以将部分文本作为值传递。在共享的 HTML 代码段中,我们有一个可用的链接,让我们看看如何定位它。
WebDriver driver = new ChromeDriver();
driver.findElement(By.partialLinkText("Official Page"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.PARTIAL_LINK_TEXT, "Official Page")
var driver = new ChromeDriver();
driver.FindElement(By.PartialLinkText("Official Page"));
driver.find_element(partial_link_text: 'Official Page')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.partialLinkText('Official Page'));
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.partialLinkText("Official Page"))
标签名
我们可以使用 HTML 标签本身作为定位器来识别页面上的 Web 元素。从上面共享的 HTML 代码段中,让我们使用其 html 标签“a”来识别该链接。
WebDriver driver = new ChromeDriver();
driver.findElement(By.tagName("a"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.TAG_NAME, "a")
var driver = new ChromeDriver();
driver.FindElement(By.TagName("a"));
driver.find_element(tag_name: 'a')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.tagName('a'));
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.tagName("a"))
xpath
可以将 HTML 文档视为 XML 文档,然后我们可以使用 xpath,这将是遍历到要定位的元素的路径。XPath 可以是绝对 xpath,它是从文档的根创建的。示例 - /html/form/input[1]。这将返回男性单选按钮。或者 xpath 可以是相对的。示例 - //input[@name=‘fname’]。这将返回名字文本框。让我们使用 xpath 为女性单选按钮创建定位器。
WebDriver driver = new ChromeDriver();
driver.findElement(By.xpath("//input[@value='f']"));
driver = webdriver.Chrome()
driver.get("https://seleniumcn.cn/selenium/web/locators_tests/locators.html")
element = driver.find_element(By.XPATH, "//input[@value='f']")
var driver = new ChromeDriver();
driver.FindElement(By.Xpath("//input[@value='f']"));
driver.find_element(xpath: "//input[@value='f']")
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.xpath('//input[@value='f']'));
import org.openqa.selenium.By
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.xpath('//input[@value='f']'))
利用定位器
FindElement 使使用定位器变得轻而易举!对于大多数语言,您只需利用 webdriver.common.by.By
,但在其他语言中,它就像在 FindElement 函数中设置参数一样简单
By
import org.openqa.selenium.By;
WebDriver driver = new ChromeDriver();
driver.findElement(By.className("information"));
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.find_element(By.CLASS_NAME, "information")
var driver = new ChromeDriver();
driver.FindElement(By.ClassName("information"));
driver.find_element(class: 'information')
let driver = await new Builder().forBrowser('chrome').build();
const loc = await driver.findElement(By.className('information'));
import org.openqa.selenium.By
val driver = ChromeDriver()
val loc: WebElement = driver.findElement(By.className("information"))
ByChained
ByChained
类使您可以将两个 By 定位器链接在一起。例如,您不必定位父元素,然后定位该父元素的子元素,而是可以将这两个 FindElement()
函数合并为一个。
By example = new ByChained(By.id("login-form"), By.id("username-field"));
WebElement username_input = driver.findElement(example);
ByAll
ByAll
类使您可以同时利用两个 By 定位器,查找与 任一 By 定位器匹配的元素。例如,您不必使用两个 FindElement()
函数分别查找用户名和密码输入字段,而是可以在一个简洁的 FindElements()
中一起查找它们
By example = new ByAll(By.id("password-field"), By.id("username-field"));
List<WebElement> login_inputs = driver.findElements(example);
相对定位器
Selenium 4 引入了相对定位器(以前称为友好定位器)。当不容易为所需元素构造定位器时,这些定位器很有帮助,但很容易描述元素在空间上相对于具有易于构造的定位器的元素的位置。
工作原理
Selenium 使用 JavaScript 函数 getBoundingClientRect() 来确定页面上元素的大小和位置,并可以使用此信息来定位相邻元素。
相对定位器方法可以将先前定位的元素引用或另一个定位器作为原点的参数。在这些示例中,我们只使用定位器,但您可以将最后一个方法中的定位器替换为元素对象,它的工作方式相同。
让我们考虑以下示例以了解相对定位器。

可用的相对定位器
上方
如果出于某种原因,电子邮件文本字段元素不容易识别,但密码文本字段元素很容易识别,我们可以使用它是一个“输入”元素“位于”密码元素“上方”的事实来定位文本字段元素。
By emailLocator = RelativeLocator.with(By.tagName("input")).above(By.id("password"));
email_locator = locate_with(By.TAG_NAME, "input").above({By.ID: "password"})
var emailLocator = RelativeBy.WithLocator(By.TagName("input")).Above(By.Id("password"));
driver.find_element({relative: {tag_name: 'input', above: {id: 'password'}}})
let emailLocator = locateWith(By.tagName('input')).above(By.id('password'));
val emailLocator = RelativeLocator.with(By.tagName("input")).above(By.id("password"))
下方
如果出于某种原因,密码文本字段元素不容易识别,但电子邮件文本字段元素很容易识别,我们可以使用它是一个“输入”元素“位于”电子邮件元素“下方”的事实来定位文本字段元素。
By passwordLocator = RelativeLocator.with(By.tagName("input")).below(By.id("email"));
password_locator = locate_with(By.TAG_NAME, "input").below({By.ID: "email"})
var passwordLocator = RelativeBy.WithLocator(By.TagName("input")).Below(By.Id("email"));
driver.find_element({relative: {tag_name: 'input', below: {id: 'email'}}})
let passwordLocator = locateWith(By.tagName('input')).below(By.id('email'));
val passwordLocator = RelativeLocator.with(By.tagName("input")).below(By.id("email"))
左侧
如果由于某种原因取消按钮不容易识别,但提交按钮元素容易识别,我们可以使用取消按钮元素是位于提交元素“左侧”的“按钮”元素这一事实来定位取消按钮元素。
By cancelLocator = RelativeLocator.with(By.tagName("button")).toLeftOf(By.id("submit"));
cancel_locator = locate_with(By.TAG_NAME, "button").to_left_of({By.ID: "submit"})
var cancelLocator = RelativeBy.WithLocator(By.tagName("button")).LeftOf(By.Id("submit"));
driver.find_element({relative: {tag_name: 'button', left: {id: 'submit'}}})
let cancelLocator = locateWith(By.tagName('button')).toLeftOf(By.id('submit'));
val cancelLocator = RelativeLocator.with(By.tagName("button")).toLeftOf(By.id("submit"))
右侧
如果由于某种原因提交按钮不容易识别,但取消按钮元素容易识别,我们可以使用提交按钮元素是位于取消元素“右侧”的“按钮”元素这一事实来定位提交按钮元素。
By submitLocator = RelativeLocator.with(By.tagName("button")).toRightOf(By.id("cancel"));
submit_locator = locate_with(By.TAG_NAME, "button").to_right_of({By.ID: "cancel"})
var submitLocator = RelativeBy.WithLocator(By.tagName("button")).RightOf(By.Id("cancel"));
driver.find_element({relative: {tag_name: 'button', right: {id: 'cancel'}}})
let submitLocator = locateWith(By.tagName('button')).toRightOf(By.id('cancel'));
val submitLocator = RelativeLocator.with(By.tagName("button")).toRightOf(By.id("cancel"))
附近
如果相对位置不明显,或者它会根据窗口大小而变化,您可以使用 “附近” 方法来识别距离提供的定位器最多 50px
的元素。 这方面的一个很好的用例是处理一个没有容易构建的定位器的表单元素,但其关联的 输入标签元素 却有。
By emailLocator = RelativeLocator.with(By.tagName("input")).near(By.id("lbl-email"));
email_locator = locate_with(By.TAG_NAME, "input").near({By.ID: "lbl-email"})
var emailLocator = RelativeBy.WithLocator(By.tagName("input")).Near(By.Id("lbl-email"));
driver.find_element({relative: {tag_name: 'input', near: {id: 'lbl-email'}}})
let emailLocator = locateWith(By.tagName('input')).near(By.id('lbl-email'));
val emailLocator = RelativeLocator.with(By.tagName("input")).near(By.id("lbl-email"));
链接相对定位器
如果需要,您还可以链式使用定位器。 有时,最容易识别元素的方法是使其既在某个元素的上方/下方,又在另一个元素的右侧/左侧。
By submitLocator = RelativeLocator.with(By.tagName("button")).below(By.id("email")).toRightOf(By.id("cancel"));
submit_locator = locate_with(By.TAG_NAME, "button").below({By.ID: "email"}).to_right_of({By.ID: "cancel"})
var submitLocator = RelativeBy.WithLocator(By.tagName("button")).Below(By.Id("email")).RightOf(By.Id("cancel"));
driver.find_element({relative: {tag_name: 'button', below: {id: 'email'}, right: {id: 'cancel'}}})
let submitLocator = locateWith(By.tagName('button')).below(By.id('email')).toRightOf(By.id('cancel'));
val submitLocator = RelativeLocator.with(By.tagName("button")).below(By.id("email")).toRightOf(By.id("cancel"))