Python lxml XPath:无效表达式(可选子项)

问题描述 投票:0回答:1

我需要从网站中提取文本。该网站有两种不同的结构,其中一种在正文之前有一个附加元素。

我尝试提取文本如下:

//div[contains(@id, "text")]/(p|.)/text()

据我所知,eTree 的 Xpath 不喜欢

(p|.)
。是否有另一种简短的方式来编写此代码,以便 lxml 不会抱怨?我知道我可以把两者都写出来并在它们之间放置一个或,但是上面的这个选项节省了大量的输入(考虑到纯 XPath 也可以工作)。

谢谢!

编辑 以下是这两种情况的两个小示例片段(已简化):

没有孩子:

<div class="article_text">
    ...
    <div id="bodytext"...>
    "yadda yadda here be dragons"
    </div>
</div>

带着孩子:

<div class="article_text">
    ...
    <div id="bodytext">
        <p>
            "Here be paragraphed dragons"
        </p>
    </div>
</div>

编辑 2: 这不完全是关于这个特定的案例,而是直接关于 lxml - 我从很多不同的网站提取文本,这个“可选的孩子”很常见 - 我的问题是是否有另一种选择(不同的写作)这种语法,还是 lxml 不接受它,我必须全部“或”它?

编辑 3: 我刚才遇到的事情是:新闻站点有不同类型的文章,有时是所谓的“信息框”,不需要提取。所以我会做

//main/(div[not(contains(@class, "infobox"))]|.)/p/text()
,排除这个特定的div,但包括其他div或其他类型的标签。文本在一些页面中包裹在 div 中,在其他包裹在多个 div 中,有时在跨度等中。意思是“或”与那里的解决方案相比,它们一起会产生一个极其/不必要的复杂 XPath - 但如前所述,lxml 不会似乎喜欢它。

python xpath lxml
1个回答
0
投票

如果你想要所有后代的文本,你可以这样做(我把你的两个例子都加入到一个 XML 文档中):

>>> doc.xpath('//div[contains(@id, "text")]//text()')
['\n    "yadda yadda here be dragons"\n    ', '\n        ', '\n            "Here be paragraphed dragons"\n        ', '\n    ']

注意

//
之前的
text()
,输出是一个平面列表。

如果你想在节点上分割输出,你可以做一些事情:

>>> for node in doc.xpath('//div[contains(@id,"text")]'):
    print((''.join(node.xpath('.//text()')).strip()))
"yadda yadda here be dragons"
"Here be paragraphed dragons"
© www.soinside.com 2019 - 2024. All rights reserved.