繁体   English   中英

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

[英]How to use regular expression in lxml xpath?

我正在使用这样的结构:

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

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

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

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

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

您可以使用starts-with()函数:

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

因为我不能忍受 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方法本身,但我没有打扰,因为它运行良好。

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

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

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

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

它的文本不是以some text开头,但也可以使用contains方法来contains它,例如

doc.xpath("//a[contains(text(),'some text')]")

答案是 :

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 中使用正则表达式。

但是正则表达式应该只在简单的字符串函数不能解决问题的时候使用。 在您的特定情况下,您需要的只是开始功能。 时间复杂度仅为 O(n),n 是第二个字符串的长度。 使用正则表达式时,算法更加复杂。 因此花费的时间更多。

有关此主题的更多信息:

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

这是 w3 网站:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM