【问题标题】:Extracting text from a succession of strings enclosed in HTML tags and strings without tags从包含在 HTML 标记和不带标记的字符串中的一系列字符串中提取文本
【发布时间】:2020-05-13 16:30:22
【问题描述】:

考虑以下 HTML:

<li>
  <a href="url">
    <b>This</b>
    " is "
    <b>a</b>
    " test "
    <b>string</b>
    "!"
  </a>
</li>

我想提取除"!" 之外的&lt;a&gt; 标签之间的所有文本。换句话说,包含在第一个开头 &lt;b&gt; 和最后一个结尾 &lt;/b&gt; 之间的文本:This is a test string

from bs4 import BeautifulSoup

html = '''
<li>
<a href="url">
<b>This</b>
" is "
<b>a</b>
" test "
<b>string</b>
"!"
</a>
</li>
'''
soup = BeautifulSoup(html)
anchor = soup.a

请注意,&lt;b&gt; 标记和不带标记的字符串的数量会有所不同,因此 nextnext_sibling 将不起作用。

有更简单的方法吗?

编辑: 理想情况下,即使在最后一个&lt;/b&gt; 之后有多个未包含在标签中的字符串,我也想要一种有效的方法。

【问题讨论】:

  • 可能是[c.text if isinstance(c, element.Tag) else str(c) for c in anchor.contents[:-1]],其中元素是from bs4 import element
  • @Justin Ezequiel 谢谢你的建议。这在我的示例中可行,但如果在最后一个&lt;/b&gt; 之后有多个未包含在标签中的字符串,则可能会发生这种情况。我认为我的“尝试”示例有点令人困惑,因为它看起来好像我总是在末尾有一个字符串。

标签: python python-3.x beautifulsoup


【解决方案1】:

根据您的问题和 cmets,我认为获取子字符串的索引并对 HTML 的整个子集进行操作可以满足您的需求。

让我们为retrieve all of the indexes of a substring first 创建一个函数(参见@AkiRoss 的回答):

def findall(p, s):
    i = s.find(p)
    while i != -1:
        yield i
        i = s.find(p, i+1)

然后使用它来查找&lt;b&gt;&lt;/b&gt; 的出现。

opening_b_occurrences = [i for i in findall('<b>', html)]
# has the value of [21, 40, 58]
closing_b_occurrences = [i for i in findall('</b>', html)]
# has the value of [28, 44, 67]

现在您可以使用该信息获取 HTML 的子字符串来进行文本提取:

first_br = opening_b_occurrences[0]
last_br = closing_b_occurrences[-1] # getting the last one from list
text_inside_br = html[first_br:last_br]

text_inside_br 中的文本现在应该是 '&lt;b&gt;This&lt;/b&gt;\n" is "\n&lt;b&gt;a&lt;/b&gt;\n" test "\n&lt;b&gt;string'。您现在可以清理它,例如通过将 &lt;/br&gt; 附加回它并使用 BeautifulSoup 提取值或只是 using regex to do that.

【讨论】:

  • 感谢您的建议。这也有效,但需要额外的步骤来清理输出。我认为在更复杂的情况下,它会比@Shibirraj 的答案更好,因为它混合了不同的标签类型。
  • @Junitar 很高兴为您提供帮助。是的,当然取决于您的用例的复杂性,如果您的与您的示例非常相似,那么 Shibirraj 的解决方案非常棒。
【解决方案2】:

试试下面的代码

result = ''.join([i.strip().replace('"', '') for i in anchor.strings if i.strip()][:-1])
print(result)

输出

'This is a test string'

【讨论】:

  • 感谢您的建议。这在这种特殊情况下有效。不幸的是,如果我在最后一个&lt;/b&gt; 之后有多个未包含在标签中的字符串,它将不起作用。
  • 如果我没有得到任何其他答案,我会接受你的答案,因为你的答案适用于我提供的示例。也就是说,如果您知道一种无需使用特定数字切片即可处理此问题的方法,那就太好了。
  • @Junitar 我已经更新了答案,希望这个解决方案能解决您的问题。
猜你喜欢
  • 2016-03-18
  • 1970-01-01
  • 2015-05-12
  • 1970-01-01
  • 2021-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
相关资源
最近更新 更多