1

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

这是 XPath

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

这工作正常,直到我发现重复的match text. 所以,在一个网页上,我有两个元素match text

一个与match text另一个与match text 9000

现在,我只需要执行 click for match text。所以,我写了以下 XPath

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

请注意,匹配文本在网页上具有前导空格。上面的 Xpath 没有用。我已经用Fire PathFirefox 的扩展检查了这个。

谁能给我推荐一个 Xpath,它可以找到与match text. 假设匹配文本可以包含任意数量的前导空格。

我也尝试过使用,normalize-space()但也没有用。这是我尝试过的

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

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

感谢你的帮助。

更新:

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

我也提到了这两个字符串

  • 匹配文本
  • 匹配文本 9000

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

我已经尝试了使用 Firefox 的 FirePath 扩展提到的所有答案,但网页上没有选择任何内容。

如前所述,我在匹配文本之前有前导空格。

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 就可以了。

4

3 回答 3

2

对所有答案的评论:最好避免使用text(),因为这会使它对评论节点敏感。此外,一些(不正确的)XPath 实现无法连接相邻的文本节点,这些节点可能存在于以编程方式构建的 DOM 中。所以总是最好匹配元素的字符串值,而不是文本节点。无论如何,它更简单。这使得正确的解决方案:

tbody/tr[@backcolor]/td/b/a[normalize-space(.) = 'match text']
于 2015-08-04T07:17:48.600 回答
2

鉴于您使用的 XPath 有效,这两个选项之一应该contains()有效:

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>元素(我在这里测试过,您可以使用任何其他选择的测试仪)。如果这些都不起作用,请提供对 XPath 失败的简化 HTML 标记。

更新 :

根据更新中发布的 HTML 片段,很明显为什么normalize-space()不起作用。我会建议一种不同的方法。在 XPath 2.0 中,您可以使用ends-with()函数来匹配<a>以如下结尾的内部文本'match text'

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

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

//a[substring(., string-length(.)-string-length('match text')+1) = 'match text']
于 2015-08-04T01:21:59.633 回答
1

你的第一次尝试已经很接近了。

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

tbody/tr[@backcolor]/td/b/a[contains(text(), 'match text') and not (contains(text(), '9000'))]
于 2015-08-04T06:18:27.573 回答