25

我正在使用这样的构造:

doc = parse(url).getroot()
links = doc.xpath("//a[text()='some text']")

但我需要选择所有文本以“某些文本”开头的链接,所以我想知道有没有办法在这里使用正则表达式?在 lxml 文档中找不到任何内容

4

5 回答 5

46

您可以这样做(尽管您不需要该示例的正则表达式)。Lxml 支持来自EXSLT扩展函数的正则表达式。(请参阅XPath 类的 lxml 文档,但它也适用于该xpath()方法)

doc.xpath("//a[re:match(text(), 'some text')]", 
        namespaces={"re": "http://exslt.org/regular-expressions"})

请注意,您需要提供命名空间映射,以便它知道 xpath 表达式中的“re”前缀代表什么。

于 2010-05-03T08:53:36.613 回答
19

您可以使用以下starts-with()功能:

doc.xpath("//a[starts-with(text(),'some text')]")
于 2010-05-03T03:22:48.630 回答
1

因为我不能忍受 lxml 的命名空间方法,所以我写了一个小方法,你可以绑定到HtmlElement类。

只需导入HtmlElement

from lxml.etree import HtmlElement

然后把它放在你的文件中:

# Patch the HtmlElement class to add a function that can handle regular
# expressions within XPath queries.
def re_xpath(self, path):
    return self.xpath(path, namespaces={
        're': 'http://exslt.org/regular-expressions'})
HtmlElement.re_xpath = re_xpath

然后,当您要进行正则表达式查询时,只需执行以下操作:

my_node.re_xpath("//a[re:match(text(), 'some text')]")

你要去参加比赛了。再做一些工作,您可能可以修改它以替换xpath方法本身,但我没有打扰,因为它运行得很好。

于 2018-05-16T22:27:48.660 回答
1

你为什么不在这里使用 xpath 方法starts-with。您可以使用它来选择具有以您的单词开头的文本的特定元素,例如

doc.xpath("//a[starts-with(text(),'some text')]")

请注意,如果您也想选择此元素

<a href="www.example.com">ends with some text2</a>

它的文本不是以开头的,some text但也可以使用contains类似的方法将其包含在内

doc.xpath("//a[contains(text(),'some text')]")
于 2021-01-08T09:06:48.527 回答
0

答案是 :

doc.xpath("//a[starts-with(text(), 'some')]")

这是最简单的。通常最简单的就是最快最好的。

假设我们有以下 xml 并将其读取到doc

from lxml import etree
s="""
<html>
<head><title>Page Title</title></head>
<body>
    <a href="www.example.com">some text</a>
    <a href="www.example.com">some text2</a>
    <a href="www.example.com">ends with some text2</a>
    <a href="www.example.com">other text1</a>
    <a href="www.example.com">other text2</a>
</body>
</html>
"""
doc=etree.fromstring(s)

我们测试了前面答案中提到的三种方式的速度。

时间 陈述
39.8 微秒 doc.xpath("//a[re:match(text(), '^some')]", namespaces={'re': 'http://exslt.org/regular-expressions'})
29.3 微秒 doc.xpath("//a[re:test(text(), '^some')]", namespaces={'re': 'http://exslt.org/regular-expressions'})
16.7 微秒 doc.xpath("//a[starts-with(text(), 'some')]")

根据官方网站herere:match返回一个对象,而re:test只返回一个布尔值。我的猜测是re:match必须比re:test更复杂。当返回值是一个对象而不是布尔值时,需要更多的空间/内存,因此分配内存需要更多的时间。这就是re:testre:match快的原因。所以我在想如果你只是想检查一个字符串是否匹配一个模式,re:test足够。另一个正则表达式函数是替换。如果你像我一样在工作中大量使用 xpath,你也应该仔细阅读文档。这回答了这个问题的标题,如何在 lxml xpath 中使用正则表达式。

但是正则表达式只有在简单的字符串函数不能解决问题时才应该使用。在您的特定情况下,您所需要的只是starts-with函数。时间共谋只有 O(n),n 是第二个字符串的长度。使用正则表达式时,算法比较复杂。因此花费了更多的时间。

有关此主题的更多信息:

从 xpath 2.0 开始,无需使用 exslt 即可使用正则表达式。但 lxml 只支持 xpath 1.0。

这是 w3 网站:

https://www.w3.org/TR/xpath-functions/#string.match

于 2021-01-08T07:13:35.277 回答