大多数Pythonic方法是在XML中找到元素的兄弟姐妹



问题:我有以下XML摘要:

...snip...
<p class="p_cat_heading">DEFINITION</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">PRONUNCIATION </p>
..snip...

我需要搜索XML的总体,找到具有文本DEFINITION的标题,然后打印关联的定义。定义的格式不一致,可以更改属性/元素,因此捕获所有内容的唯一可靠方法是读取直到带有属性p_cat_heading的下一个元素。

现在,我正在使用以下代码查找所有标题:

for heading in root.findall(".//*[@class='p_cat_heading']"):
    if heading.text == "DEFINITION":
        <WE FOUND THE CORRECT HEADER - TAKE ACTION HERE>

我尝试过的东西:

  • 使用LXML的getNext方法。这将获得下一个具有" p_cat_heading"属性的兄弟姐妹,这不是我想要的。
  • plostrongibling-lxml应该支持这一点,但它抛出了"在前缀映射中找不到sivebly"

我的解决方案:

我还没有完成它,但是由于我的XML很短,所以我只会获得所有元素的列表,直到具有定义属性的元素,然后迭代直到带有p_cat_heading属性的下一个元素。这个解决方案是可怕而丑陋的,但我似乎找不到一个干净的选择。

我要寻找的是:

在我们的情况下,打印定义的一种更加柔软的方式。解决方案可以使用XPATH或其他替代方案。Python本地解决方案更喜欢,但任何事情都会做。

有几种方法可以做到这一点,但是依靠xpath来完成大部分工作,此表达式

//*[@class='p_cat_heading'][contains(text(),'DEFINITION')]/following-sibling::*[1]

应该工作。

使用LXML:

from lxml import html
data = [your snippet above]
exp = "//*[@class='p_cat_heading'][contains(text(),'DEFINITION')]/following-sibling::*[1]"
tree = html.fromstring(data) 
target = tree.xpath(exp)
for i in target:
    print(i.text_content())

输出:

这个,这些。

您可以将Flifutifure与CSS选择器一起用于此任务。选择器.p_cat_heading:contains("DEFINITION") ~ .p_cat_heading将选择所有元素的所有元素,该元素在 p_cat_heading之前列出了元素,其中包含字符串"定义"的类p_cat_heading

data = '''
<p class="p_cat_heading">THIS YOU DONT WANT</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">DEFINITION</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">PRONUNCIATION </p>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(data, 'lxml')
for heading in soup.select('.p_cat_heading:contains("DEFINITION") ~ .p_cat_heading'):
    print(heading.text)

打印:

PRONUNCIATION 

进一步阅读

CSS选择器指南

编辑:

在定义之后选择直接兄弟姐妹:

data = '''
<p class="p_cat_heading">THIS YOU DONT WANT</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">DEFINITION</p>
<p class="p_numberedbullet"><span class="calibre10">This is after DEFINITION</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">PRONUNCIATION </p>
<p class="p_numberedbullet"><span class="calibre10">This is after PRONUNCIATION</span>, <span class="calibre10">these</span>. </p>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(data, 'lxml')
s = soup.select_one('.p_cat_heading:contains("DEFINITION") + :not(.p_cat_heading)')
print(s.text)

打印:

This is after DEFINITION, these. 

最新更新