Selenium Find By Xpath 返回错误的元素
Selenium Find By Xpath returning the wrong element
我正在尝试 select 显示在 HTML table 中的一系列频道中的一个频道。我正在使用以下 Selenium 方法 select link
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),Sales)]"));
channel.click();
但是它 select 是列表中的第一个频道(账户管理)。我希望它 select 正确的通道或抛出错误,而不是 select 错误的通道。以下是我要的频道的完整xpath:
/html/body/div[2]/div[2]/form/div/table/tbody[2]/tr/td/ul/li[2]/a/span
频道列表在HTML代码中定义如下:
<form action="nextpage.do" method="post" name="selectChannelForm">
<div class="de">
<h2>Select channel</h2>
<table id="selectChannelForm">
<tbody id=""></tbody>
<tbody id="">
<tr rowtype="container">
<td class="desecond" colspan="3">
<ul>
<li>
<a id="selected_a" href="nextpage.do?selectedChannel=123">
<span>Account Management</span></a>
</li>
<li>
<a id="selected_a" href="nextpage.do?selectedChannel=456">
<span>Sales</span></a>
</li>
<li>
<a id="selected_a" href="nextpage.do?selectedChannel=789">
<span>Complaints</span></a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<input type="hidden" value="selectChannelForm" name="formid">
</div>
您正在使用的 xpath 在 Sales
文本周围缺少引号 ""
。 text()
函数接受一个字符串参数,字符串可以使用引号组成。按照以下方式更新您的 xpath -
driver.findElement(By.xpath("//span[contains(text(),'Sales')]")).click();
或者,如果您想将其分配给 WebElement,请在引号中加上 -
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),'Sales')]"));
channel.click();
如果你想写嵌套双引号或嵌套单引号,那么使用转义字符 \
来写它。方法如下 -
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),\"Sales\")]"));
channel.click();
希望这对您有所帮助。
首先 - 你的错误!
您忘记了 "Sales" 两边的引号,只需稍微更改您的代码即可:
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),'Sales')]"));
channel.click();
第二 - xpath 错误?
你是对的,这很奇怪,你没有收到错误消息,而是第一个元素是跨度。
这实际上可能是 xpath 中的错误。 contains 函数意识到您的第二个参数不是字符串,但它没有返回 false,而是 returns true.
它实际上命中了所有三个跨度项。结果你只得到第一个,因为你使用了 findElement
函数。
试试这个,你会发现怪癖:
System.out.println(driver.findElements(By.xpath("//span[contains(text(),Sales)]")).size());
结果将是:
3
第三 - 可能是 "as designed"
查看 w3c definition 您会发现以下行:
If the value of $arg2 is the zero-length string, then the function
returns true.
然后在 xpath-site of microsoft 你会发现另一个有趣的谜题提示:
If an argument is not of type string, it is first converted to a
string and then evaluated.
将所有这些信息放在一起,我猜 xpath 将您的 non-string/non-variable 第二个参数解释为空字符串,因此对于所有 span 元素 returns 为真,因为您正在搜索 //span
.
更新
我们从@MichaelKay 的评论中了解到,我的 "guess" 非常接近:
In XPath and XQuery, a bare name like "hello" means child::hello, and
if you're not using schema-awareness, then the system will just look
for children called hello, and if there aren't any, it will return an
empty node-set.
结论:OP 看到的行为是设计好的,尽管它看起来很不直观。
xpath需要修改为"//span[contains(text(),'Sales')]" .
正如我们在下面的方法定义中看到的那样,仅当第二个参数也是文本时,contains 方法才会 return 为真。
来源:https://en.wikipedia.org/wiki/XPath
包含(s1,s2)
return如果 s1 包含 s2,则为真。
文本()
找到一个类型为 text
的节点
我正在尝试 select 显示在 HTML table 中的一系列频道中的一个频道。我正在使用以下 Selenium 方法 select link
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),Sales)]"));
channel.click();
但是它 select 是列表中的第一个频道(账户管理)。我希望它 select 正确的通道或抛出错误,而不是 select 错误的通道。以下是我要的频道的完整xpath:
/html/body/div[2]/div[2]/form/div/table/tbody[2]/tr/td/ul/li[2]/a/span
频道列表在HTML代码中定义如下:
<form action="nextpage.do" method="post" name="selectChannelForm">
<div class="de">
<h2>Select channel</h2>
<table id="selectChannelForm">
<tbody id=""></tbody>
<tbody id="">
<tr rowtype="container">
<td class="desecond" colspan="3">
<ul>
<li>
<a id="selected_a" href="nextpage.do?selectedChannel=123">
<span>Account Management</span></a>
</li>
<li>
<a id="selected_a" href="nextpage.do?selectedChannel=456">
<span>Sales</span></a>
</li>
<li>
<a id="selected_a" href="nextpage.do?selectedChannel=789">
<span>Complaints</span></a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<input type="hidden" value="selectChannelForm" name="formid">
</div>
您正在使用的 xpath 在 Sales
文本周围缺少引号 ""
。 text()
函数接受一个字符串参数,字符串可以使用引号组成。按照以下方式更新您的 xpath -
driver.findElement(By.xpath("//span[contains(text(),'Sales')]")).click();
或者,如果您想将其分配给 WebElement,请在引号中加上 -
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),'Sales')]"));
channel.click();
如果你想写嵌套双引号或嵌套单引号,那么使用转义字符 \
来写它。方法如下 -
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),\"Sales\")]"));
channel.click();
希望这对您有所帮助。
首先 - 你的错误!
您忘记了 "Sales" 两边的引号,只需稍微更改您的代码即可:
WebElement channel = driver.findElement(By.xpath("//span[contains(text(),'Sales')]"));
channel.click();
第二 - xpath 错误?
你是对的,这很奇怪,你没有收到错误消息,而是第一个元素是跨度。 这实际上可能是 xpath 中的错误。 contains 函数意识到您的第二个参数不是字符串,但它没有返回 false,而是 returns true.
它实际上命中了所有三个跨度项。结果你只得到第一个,因为你使用了 findElement
函数。
试试这个,你会发现怪癖:
System.out.println(driver.findElements(By.xpath("//span[contains(text(),Sales)]")).size());
结果将是:
3
第三 - 可能是 "as designed"
查看 w3c definition 您会发现以下行:
If the value of $arg2 is the zero-length string, then the function returns true.
然后在 xpath-site of microsoft 你会发现另一个有趣的谜题提示:
If an argument is not of type string, it is first converted to a string and then evaluated.
将所有这些信息放在一起,我猜 xpath 将您的 non-string/non-variable 第二个参数解释为空字符串,因此对于所有 span 元素 returns 为真,因为您正在搜索 //span
.
更新
我们从@MichaelKay 的评论中了解到,我的 "guess" 非常接近:
In XPath and XQuery, a bare name like "hello" means child::hello, and if you're not using schema-awareness, then the system will just look for children called hello, and if there aren't any, it will return an empty node-set.
结论:OP 看到的行为是设计好的,尽管它看起来很不直观。
xpath需要修改为"//span[contains(text(),'Sales')]" .
正如我们在下面的方法定义中看到的那样,仅当第二个参数也是文本时,contains 方法才会 return 为真。
来源:https://en.wikipedia.org/wiki/XPath
包含(s1,s2) return如果 s1 包含 s2,则为真。 文本() 找到一个类型为 text
的节点