使BeautifulSoup句柄像浏览器一样换行

KCz*_*zar 5 html python beautifulsoup

我正在使用BeautifulSoup(Python 3.4版本'4.3.2')将html文档转换为文本。我遇到的问题是,有时网页中的换行符“ \ n”实际上不会在浏览器中显示为换行符,但是当BeautifulSoup将它们转换为文本时,它会留在“ \ n”中。

例:

您的浏览器可能会在一行中呈现以下所有内容(即使中间包含换行符):

这是一个段落。

即使我输入的内容中没有换行符,您的浏览器也可能以多行显示以下内容:

这是一个段落。

这是另一段。

但是,当BeautifulSoup将相同的字符串转换为文本时,它使用的唯一换行符是换行符-并且始终使用它们:

from bs4 import BeautifulSoup

doc = "<p>This is a\nparagraph.</p>"
soup = BeautifulSoup(doc)

soup.text
Out[181]: 'This is a \n paragraph.'

doc = "<p>This is a paragraph.</p><p>This is another paragraph.</p>"
soup = BeautifulSoup(doc)

soup.text
Out[187]: 'This is a paragraph.This is another paragraph.'
Run Code Online (Sandbox Code Playgroud)

有谁知道如何使BeautifulSoup以更漂亮的方式提取文本(或者实际上只是使所有换行符正确)?还有其他解决问题的简单方法吗?

nao*_*oko 12

get_text 在这里可能会有所帮助:

>>> from bs4 import BeautifulSoup
>>> doc = "<p>This is a paragraph.</p><p>This is another paragraph.</p>"
>>> soup = BeautifulSoup(doc)
>>> soup.get_text(separator="\n")
u'This is a paragraph.\nThis is another paragraph.'
Run Code Online (Sandbox Code Playgroud)

  • 此建议适用于“&lt;p&gt;”标记示例,但通常不起作用。例如:`&lt;p&gt;This is some text &lt;font style="white-space:nowrap"&gt;无法换行&lt;/font&gt;到新行。&lt;/p&gt;`将在浏览器中渲染为一行但使用 get_text('\n') 会在 OP 不需要的地方添加一个新行字符。 (3认同)

小智 8

虽然我确实意识到这是一篇旧帖子,但我想强调 bs4 中从标签打印文本的一些行为。

我不是 html 专家,但这些是我在尝试像浏览器一样制作 bs4 打印文本时考虑的几件事 -

我将要描述的行为适用于BeautifulSoup 中的tag.get_text()功能tag.find_all(text=True,recursive=True)

  1. HTML 源代码中的新行

Beautiful soup 打印一个新行(如果它在 html 源代码中可用)

  1. 由于块级元素而隐式换行

Beautiful soup 不会在块元素之前和之后添加新行,就像p标签周围没有源新行一样

  1. <br>标签

如果源包含标签并且标签<br>周围没有源新行, BeautifulSoup 不会打印新行<br>

解决方案

这是一个适用于多种情况的解决方案(限制因素为 -1)所有内联元素的列表 2)CSS/JS 在浏览器环境中运行时如何影响内联性或块性

def get_text(tag: bs4.Tag) -> str:
    _inline_elements = {"a","span","em","strong","u","i","font","mark","label",
    "s","sub","sup","tt","bdo","button","cite","del","b","a","font",}

    def _get_text(tag: bs4.Tag) -> typing.Generator:
        for child in tag.children:
            if isinstance(child, bs4.Tag):
                # if the tag is a block type tag then yield new lines before after
                is_block_element = child.name not in _inline_elements
                if is_block_element:
                    yield "\n"
                yield from ["\n"] if child.name == "br" else _get_text(child)
                if is_block_element:
                    yield "\n"
            elif isinstance(child, bs4.NavigableString):
                yield child.string

    return "".join(_get_text(tag))
Run Code Online (Sandbox Code Playgroud)