116.md 13.6 KB
Newer Older
W
wizardforcel 已提交
1
# 9O WebDriver – 定位元素:第 4b 部分(XPath 续)
W
init  
wizardforcel 已提交
2 3 4 5 6

> 原文: [https://javabeginnerstutorial.com/selenium/9o-webdriver-locating-elements-4b/](https://javabeginnerstutorial.com/selenium/9o-webdriver-locating-elements-4b/)

嗨冠军! 欢迎来到我们关于定位元素的最后一篇文章。 好极了!!!

W
wizardforcel 已提交
7
这是我们上一篇文章“[9n。 WebDriver – 定位元素:第 4a 部分(由 XPath 提供)](https://javabeginnerstutorial.com/selenium/9n-webdriver-locating-elements-4a/)”。 您以前曾经听过我说过这个,然后您会再次听我说过……在继续使用 XPath 策略之前,请先阅读第 4a 部分。
W
init  
wizardforcel 已提交
8 9 10

在这篇文章中,我们将研究以下技术,

W
wizardforcel 已提交
11 12
1.  使用`Text()`
2.  使用`starts-with()`
W
wizardforcel 已提交
13
3.  使用 XPath 轴
W
init  
wizardforcel 已提交
14

W
wizardforcel 已提交
15
这些技术以及我们在第 4a 部分中看到的技术可以结合起来,并用于形成有效的 XPath,该 XPath 可以定位网页上的任何元素。 现在通过示例来介绍当今的技术。
W
init  
wizardforcel 已提交
16

W
wizardforcel 已提交
17
## 1.使用`text()`
W
init  
wizardforcel 已提交
18

W
wizardforcel 已提交
19
通过提供与网页上显示的文本**完全相同的**文本,这是一种轻松定位元素的方法。
W
init  
wizardforcel 已提交
20

W
wizardforcel 已提交
21
**注意:**
W
init  
wizardforcel 已提交
22

W
wizardforcel 已提交
23
*当心! 即使错误地包含空格,您也可能遇到“`ElementNotFound`”异常。 在代码中提供的文本必须与可见文本完全匹配,这一点非常重要,我的意思是从字面上看!*
W
init  
wizardforcel 已提交
24

W
wizardforcel 已提交
25
**示例**:让我们找到“Facebook 注册”页面上的“忘记帐户?”链接。
W
init  
wizardforcel 已提交
26

W
wizardforcel 已提交
27
右键点击“忘记帐户?”链接,然后选择检查元素以获取相应的 HTML 代码,如下所示,
W
init  
wizardforcel 已提交
28 29 30 31 32 33

```java
<a href="https://www.facebook.com/recover/initiate?lwv=111" 
data-testid="forgot_account_link">Forgot account?</a>
```

W
wizardforcel 已提交
34
让我们通过提供出现在 Facebook 页面上的文本来找到此链接。
W
init  
wizardforcel 已提交
35 36 37 38 39 40 41

*代码:*

```java
driver.findElement(By.xpath("//a[text()='Forgot account?']"));
```

W
wizardforcel 已提交
42
如果要查找包含部分文本的所有元素,可以将`contains()``text()`技术结合使用。 可以使用`findElements`方法在列表中获取所有元素。
W
init  
wizardforcel 已提交
43

W
wizardforcel 已提交
44
让我们尝试在同一示例中同时实现`contains()``text()`。 由于我们只有一个链接与该文本,因此将使用`findElement`方法。
W
init  
wizardforcel 已提交
45 46 47 48 49

```java
driver.findElement(By.xpath("//*[contains(text(),'Forgot')]"));
```

W
wizardforcel 已提交
50
## 2.使用`starts-with()`
W
init  
wizardforcel 已提交
51

W
wizardforcel 已提交
52
通过指定属性的部分值(前缀),可以使用`starts-with()`查找元素。 当页面重新加载时属性值动态更改时,此功能非常有用。
W
init  
wizardforcel 已提交
53

W
wizardforcel 已提交
54
**示例**:让我们在“Facebook 注册”页面上找到“新密码”文本框。
W
init  
wizardforcel 已提交
55

W
wizardforcel 已提交
56
右键点击“新密码”文本框,然后选择检查元素以获取相应的 HTML 代码,
W
init  
wizardforcel 已提交
57 58 59 60 61 62 63

```java
<input class="inputtext _58mg _5dba _2ph-" data-type="text" 
name="reg_passwd__" aria-required="1" placeholder="" id="u_0_d" 
aria-label="New password" type="password">
```

W
wizardforcel 已提交
64
让我们通过提供`type`属性的部分前缀值“通过”来找到此文本框。 请注意,“登录”部分中的密码字段还具有`type`作为`password`
W
init  
wizardforcel 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77

```java
<input class="inputtext" name="pass" id="pass" tabindex="2" type="password">
```

因此,第二个元素必须位于我们的案例中。

*Code:*

```java
driver.findElement(By.xpath("(//input[starts-with(@type,'pass')])[2]"));
```

W
wizardforcel 已提交
78
## 3.使用 XPath 轴
W
init  
wizardforcel 已提交
79

W
wizardforcel 已提交
80
XPath 轴定义在当前节点浏览 DOM 的树形结构时要考虑的相对于当前节点的节点集或方向。
W
init  
wizardforcel 已提交
81

W
wizardforcel 已提交
82
下表(礼貌性表示: [w3schools](https://www.w3schools.com/xml/xpath_axes.asp) )显示了所有 13 个可用的 XPath 轴及其结果。
W
init  
wizardforcel 已提交
83 84

| **轴名称** | **结果** |
W
wizardforcel 已提交
85
| --- | --- |
W
wizardforcel 已提交
86 87
| 祖先 | 选择当前节点的所有祖先(父,祖父级等) |
| 祖先或自己 | 选择当前节点的所有祖先(父,祖父级等)和当前节点本身 |
W
init  
wizardforcel 已提交
88
| 属性 | 选择当前节点的所有属性 |
W
wizardforcel 已提交
89
| 子项 | 选择当前节点的所有子节点 |
W
wizardforcel 已提交
90
| 后代 | 选择当前节点的所有后代(子代,孙代等) |
W
init  
wizardforcel 已提交
91
| 后代或自己 | 选择当前节点的所有后代(子代,孙代等)和当前节点本身 |
W
wizardforcel 已提交
92 93
| 之后 | 选择当前节点的结束标记之后的文档中的所有内容 |
| 之后的同级 | 选择当前节点之后的所有同级 |
W
init  
wizardforcel 已提交
94
| 命名空间 | 选择当前节点的所有名称空间节点 |
W
wizardforcel 已提交
95 96 97 98
| 父项 | 选择当前节点的父节点 |
| 之前 | 选择出现在文档中当前节点之前的所有节点,但祖先,属性节点和名称空间节点除外 |
| 之前的同级 | 选择当前节点之前的所有同级 |
| 自己 | 选择当前节点 |
W
init  
wizardforcel 已提交
99 100 101

让我们来看一些重要的

W
wizardforcel 已提交
102
### 3a. 父轴
W
init  
wizardforcel 已提交
103 104 105

选择当前节点的父级。

W
wizardforcel 已提交
106
**示例**:让我们找到位于 Facebook Sign Up 页面左上方的 Facebook 徽标的锚标记。
W
init  
wizardforcel 已提交
107 108 109 110 111 112

在检查元素后,

```java
<a href="https://www.facebook.com/" title="Go to Facebook Home">
   <i class="fb_logo img sp_euCDsy2vhU4 sx_af4dba">
W
wizardforcel 已提交
113
       Facebook
W
init  
wizardforcel 已提交
114 115 116 117 118 119 120 121 122 123
   </i>
</a> 
```

*Code:*

```java
driver.findElement(By.xpath("//i[@class='fb_logo']/parent::a"));
```

W
wizardforcel 已提交
124
将找到具有`href``title`属性的父节点“`a`”。
W
init  
wizardforcel 已提交
125

W
wizardforcel 已提交
126
### 3b. 祖先轴
W
init  
wizardforcel 已提交
127

W
wizardforcel 已提交
128
选择当前节点的所有祖先(父代,祖父级等)。
W
init  
wizardforcel 已提交
129

W
wizardforcel 已提交
130
**示例**:让我们在“Facebook 注册”页面上找到文字“生日”。
W
init  
wizardforcel 已提交
131 132 133 134 135 136 137 138 139 140 141

Upon inspecting the element,

Birthday

*Code:*

```java
driver.findElement(By.xpath("//select[@id='month']/ancestor::div[@class='_5k_5']/preceding-sibling::div"));
```

W
wizardforcel 已提交
142
带有 ID 的“`select`”标签,选择了“`month`”。 转到类“`_5k_5`”的祖先`div`标签。 然后到其前一个带有“`div`”标签的同级节点,其文本为“`Birthday`”。
W
init  
wizardforcel 已提交
143 144 145

选择该特定示例以显示可以组合多个轴以获得所需的结果。

W
wizardforcel 已提交
146
### 3c. 子轴
W
init  
wizardforcel 已提交
147 148 149

选择当前节点的所有子节点

W
wizardforcel 已提交
150
**示例**:让我们找到“Facebook 注册”页面上的“登录”按钮。
W
init  
wizardforcel 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163

Upon inspecting the element,

```java
 <label class="uiButton uiButtonConfirm" for="u_0_q" id="loginbutton"></label> 
```

*Code:*

```java
driver.findElement(By.xpath("//label[@id='loginbutton']/child::input"));
```

W
wizardforcel 已提交
164
标识为“`loginbutton`”的标签的子节点-标识为“`u_0_q`”的输入标签。
W
init  
wizardforcel 已提交
165

W
wizardforcel 已提交
166
### 3d. 后代轴
W
init  
wizardforcel 已提交
167 168 169

选择当前节点的所有后代(子代,孙代等)。

W
wizardforcel 已提交
170
**示例**:让我们在“Facebook 注册”页面上找到“名字”文本框。
W
init  
wizardforcel 已提交
171 172 173 174 175

Upon inspecting the element,

First name

W
wizardforcel 已提交
176 177 178
```java
<input id=u_0_1 class=”inputtext _58mg _5dba _2ph- data-type=text name=firstname aria-required=1 placeholder=”” aria-label=First name type=text> </div>
```
W
init  
wizardforcel 已提交
179 180 181 182 183 184 185

*Code:*

```java
driver.findElement(By.xpath("//div[contains(@class,'uiStickyPlaceholderInput')]/descendant::input"));
```

W
wizardforcel 已提交
186
类别为`uiStickyPlaceholderInput``div`标签的后代节点-ID 为`u_o_1`的输入标签已找到。
W
init  
wizardforcel 已提交
187

W
wizardforcel 已提交
188
### 3e. 同级轴
W
init  
wizardforcel 已提交
189 190 191

选择当前节点之后的所有同级

W
wizardforcel 已提交
192
**示例**:让我们在“Facebook 注册”页面页脚部分中找到“登录”链接。
W
init  
wizardforcel 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

Upon inspecting the element,

```java
<td class="_51m- hLeft plm">
   <a href="/r.php" title="Sign Up for Facebook">Sign Up</a>
</td>
<td class="_51m- hLeft plm">
   <a href="/login/" title="Log into Facebook">Log In</a>
</td> 
```

*Code:*

```java
driver.findElement(By.xpath("//td[@class='_51m- hLeft plm']/following-sibling::td/child::a"));
```

W
wizardforcel 已提交
211
以下`td`标签的同级类`_51m-hLeft plm`是另一个`td`标签,其子对象是带有标题“登录 Facebook”的锚标签。
W
init  
wizardforcel 已提交
212 213 214

将后继同级和子级轴组合在一起,以在页脚部分中找到“登录”超链接。

W
wizardforcel 已提交
215
### 3f. 上一个同级轴
W
init  
wizardforcel 已提交
216 217 218

选择当前节点之前的所有同级

W
wizardforcel 已提交
219
**示例**:让我们找到“Facebook 注册”页面上的“女性”单选按钮。
W
init  
wizardforcel 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

Upon inspecting the element,

```java
<span class="_5k_2 _5dba">
   <input id="u_0_g" name="sex" value="1" type="radio">
   <label class="_58mt" for="u_0_g">Female</label>
</span> 
```

*Code:*

```java
driver.findElement(By.xpath("//label[@class='_58mt']/preceding-sibling::input"));
```

W
wizardforcel 已提交
236
“标签”标签的前面同级是“无线电”类型的`input`标签。 这样就找到了所需的单选按钮。
W
init  
wizardforcel 已提交
237

W
wizardforcel 已提交
238
这样,就涵盖了一些常用的 XPath 轴类型。
W
init  
wizardforcel 已提交
239

W
wizardforcel 已提交
240
我们在 BrainBell 方面一直处于停滞状态。 那为什么要延迟呢? 开始了,
W
init  
wizardforcel 已提交
241

W
wizardforcel 已提交
242
**BrainBell****注意!** *注意您的大脑状态。*
W
init  
wizardforcel 已提交
243

W
wizardforcel 已提交
244 245
*   *症状*:没有任何东西被注册,开始浏览文章或忘记您刚刚阅读的内容。
*   *诊断*:您的大脑超负荷。
W
wizardforcel 已提交
246
*   *补救*:休息一下! 但是记得很快回来😉
W
init  
wizardforcel 已提交
247

W
wizardforcel 已提交
248
*我将根据我的经验个人建议 **Pomodoro 技术**。 它非常有效。 试一试!*
W
init  
wizardforcel 已提交
249

W
wizardforcel 已提交
250
## 概览
W
init  
wizardforcel 已提交
251 252 253 254 255

让我们来看一个测试案例,该案例实现了迄今为止本文中涵盖的所有技术,

*场景*

W
wizardforcel 已提交
256 257
1.  打开 Firefox 浏览器。
2.  导航到 www.facebook.com
W
wizardforcel 已提交
258
3.  使用`text()`找到“忘记帐户?”链接
W
init  
wizardforcel 已提交
259
4.  将链接文本打印到控制台
W
wizardforcel 已提交
260 261
5.  使用`starts-with()`找到“新密码”文本框
6.  输入值“`test1234!`
W
init  
wizardforcel 已提交
262 263
7.  使用子轴找到“登录”按钮
8.  将值属性打印到控制台
W
wizardforcel 已提交
264
9.  使用父轴找到 Facebook 徽标
W
wizardforcel 已提交
265
10.  将其`title`属性的值打印到控制台
W
init  
wizardforcel 已提交
266
11.  在页脚部分的“兄弟姐妹”轴中找到“登录”链接
W
wizardforcel 已提交
267
12.  将其`title`属性的值打印到控制台
W
init  
wizardforcel 已提交
268 269 270 271 272 273
13.  使用上一个同级轴找到“女性”单选按钮
14.  点击单选按钮
15.  使用祖先轴找到文本“生日”
16.  将其文本打印到控制台
17.  使用后代轴找到“名字”文本框
18.  输入值“首先测试”
W
wizardforcel 已提交
274
19.  验证 Eclipse IDE 控制台的输出屏幕和 JUnit 窗格是否成功
W
init  
wizardforcel 已提交
275

W
wizardforcel 已提交
276
此方案的 JUnit 代码是,
W
init  
wizardforcel 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362

```java
package com.blog.junitTests;

import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class ElementLocatorTest4b {
    // Declaring variables
    private WebDriver driver;
    private String baseUrl;

    @Before
    public void setUp() throws Exception {
        // Selenium version 3 beta releases require system property set up
        System.setProperty("webdriver.gecko.driver", "E:\\Softwares\\Selenium\\geckodriver-v0.10.0-win64\\geckodriver.exe");
        // Create a new instance for the class FirefoxDriver
        // that implements WebDriver interface
        driver = new FirefoxDriver();
        // Implicit wait for 5 seconds
        driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        // Assign the URL to be invoked to a String variable
        baseUrl = "https://www.facebook.com/";
    }

    @Test
    public void testPageTitle() throws Exception {
        // Open baseUrl in Firefox browser window
        driver.get(baseUrl);

        // Locate 'Forgot Account' link using XPath: text()
        WebElement forgotAccLink = driver.findElement(By.xpath("//*[contains(text(),'Forgot')]"));
        // Prints the link text to the console
        System.out.println("Link text: " + forgotAccLink.getText());
        // Locate 'New password' text box by XPath: using starts-with()
        WebElement passwordNew = driver.findElement(By.xpath("(//input[starts-with(@type,'pass')])[2]"));
        // Clear the default placeholder or any value present
        passwordNew.clear();
        // Enter/type the value to the text box
        passwordNew.sendKeys("test1234!");

        // Locate 'Log In' button using XPath: child axis
        WebElement logIn = driver.findElement(By.xpath("//label[@id='loginbutton']/child::input"));
        // Prints 'value' attribute to console
        System.out.println("Child axis: " + logIn.getAttribute("value"));
        // Locate 'Facebook' logo using XPath: parent axis
        WebElement fbLogo = driver.findElement(By.xpath("//i[contains(@class,'fb_logo')]/parent::a"));
        // Prints 'title' attribute's value to console
        System.out.println("Parent axis: " + fbLogo.getAttribute("title"));
        // Locate 'Log In' link in footer section using XPath: following-sibling axis
        WebElement loginFooter = driver.findElement(By.xpath("//td[@class='_51m- hLeft plm']/following-sibling::td/child::a"));
        //Prints 'title' attribute's value to console
        System.out.println("Following-sibling: " + loginFooter.getAttribute("title"));
        // Locate 'female' radio button using XPath: preceding-sibling axis
        WebElement femaleRadioBtn = driver.findElement(By.xpath("//label[@class='_58mt']/preceding-sibling::input"));
        // Click the radio button
        femaleRadioBtn.click();
        // Locate 'Birthday' text using XPath: ancestor axis
        WebElement birthday = driver.findElement(By.xpath("//select[@id='month']/ancestor::div[@class='_5k_5']/preceding-sibling::div"));
        //Prints text to console
        System.out.println("Ancestor axis: " + birthday.getText());
        // Locate 'first name' test box using XPath: descendant axis
        WebElement firstName = driver.findElement(By.xpath("//div[contains(@class,'uiStickyPlaceholderInput')]/descendant::input"));
        firstName.clear();
        firstName.sendKeys("test first");
    }

    @After
    public void tearDown() throws Exception {
        // Close the Firefox browser
        driver.close();
    }
}
```

*执行结果:*

这段代码将作为本文讨论的每种技术的一部分进行解释。

W
wizardforcel 已提交
363
在 JUnit 窗口中,绿色条显示测试用例已成功执行。 控制台窗口显示没有任何错误。 它还可以按预期显示所有打印结果。
W
init  
wizardforcel 已提交
364 365 366

![XPath JUnit Console](img/044fb8d15c96e0bbc42010e4396dd739.png)

W
wizardforcel 已提交
367
下图显示了成功执行测试脚本后获得的 Firefox 输出。
W
init  
wizardforcel 已提交
368 369 370 371 372 373 374

![XPath Firefox output](img/c696b7d190e210595629764b59692033.png)

好吧! 现在,您应该全都适应定位策略。 我们将在所有即将到来的示例中看到这些策略的应用。 因此,请继续关注此空间。

在另一个帖子中再见! 祝你有美好的一天!