python-3.x - 使用将保留 AND 西里尔字符的格式化程序使用 BeautifulSoup 进行美化?
问题描述
我正在使用 python 和 BeautifulSoup4 生成一些 HTML。最后,我想美化生成的 HTML。如果我美化如下:
soup.prettify()
BeautifulSoup 将所有 字符转换为空格。不幸的是,我的网页依赖于这些 字符。经过一些指导,我意识到可以通过提供格式化程序来美化:
soup.prettify(formatter='html')
不幸的是,当我这样做时,尽管 字符被保留,BeautifulSoup 在我的 HTML 中对西里尔文(俄语)字符进行编码,使它们对我来说不可读。这使我无法使用 formatter='html' 选项。
(formatter='minimal'
而且formatter=None
也不起作用;他们不理会西里尔文,但带走了 。)
查看BeautifulSoup 文档后,我意识到您可以使用 BeautifulSoup 的 Formatter 类指定您自己的自定义格式化程序。不幸的是,我不确定这个类是如何工作的。我试图找到 Formatter 类的文档,但我找不到。有谁知道是否可以编写一个自定义格式化程序,它会告诉 BeautifulSoup 保留 字符(并留下我的西里尔字符)?或者,有没有关于这个类是如何工作的文档?BS 文档的该部分中有一些示例,但是在阅读了它们之后,我仍然不清楚如何完成我想要完成的工作。
编辑:我找到了不同的文档,这使得它更加清晰。自定义格式化程序只是您传递给“格式化程序”参数的函数(即prettify(formatter=my_func)
,其中 my_func 是您自己定义的函数);它为遇到的每个字符串和属性值调用一次,将该值传递给函数并使用函数返回的任何内容作为 prettify 中的输出。我已经尝试编写自己的格式化程序函数,并且我能够检测是否存在 ,但不确定从函数返回什么,以便 prettify 将输出 。请参阅下面的“示例 3”,了解我的虚拟格式化程序以检测 &nsbp。
这是一个演示问题的虚拟示例:
示例 1:在没有格式化程序的情况下使用美化
from bs4 import BeautifulSoup
hello = '<span>Привет, мир</span>'
soup = BeautifulSoup(hello, 'html.parser')
print("\nBefore prettify:\n{}".format(soup))
soup = soup.prettify()
print("\nAfter prettify:\n{}".format(soup))
输出 - 西里尔字符很好,但 转换为 ws
Before prettify:
<span>Привет, мир</span>
After prettify:
<span>
Привет, мир
</span>
示例 2:使用带有 formatter='html' 的美化
from bs4 import BeautifulSoup
hello = '<span>Привет, мир</span>'
soup = BeautifulSoup(hello, 'html.parser')
print("\nBefore prettify:\n{}".format(soup))
soup = soup.prettify(formatter='html')
print("\nAfter prettify:\n{}".format(soup))
输出: 被保留,但西里尔字符被转换为不可读
Before prettify:
<span>Привет, мир</span>
After prettify:
<span>
Привет, мир
</span>
示例 3:提供自定义格式化程序。为了示例的目的,这只是一个虚拟格式化程序,用于检测 是否存在。如果我想保留 ,我应该从这个函数返回什么?(ps,似乎 被解析为 \xa0,这就是我以这种方式检查它的原因)
def check_for_nbsp(str):
if '\xa0' in str:
return str+" <-- HAS"
else:
return str+" <-- DOESN'T HAVE"
hello = '<span>Привет, мир</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>
有没有办法两全其美 - 保留 和西里尔字符?或者,除了 BeautifulSoup 之外,是否有一个可靠的 python 包可以美化 HTML?
这是我之前发布的关于修改西里尔字符的 Stackoverflow 问题 - 这就是让我明白我应该删除 formatter='html' 选项的原因,不幸的是这会删除 字符,这同样是有问题的。
解决方案
我能够解决这个问题。我在这些文档中发现了关于模块EntitySubstitution
中的类。bs4.dammit
它将 Beautiful Soup 的标准格式化程序实现为类方法——“html”格式化程序(保留 字符)是EntitySubstitution.substitute_html
. 这将允许您获得该格式化程序行为,但随后会做额外的事情。
(ps, 在 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   characters.
- For portion that's not   - return as is.
- For portion that's   - run it through EntitySubstitution.substitute_html,
which will preserve the  )
'''
def preserve_nbsp_and_ru(str):
newstr = ""
split_str = str.split('\xa0') #   are parsed as \xa0 in BS
# (this will split a b&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   after it, unless you're on the last
# item in the list, after which there would not be an  
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>Привет, мир</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>
Привет, мир
</span>
推荐阅读
- rest - Rest api vs sqoop
- typescript - 按键访问时返回类型化对象属性
- c# - 在编译时循环遍历类中的所有对象 C#
- grails - 如何在 Grails 中使用自定义身份验证过滤器?
- regex - 如果单词以给定的后缀结尾,则替换所有出现的字母
- php - 插入电源后,PHP SESSION 在 iPad 上死机。铬应用
- java - 在 Ubuntu 中执行 Jmeter 脚本,遇到错误
- javascript - 当我们不知道数据的嵌套级别时,如何在 react/redux 的 reducer 状态属性中更新数据?
- android - firebase 数据库更改时向应用程序用户(android)推送通知?
- qt - 如何不在控制台上打印 Qt 内部消息?