使用XPath

时间:2015-08-04 00:13:04

标签: c# selenium xpath exact-match

我写了一个xpath来使用selenium c#从网页中抓取元素。

这是XPath

tbody/tr[@backcolor]/td/b/a[contains(text(),"match text")]

这是正常工作,直到我发现match text重复。因此,在网页上我有两个match text

的元素

一个match text,另一个match text 9000

现在,我只需点击match text即可。所以,我写了以下XPath

table/tbody/tr[@bgcolor]/td/b/a[text()="   match text"]

请注意,匹配文字在网页上有前导空格。上面的Xpath没有用。我已经使用Firefox的Fire Path扩展程序对此进行了检查。

任何人都可以建议我使用Xpath,它会找到match text的完全匹配。假设匹配文本可以包含任意数量的前导空格。

我也尝试使用normalize-space(),但这也不起作用。这就是我试过的

text()[normalize-space(.)='match']

我发现了一些关于SO的问题,这没有帮助。

感谢您的帮助。

更新

感谢您的回答,但没有一个对我有用。

我也提到了这两个字符串

  • 匹配文字
  • 匹配文字9000

在我的代码中,我将在foreach循环中迭代它们。所以,我不能保证我会得到9000作为第二个元素。

我已尝试使用FirePath扩展程序为Firefox提及的所有答案,但网页上未选择任何内容。

如前所述,我在比赛文本之前有前导空格。

HTML:(匹配xpath)

<html>
<body>
<table>
<tbody>
<tr><td><b><a class="s7intext" href="#">&nbsp;&nbsp; match text</a></b></td></tr>
<tr><td><b><a class="s7intext" href="#">&nbsp;&nbsp; match text random</a></b></td></tr>
</tbody>
</table>
</body>
</html>

这是我页面中的HTML,其中包含&nbsp;个字符。在&nbsp;之前有两个match text个字符和一个额外的空格。我正在抓取元素的网站是一个客户端网站。我不能说他要修改他的HTML。

3 个答案:

答案 0 :(得分:1)

这两个选项中的一个应该可以使用contains()使用的XPath:

tbody/tr[@backcolor]/td/b/a[normalize-space(text()) = 'match text']

tbody/tr[@backcolor]/td/b/a[text()[normalize-space(.) = 'match text']]

输入用于测试的HTML:

<div>
    <a>
       match text 900</a>
    <a>
       match text</a>
</div>

测试了XPath表达式:

//a[normalize-space(text()) = 'match text']

//a[text()[normalize-space(.) = 'match text']]

输出始终只是第二个<a>元素(我测试here,您可以使用任何其他选择的测试人员)。如果这些都不起作用,请提供一个针对XPath失败的简化HTML标记。

更新:

根据更新中发布的HTML代码段,很明显为什么normalize-space()无效。我建议采用不同的方法。在XPath 2.0中,您可以使用ends-with()函数将内部文本结尾的<a>'match text'匹配,如下所示:

//a[ends-with(.,'match text')]

如果Selenium不支持XPath 2.0,您可以像这样在XPath 1.0中模拟ends-with()

//a[substring(., string-length(.)-string-length('match text')+1) = 'match text']

答案 1 :(得分:1)

对所有答案的评论:最好避免使用for i in 0 ..< (objs?.count ?? 0) { let obj = objs?[i] } ,因为这会使评论节点敏感。此外,一些(不正确的)XPath实现无法连接相邻的文本节点,这些节点可以存在于以编程方式构造的DOM中。因此,最好匹配元素的字符串值,而不是文本节点。无论如何,它更简单。这是正确的解决方案:

text()

答案 2 :(得分:0)

你的第一次尝试已经结束了。

如果9000比赛是唯一不想要的比赛 尝试使用'not'排除9000匹配:

tbody/tr[@backcolor]/td/b/a[contains(text(), 'match text') and not (contains(text(), '9000'))]