从包含在 HTML 标记和不带标记的字符串中的一系列字符串中提取文本

Posted

技术标签:

【中文标题】从包含在 HTML 标记和不带标记的字符串中的一系列字符串中提取文本【英文标题】:Extracting text from a succession of strings enclosed in HTML tags and strings without tags 【发布时间】: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; 之后有多个未包含在标签中的字符串,则可能会发生这种情况。我认为我的“尝试”示例有点令人困惑,因为它看起来好像我总是在末尾有一个字符串。 【参考方案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 我已经更新了答案,希望这个解决方案能解决您的问题。

以上是关于从包含在 HTML 标记和不带标记的字符串中的一系列字符串中提取文本的主要内容,如果未能解决你的问题,请参考以下文章

从 Python 字符串中删除不在允许列表中的 HTML 标记

从字符串中删除 html 标记

如何替换 Java 字符串中的一组标记?

从包含 Div 和脚本标记的 html 编码字符串中动态添加 div 元素

将包含 html 标记的存储字符串转换为 html 文本格式

Struts2标记中的HTML标记