繁体   English   中英

使用可保留 AND 西里尔字符的格式化程序使用 BeautifulSoup 进行美化?

[英]Prettify with BeautifulSoup using a formatter that will preserve &nbsp AND Cyrillic characters?

我正在用 python 和 BeautifulSoup4 生成一些 HTML。 最后,我想美化生成的 HTML。 如果我美化如下:

soup.prettify()

BeautifulSoup 将所有 &nbsp 字符转换为空格。 不幸的是,我的网页依赖于这些 &nbsp 字符。 经过一些指导,我意识到可以通过提供格式化程序来美化:

soup.prettify(formatter='html')

不幸的是,当我这样做时,尽管保留了 &nbsp 字符,但 BeautifulSoup 会在我的 HTML 中对西里尔文(俄语)字符进行编码,使我无法读取它们。 这使我无法使用 formatter='html' 选项。

formatter='minimal'formatter=None也不起作用;他们不理会西里尔文,但带走了 &nbsp。)

查看BeautifulSoup 文档后,我意识到您可以使用 BeautifulSoup 的 Formatter 类指定自己的自定义格式化程序。 不幸的是,我不确定这个类是如何工作的。 我试图找到 Formatter 类的文档,但我无法找到。 有谁知道是否可以编写自定义格式化程序,它会告诉 BeautifulSoup 保留 &nbsp 字符(并保留我的西里尔字符)? 或者,是否有任何关于此类如何工作的文档? BS 文档的那部分中有一些示例,但是在阅读它们之后,我仍然不清楚如何完成我想要完成的任务。

编辑:我发现了不同的文档,这使它更加清晰。 自定义格式化程序只是您传递给“格式化程序”参数的一个函数(即prettify(formatter=my_func) ,其中 my_func 是您自己定义的函数); 它为遇到的每个字符串和属性值调用一次,将该值传递给函数并使用函数返回的任何内容作为 prettify 的输出。 我已经尝试编写自己的格式化程序函数,并且我能够检测到 &nbsp 是否存在,但不确定从该函数返回什么,因此 prettify 将输出 &nbsp。 请参阅下面的“示例 3”,了解我的虚拟格式化程序来检测 &nsbp。

这是一个演示问题的虚拟示例:

示例 1:在没有格式化程序的情况下使用 prettify

from bs4 import BeautifulSoup
hello = '<span>Привет,&nbspмир</span>'
soup = BeautifulSoup(hello, 'html.parser')
print("\nBefore prettify:\n{}".format(soup))
soup = soup.prettify()
print("\nAfter prettify:\n{}".format(soup))

输出 - 西里尔字符很好,但 &nbsp 被转换为 ws

Before prettify:
<span>Привет, мир</span>

After prettify:
<span>
 Привет, мир
</span>

示例 2:将 prettify 与 formatter='html' 一起使用

from bs4 import BeautifulSoup
hello = '<span>Привет,&nbspмир</span>'
soup = BeautifulSoup(hello, 'html.parser')
print("\nBefore prettify:\n{}".format(soup))
soup = soup.prettify(formatter='html')
print("\nAfter prettify:\n{}".format(soup))

输出: &nbsp 被保留,但西里尔字符被转换为不可读

Before prettify:
<span>Привет, мир</span>

After prettify:
<span>
 &Pcy;&rcy;&icy;&vcy;&iecy;&tcy;,&nbsp;&mcy;&icy;&rcy;
</span>

示例 3:提供自定义格式化程序。 就示例而言,这只是一个虚拟格式化程序,用于检测 &nbsp 是否存在。 如果我希望 &nbsp 被保留,我应该从这个函数返回什么? (ps,似乎&nbsp 被解析为 \\xa0 ,这就是我以这种方式检查它的原因)

def check_for_nbsp(str):
    if '\xa0' in str:
        return str+" <-- HAS"
    else:
        return str+" <-- DOESN'T HAVE"

hello = '<span>Привет,&nbspмир</span>'
soup = BeautifulSoup(hello, 'html.parser')
print("\nBefore prettify:\n{}".format(soup))
soup = soup.prettify(formatter=check_for_nbsp)
print("\nAfter prettify:\n{}".format(soup))

输出:

Before prettify:
<span>Привет, мир</span>

After prettify:
<span>
 Привет, мир <-- HAS
</span>

有没有办法两全其美 - 保留 &nbsp 和西里尔字母? 或者,除了BeautifulSoup之外,是否有一个真正的python包可以美化HTML?

这是我之前发布的有关修改西里尔字母的Stackoverflow 问题- 这让我明白我应该删除 formatter='html' 选项,不幸的是这删除了 ​​&nbsp 字符,这同样有问题。

我在这些文档中发现了bs4.dammit模块中的EntitySubstitution类。 它将 Beautiful Soup 的标准格式化程序实现为类方法 - “html”格式化程序(保留 &nbsp 字符)是EntitySubstitution.substitute_html 这将允许您获得格式化程序的行为,但随后会做一些额外的事情。

(ps, &nbsp 在 BeautifulSoup 中被解析为 \\xa0 )

这是代码:

from bs4 import BeautifulSoup
from bs4.dammit import EntitySubstitution # don't miss this import statement!

'''
this is the custom formatter.
prettify will call this function every String and attribute value encountered;
it is going to display whatever you return, in the prettified output

Strategy:
 - Split the string on &nbsp characters.
 - For portion that's not &nbsp - return as is.
 - For portion that's &nbsp - run it through EntitySubstitution.substitute_html,
   which will preserve the &nbsp)
'''
def preserve_nbsp_and_ru(str):
    newstr = ""
    split_str = str.split('\xa0') # &nbsp are parsed as \xa0 in BS
    # (this will split a&nbspb&nsbp&c --> [a,b,c])
    for i, space_between in enumerate(split_str):
        # space_between will be regular text, preserve it as is
        newstr += space_between
        # add an &nbsp after it, unless you're on the last
        # item in the list, after which there would not be an &nbsp
        if i < len(split_str) - 1:
            # put the nbsp through the EntitySubstitution function
            # which will preserve it
            newstr += EntitySubstitution.substitute_html('\xa0')
    return newstr

hello = '<span>Привет,&nbspмир</span>'
soup = BeautifulSoup(hello, 'html.parser')
print("\nBefore prettify:\n{}".format(soup))
soup = soup.prettify(formatter=preserve_nbsp_and_ru)
print("\nAfter prettify:\n{}".format(soup))

输出:

Before prettify:
<span>Привет, мир</span>

After prettify:
<span>
 Привет,&nbsp;мир
</span>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM