【发布时间】:2011-02-14 21:42:33
【问题描述】:
我正在使用这样的构造:
doc = parse(url).getroot()
links = doc.xpath("//a[text()='some text']")
但我需要选择所有文本以“某些文本”开头的链接,所以我想知道这里有什么方法可以使用正则表达式吗?在 lxml 文档中找不到任何内容
【问题讨论】:
我正在使用这样的构造:
doc = parse(url).getroot()
links = doc.xpath("//a[text()='some text']")
但我需要选择所有文本以“某些文本”开头的链接,所以我想知道这里有什么方法可以使用正则表达式吗?在 lxml 文档中找不到任何内容
【问题讨论】:
你可以使用starts-with()函数:
doc.xpath("//a[starts-with(text(),'some text')]")
【讨论】:
您可以这样做(尽管您不需要该示例的正则表达式)。 Lxml 支持来自EXSLT 扩展函数的正则表达式。 (有关XPath class,请参阅lxml 文档,但它也适用于xpath() 方法)
doc.xpath("//a[re:match(text(), 'some text')]",
namespaces={"re": "http://exslt.org/regular-expressions"})
请注意,您需要提供命名空间映射,以便它知道 xpath 表达式中的“re”前缀代表什么。
【讨论】:
match(., 'some text')。顺便说一句,我不太了解. 部分。并且 func test 具有相同的结果(我认为实际上使用 test 更有意义:P)
因为我无法忍受 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 方法本身,但我没有打扰,因为它工作得很好。
【讨论】:
from lxml.html import HtmlElement
<div id=blah_1>tree.re_xpath("//div[re:match(@id, 'blah_\d+')]")
答案是:
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)
我们测试了前面答案中提到的三种方式的速度。
| time | statement |
|---|---|
| 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')]") |
根据官网here,re:match返回一个对象,而re:test只返回一个布尔值。我的猜测是 re:match 一定比 re:test 更复杂。当返回值是一个对象而不是布尔值时,需要更多的空间/内存,因此分配内存需要更多的时间。这就是 re:test 比 re:match 更快的原因。所以我在想如果你只是想检查一个字符串是否匹配一个模式, re:test 就足够了。另一个正则表达式函数是替换。如果你像我一样在工作中大量使用 xpath,你也应该仔细阅读文档。这回答了这个问题的标题,如何在 lxml xpath 中使用正则表达式。
但是正则表达式只能在简单的字符串函数不能解决问题的情况下使用。在您的具体情况下,您所需要的只是 starts-with 函数。时间共谋只有 O(n),n 是第二个字符串的长度。使用正则表达式时,算法比较复杂。因此花费了更多的时间。
有关此主题的更多信息:
从 xpath 2.0 开始,正则表达式将在不使用 exslt 的情况下可用。但是lxml只支持xpath 1.0。
这里是 w3 网站:
【讨论】:
你为什么不在这里使用 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')]")
【讨论】: