【问题标题】:How does one get the text from html while ignoring formatting tags using BeautifulSoup?如何在使用 BeautifulSoup 忽略格式化标签的同时从 html 中获取文本?
【发布时间】:2016-05-30 02:37:46
【问题描述】:

以下代码用于从 html 中抓取连续的文本段。

    for text in soup.find_all_next(text=True):
        if isinstance(text, Comment):
            # We found a comment, ignore
            continue
        if not text.strip():
            # We found a blank text, ignore
            continue
        # Whatever is left must be good
        print(text)

文本项由<div><br> 等结构标签以及<em><strong> 等格式标签分解。这给我进一步解析文本带来了一些不便,我希望能够抓取连续的文本项,同时忽略文本内部的任何格式标记。

例如,soup.find_all_next(text=True) 将采用 html 代码 <div>This is <em>important</em> text</div> 并返回单个字符串 This is important text,而不是三个字符串 This isimportanttext

我不确定这是否清楚...如果不是,请告诉我。

编辑:我逐个文本项遍历 html 文本项的原因是,我只是在看到特定的“开始”注释标记并且停止后才开始遍历当我到达特定的“结束”评论标签时。在需要逐项遍历的情况下,是否有任何解决方案有效?我正在使用的完整代码如下。

soup = BeautifulSoup(page)
for instanceBegin in soup.find_all(text=isBeginText):
    # We found a start comment, look at all text and comments:
    for text in instanceBegin.find_all_next(text=True):
        # We found a text or comment, examine it closely
        if isEndText(text):
            # We found the end comment, everybody out of the pool
            break
        if isinstance(text, Comment):
            # We found a comment, ignore
            continue
        if not text.strip():
            # We found a blank text, ignore
            continue
        # Whatever is left must be good
        print(text)

如果传递给它们的字符串与我的开始或结束注释标签匹配,则 isBeginText(text)isEndText(text) 这两个函数返回 true。

【问题讨论】:

  • 如果您有两个嵌套的块级标签,您想如何处理?比如说<div>A<p>B</p>C</div>。你想要什么?无论如何,我的看法是,您应该检查当前标签是否有任何后代。如果是这样,请(递归地)检查这些后代是否属于“格式化”类型(注意这是主观的:您认为em 是其中之一,但不是br),如果是,请删除格式化标签,但保留内部 HTML。也许我没有完全理解你的问题,但这不能解决你的问题吗?
  • 是的,我听到了。实际上,除了保留基本句子结构之外,我不关心任何格式。我可以忽略<br><p> 等,只要保留句子(即,单词不会混在一起)。我知道soup.get_text() 方法,但我不确定如何将其应用于我关于开始和结束标签的特定约束(请参阅我的原始问题的编辑)。
  • @OliverW。你打赌:开始标签是评论标签<!-- Begin -->,结束标签也是评论标签<!-- End -->。我想要这两个评论标签之间的所有文本。如果有新行或中断,我很乐意将其替换为空格,只要它保留完整的句子和单词。

标签: python html python-3.x beautifulsoup bs4


【解决方案1】:

如果你抓取包含你的子元素的父元素并执行get_text(),BeautifulSoup 会为你去除所有的 html 标签,只返回一个连续的文本字符串。

你可以找到一个例子here

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
print(soup.get_text())

【讨论】:

  • 我想我应该注意到,这一切都必须发生在两个特定的“开始”和“结束”cmets 之间。这就是我逐项浏览 html 的原因。
  • 如果我在整个 html 文件上使用get_text(),我会从页眉和页脚中得到一堆我不想要的垃圾。我已经修改了我原来的问题以包含这个上下文。
【解决方案2】:

如何使用find_all_next 两次,开始和结束标记各一次,并取两个生成列表的差异?

例如,我将使用 html_doc 的修改版本 the documentation of BeautifulSoup

import bs4

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<!-- START--><a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p><!-- END -->

<p class="story">...</p>
"""

soup = bs4.BeautifulSoup(html_doc, 'html.parser')
comments = soup.findAll(text=lambda text:isinstance(text, bs4.Comment))

# Step 1: find the beginning and ending markers
node_start = [ cmt for cmt in comments if cmt.string == " START" ][0]
node_end = [ cmt for cmt in comments if cmt.string == " END " ][0]

# Step 2, subtract the 2nd list of strings from the first
all_text = node_start.find_all_next(text=True)
all_after_text = node_end.find_all_next(text=True)

subset = all_text[:-(len(all_after_text) + 1)]
print(subset)

# ['Lacie', ' and\n', 'Tillie', ';\nand they lived at the bottom of a well.']

【讨论】:

  • 给我几分钟试试这个。
  • 这很好用!哇。我不得不对其进行一些修改以将其塞进我的代码中,但输出不仅保留了句子结构,而且还保留了格式。如果需要,我可以将其直接写入文件。谢了哥们!唯一的问题是它读取 cmets 以及文本。可以在find_all_next方法的搜索中排除cmets吗?
  • 也许我可以使用extract 方法从选定的文本正文中提取 cmets(除了我需要的两个)?我会试试的。
  • 做到了。在我们用soup.findAll 列出 cmets 后,我添加了[cmt.extract() for cmt in comments if cmt.string != start and cmt.string != end] 行,其中 start 和 end 是开始和结束 cmets 的字符串。今晚我学到了一些新东西。您是个巫师,感谢您抽出宝贵时间!
  • 我确实想为这个问题的未来观众提出一个可能的替代方案(我在 Oliver W. 的出色解决方案之前拥有的),那就是 Aaron Swartz 的 html2text。它可以将 html 极好地还原为 markdown 语言中的文本。它工作得很好,但对于我在这里所做的事情来说并不是最好的解决方案。仅供参考。
猜你喜欢
  • 2020-12-22
  • 1970-01-01
  • 2021-12-23
  • 2023-01-03
  • 2014-05-22
  • 2016-01-09
  • 1970-01-01
  • 1970-01-01
  • 2015-01-27
相关资源
最近更新 更多