如何在lxml xpath中使用正则表达式?

时间:2010-05-03 03:19:11

标签: python regex xpath lxml

我正在使用这样的结构:

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

但我需要选择所有以“some text”开头的文本链接,所以我想知道有没有办法在这里使用regexp?在lxml文档中没有找到任何内容

5 个答案:

答案 0 :(得分:38)

您可以执行此操作(尽管您不需要示例的正则表达式)。 Lxml支持EXSLT扩展函数的正则表达式。 (请参阅XPath class的lxml文档,但它也适用于xpath()方法)

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

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

答案 1 :(得分:15)

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

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

答案 2 :(得分: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')]")

答案 3 :(得分:0)

因为我无法使用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')]")

你要参加比赛了。通过更多的工作,你可以修改它来替换{​​{1}}方法本身,但我没有打扰,因为它运作良好。

答案 4 :(得分: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 µs doc.xpath("//a[re:match(text(), '^some')]", namespaces={'re': 'http:// exslt.org/regular-expressions'})
29.3 µs doc.xpath("//a[re:test(text(), '^some')]", namespaces={'re': 'http:// exslt.org/regular-expressions'})
16.7 µs 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