115.md 12.4 KB
Newer Older
W
wizardforcel 已提交
1
# 9N WebDriver – 定位元素:第 4a 部分(通过 xpath)
W
init  
wizardforcel 已提交
2 3 4

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

W
wizardforcel 已提交
5
欢迎回来,我们今天将讨论 XPath 策略。 这也是一种先进且有效的定位策略(`cssSelectors`也是!)。 虽然有效,但有时可能会造成混淆。 因此,让我们深入研究如何理解我们经常被误解的朋友,并一劳永逸地提出好的代码。
W
init  
wizardforcel 已提交
6

W
wizardforcel 已提交
7
当所有希望都丧失了时,拯救自己的唯一机会就是转向 XPath 策略。 因为在大多数情况下,我们将测试现有的东西并且无法修改。 我们并不总是能够控制页面以添加一些 ID,从而使自动化成为一项更简单的任务。 因此,请停止咆哮并认真对待!
W
init  
wizardforcel 已提交
8

W
wizardforcel 已提交
9
*准备开始*
W
init  
wizardforcel 已提交
10

W
wizardforcel 已提交
11
**XPath** (XML 路径语言):根据 [w3schools](https://www.w3schools.com/xml/xpath_intro.asp) 的说法,XPath 是一种“路径式”语言,用于标识和浏览 XML 文档中的各种元素和属性。
W
init  
wizardforcel 已提交
12

W
wizardforcel 已提交
13
因此,XPath 提供了用于定位 HTML 文档中任何元素的语法。
W
init  
wizardforcel 已提交
14

W
wizardforcel 已提交
15
**注意:**
W
init  
wizardforcel 已提交
16

W
wizardforcel 已提交
17
*如果到目前为止,您从未接触过 XPath,请在继续进行操作之前先了解 XPath 术语。 特别是,节点和这些节点之间的关系即父级,子级,同级,祖先,后代。*
W
init  
wizardforcel 已提交
18 19 20 21 22

如果您已经知道这些术语,并且希望略微刷一下,请参考下图。 礼貌: [w3schools](https://www.w3schools.com/xml/dom_intro.asp)

![xpath DOM](img/47f64a04787a000ea375191bbccb2614.png)

W
wizardforcel 已提交
23
现在是当今的主要任务**:通过 XPath 策略定位元素!** 在这篇文章中,我们将研究以下技术,
W
init  
wizardforcel 已提交
24 25

1.  捷径
W
wizardforcel 已提交
26
2.  绝对 XPath 和相对 XPath
W
init  
wizardforcel 已提交
27 28
3.  使用标签和属性
4.  使用两个条件
W
wizardforcel 已提交
29
5.  使用`contains()`
W
init  
wizardforcel 已提交
30 31 32 33 34 35
6.  查找多个元素

让我们从最简单的动机开始。

### 1.捷径:

W
wizardforcel 已提交
36
是否想以简单的方式在网页上找到任何元素的 XPath? 做完了。是否希望几乎每次都处于完美的工作状态? 也做完了。 马上完成所有这些操作呢? 它让您涵盖了摇滚明星! 您只需要“Firebug”! 它可以作为 Firefox 浏览器的附加组件使用。
W
init  
wizardforcel 已提交
37 38 39

食谱来了:

W
wizardforcel 已提交
40
1.  点击 Firebug 图标或按“`F12`”。
W
wizardforcel 已提交
41
2.  检查其 XPath 是必需的元素。
W
wizardforcel 已提交
42
3.  相应的代码将在 Firebug 面板的“HTML”部分中突出显示。
W
wizardforcel 已提交
43 44
4.  右键点击突出显示的代码,然后选择“复制 XPath”
5.  瞧! 您已将准备好的烘焙 XPath 复制到剪贴板!
W
init  
wizardforcel 已提交
45 46 47 48 49

瞥见我们刚才所说的话,

![xpath firebug](img/7ccbc0c89fb7c153094fd84dd37b031c.png)

W
wizardforcel 已提交
50
如果您希望获得有关 Firebug 的详细信息,[请在处查看](https://javabeginnerstutorial.com/selenium/7n-ide-using-firebug/)
W
init  
wizardforcel 已提交
51

W
wizardforcel 已提交
52
### 2.现在对于**长短**:
W
init  
wizardforcel 已提交
53

W
wizardforcel 已提交
54
为了从头提出 XPath,我们首先需要了解可用的两种 Xpath。 它们是绝对 XPath 和相对 XPath。
W
init  
wizardforcel 已提交
55

W
wizardforcel 已提交
56
| **绝对 XPath** | **相对 XPath** |
W
wizardforcel 已提交
57
| --- | --- |
W
wizardforcel 已提交
58 59
| 它以单个正斜杠(`/`)开头。 | 它以双正斜杠(`//`)开头。 |
| `/`指示 XPath 引擎参考根节点搜索元素。 | `//`指示 XPath 引擎在 DOM 结构中的任何位置搜索匹配的元素。 |
W
wizardforcel 已提交
60 61
| 与相对的 XPath 相比,元素标识更快。 | 由于仅指定了部分路径,因此需要花费更多时间来标识元素。 |
| 即使对 HTML DOM 结构进行了最细微的更改(例如添加标签或删除标签),绝对 XPath 也会失败。 | 相对 XPath 较短,更改的可能性较小,从而使其更可靠。 |
W
wizardforcel 已提交
62
| 例如,`/html/head/body/div[2]/form/input` | 例如`//input[@name="username"]` |
W
init  
wizardforcel 已提交
63 64 65 66 67

有了这些基本知识,就让我们开始吧!

### 3.使用标签和属性:

W
wizardforcel 已提交
68
可以使用其 HTML 标签,其属性(例如 ID,名称,类,标题,值,`href``src`等)及其相应的值来定位特定的 Web 元素。
W
init  
wizardforcel 已提交
69

W
wizardforcel 已提交
70
**语法**`driver.findElement(By.xpath("//tag_name[@attribute='value']"));`
W
init  
wizardforcel 已提交
71

W
wizardforcel 已提交
72
**解释**:标识 XPath 指向的元素。 “`//`”标识指定的节点,“`@`”符号用于选择与给定值匹配的指定属性。
W
init  
wizardforcel 已提交
73

W
wizardforcel 已提交
74
**示例**:让我们在 Gmail 帐户注册页面上找到名字文本框。
W
init  
wizardforcel 已提交
75

W
wizardforcel 已提交
76
右键点击“名字”文本框,然后选择检查元素,以获取相应的 HTML 代码,如下所示,
W
init  
wizardforcel 已提交
77 78 79 80 81 82

```java
<input value="" name="FirstName" id="FirstName" spellcheck="false" 
class="form-error" aria-invalid="true" type="text">
```

W
wizardforcel 已提交
83
我们可以看到“`input`”标签具有一个“`name`”属性,其值为“`FirstName`”。
W
init  
wizardforcel 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

*代码:*(可以使用以下任一选项)

```java
driver.findElement(By.xpath("//input[@name='FirstName']"));
driver.findElement(By.xpath("//input[@id='FirstName']"));
driver.findElement(By.xpath("//input[@class='form-error']"));
```

如果您希望使用绝对路径,

```java
driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]/div/form/div[1]/fieldset/label[1]/input"));
```

W
wizardforcel 已提交
99
表单标签有许多子`div`标签。 在我们的情况下,我们希望选择第一个`div`标签。 可以将其指定为“`div[1]`”。 这些方括号`[]`中的数字表示要选择的确切同级。
W
init  
wizardforcel 已提交
100 101 102 103 104

### 4.使用两个条件

如果多个标签具有相同的属性值怎么办? 或者,如果您希望仅在元素与指定条件都匹配时才定位它,该怎么办?

W
wizardforcel 已提交
105
**语法**`driver.findElement(By.xpath("//tag_name[@attribute1='value1'][@attribute2='value2']"))`
W
init  
wizardforcel 已提交
106

W
wizardforcel 已提交
107
**说明**:标识具有指定`tag_name`的元素,这些元素的属性与给定值匹配。
W
init  
wizardforcel 已提交
108

W
wizardforcel 已提交
109
**示例**:让我们在 Gmail 帐户注册页面上找到“确认密码”文本框。
W
init  
wizardforcel 已提交
110

W
wizardforcel 已提交
111
右键点击“创建密码”和“确认密码”文本框,然后选择检查元素以获取相应的 HTML 代码,如下所示,
W
init  
wizardforcel 已提交
112 113 114 115 116 117

```java
<input name="Passwd" id="Passwd" type="password">
<input name="PasswdAgain" id="PasswdAgain" type="password">
```

W
wizardforcel 已提交
118
请注意,两个文本框的“`class`”属性值均相同,但“`id`”和“`name`”的值均不同。 因此,为了找到“确认密码”文本框,让我们同时提及其“`class`”和“`id`”值。
W
init  
wizardforcel 已提交
119 120 121 122 123 124 125

*代码:*

```java
driver.findElement(By.xpath("//input[@type='password'][@id='PasswdAgain']"));
```

W
wizardforcel 已提交
126
### 5.使用`contains()`:
W
init  
wizardforcel 已提交
127

W
wizardforcel 已提交
128
如今,大多数属性值(例如“`id`”,“`src`”,“`href`”等)都是使用恒定的前缀或后缀动态生成的。
W
init  
wizardforcel 已提交
129

W
wizardforcel 已提交
130
想象一个网页每天都有变化的图像。 其`src`可以是“`Image_random-generated-key_date.jpg`”。 在这种情况下,我们可以通过 XPath 使用在其`src`属性中包含“`Image`”值的“`img`”标记定位图像。 因此,通过指定属性的部分值,我们可以找到元素。
W
init  
wizardforcel 已提交
131

W
wizardforcel 已提交
132
**语法**`driver.findElement(By.xpath("//tag_name[contains(@attribute, 'value')]]"))`
W
init  
wizardforcel 已提交
133

W
wizardforcel 已提交
134
**说明**:标识具有指定`tag_name`的元素,该元素的属性与给定的部分值相匹配。
W
init  
wizardforcel 已提交
135

W
wizardforcel 已提交
136
**示例**:让我们在 Gmail 帐户注册页面上找到“下一步”按钮。
W
init  
wizardforcel 已提交
137

W
wizardforcel 已提交
138
右键单击按钮并检查元素以获取相应的 HTML 代码,如下所示,
W
init  
wizardforcel 已提交
139

W
wizardforcel 已提交
140
*代码:*
W
init  
wizardforcel 已提交
141 142 143 144 145

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

W
wizardforcel 已提交
146
注意,该 XPath 标识`div`元素,该`div`元素包含带有部分值`button``class`属性(`<div class="form-element nextstep-button">`),然后找到其子“`input`”标签(即“提交”按钮)。
W
init  
wizardforcel 已提交
147 148 149

### 6.查找多个元素

W
wizardforcel 已提交
150
您可能会遇到希望查找具有特定类或名称的所有元素并对它们执行某些操作的情况。 星号(`*`)符号可助我们一臂之力!
W
init  
wizardforcel 已提交
151

W
wizardforcel 已提交
152
**示例**:让我们在 Gmail 帐户注册页面上找到所有类值为“`goog-inline-block`”的元素。
W
init  
wizardforcel 已提交
153

W
wizardforcel 已提交
154
*代码:*
W
init  
wizardforcel 已提交
155 156 157 158 159

```java
driver.findElements(By.xpath("//*[contains(@class,'goog-inline-block')]"));
```

W
wizardforcel 已提交
160
这将找到在其“`class`”属性中包含值“`goog-inline-block`”的所有标签。
W
init  
wizardforcel 已提交
161

W
wizardforcel 已提交
162
明确指出要使用“`findElements`”,以便将所有已标识的 Web 元素添加到列表中。 如果使用“`findElement`”,它将仅返回所标识的第一个元素。
W
init  
wizardforcel 已提交
163

W
wizardforcel 已提交
164
**概览**
W
init  
wizardforcel 已提交
165 166 167 168 169

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

*场景*

W
wizardforcel 已提交
170 171 172
1.  打开 Firefox 浏览器。
2.  导航到 Google 帐户创建页面
3.  使用绝对 XPath 找到“名字”文本框
W
wizardforcel 已提交
173 174 175
4.  输入“`testFirst`”作为名字
5.  使用标签和“`id`”属性找到“姓氏”文本框(当然是相对的 XPath!)
6.  输入“`testLast`”作为姓氏
W
wizardforcel 已提交
176
7.  使用两个条件(类型和 ID 属性)找到“确认密码”文本框
W
wizardforcel 已提交
177
8.  输入“`Pass1234!`”作为确认密码
W
wizardforcel 已提交
178
9.  使用星号将所有包含在其“`class`”属性中值“`goog-inline-block`”的元素定位
W
init  
wizardforcel 已提交
179 180
10.  将找到的元素总数打印到控制台
11.  将第一个标识的元素的标题值打印到控制台
W
wizardforcel 已提交
181 182
12.  使用`contains()`找到“下一步”按钮
13.  将其“`name`”属性的值打印到控制台
W
wizardforcel 已提交
183
14.  验证 Eclipse IDE 控制台的输出屏幕和 JUnit 窗格是否成功
W
init  
wizardforcel 已提交
184

W
wizardforcel 已提交
185
此方案的 JUnit 代码是,
W
init  
wizardforcel 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

```java
package com.blog.junitTests;

import java.util.List;
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 ElementLocatorTest4 {
	//Declaring variables
	private WebDriver driver; 
	private String baseUrl;

	@Before
	public void setUp() throws Exception{
		// Selenium version3 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://accounts.google.com/SignUp";
	}

	@Test
	public void testPageTitle() throws Exception{
		// Open baseUrl in Firefox browser window
		driver.get(baseUrl);
		// Locate 'First Name' text box by absolute XPath
		// assign it to a variable of type WebElement	
		WebElement firstName = driver.findElement(By.xpath("/html/body/div[1]/div[2]/div/div[1]"
			+ "/div/form/div[1]/fieldset/label[1]/input"));
		// Clear the default placeholder or any value present
		firstName.clear();
		// Enter/type the value to the text box
		firstName.sendKeys("testFirst");
		// Locate 'Last Name' text box by relative XPath: using tag and id attribute
		WebElement lastName = driver.findElement(By.xpath("//input[@id='LastName']"));
		lastName.clear();
		lastName.sendKeys("testLast");
		// Locate 'Confirm your password' text box by XPath: using two conditions   
		WebElement confirmPwd = driver.findElement(By.xpath("//input[@type='password'][@id='PasswdAgain']"));
		confirmPwd.clear();
		confirmPwd.sendKeys("Pass1234!");
		//Locate all elements with class 'goog-inline-block' by relative XPath: using asterisk symbol
		List<WebElement> dropdowns = driver.findElements(By.xpath("//*[contains(@class,'goog-inline-block')]"));
		// Prints to the console, the total number of elements located 
		System.out.println("Total elements containing the class 'goog-inline-block' are= " + dropdowns.size());	
		// Prints first identified element's title value to console
		System.out.println("Value of the dropdown's 'title' attribute = " + dropdowns.get(0).getAttribute("title"));
		// Locate 'Next step' button by XPath: contains() and child element
		WebElement submitBtn = driver.findElement(By.xpath("//div[contains(@class,'button')]/input"));
		// Prints submitBtn's 'name' attribute's value to the console 
		System.out.println("Value of the button's 'name' attribute = " + submitBtn.getAttribute("name"));
	}

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

*执行结果:*

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

W
wizardforcel 已提交
263
在 JUnit 窗口中,绿色条显示测试用例已成功执行。 控制台窗口显示没有任何错误。 它还显示带有星号的 Web 元素总数,以及下拉菜单和按钮的属性值。
W
init  
wizardforcel 已提交
264 265 266

![xpath console output](img/977d8338a6c42f78ddef7ee01858c9d9.png)

W
wizardforcel 已提交
267
下图显示了成功执行测试脚本后获得的 Firefox 输出。
W
init  
wizardforcel 已提交
268 269 270 271 272

![xpath firefox output](img/bb66994234386495657bf7d8f36f91dd.png)

休息一下伙计! 我们的下一篇文章将是定位元素策略的最后一篇。 所以不要错过! 很快见,祝您愉快!