BeautifulSoup .prettify() 的自定义缩进宽度
Posted
技术标签:
【中文标题】BeautifulSoup .prettify() 的自定义缩进宽度【英文标题】:Custom indent width for BeautifulSoup .prettify() 【发布时间】:2013-03-08 17:05:33 【问题描述】:有没有办法为.prettify()
函数定义自定义缩进宽度?从我可以从它的来源获得的信息 -
def prettify(self, encoding=None, formatter="minimal"):
if encoding is None:
return self.decode(True, formatter=formatter)
else:
return self.encode(encoding, True, formatter=formatter)
无法指定缩进宽度。我认为是因为 decode_contents()
函数中的这一行 -
s.append(" " * (indent_level - 1))
固定长度为 1 个空格! (为什么!!)我尝试指定 indent_level=4
,结果就是这样 -
<section>
<article>
<h1>
</h1>
<p>
</p>
</article>
</section>
这看起来很愚蠢。 :|
现在,我可以解决这个问题,但我只是想确定我是否缺少任何东西。因为这应该是一个基本功能。 :-/
如果你有更好的美化 html 代码的方法,请告诉我。
【问题讨论】:
回答您的附带问题(“为什么!”):HTML 和 XML 往往嵌套非常非常深,我猜 Crummy 的家伙喜欢 80 列窗口。但是您可能想要发布到邮件列表/组和/或提交请求此功能的错误(并且,由于补丁非常简单 - 并且 ramabodhi 已经为您编写了很多 - 您应该将其包含在您的电子邮件/错误中报告)。 几年前好像有人向邮件列表提交了一个针对 3.2 的类似补丁。见here。 "1-空格缩进看起来很愚蠢。:|" - 谢谢。这正是我在寻找这个问题时的想法。 【参考方案1】:实际上,我自己处理了这个问题,采用了最老套的方式:通过对结果进行后处理。
r = re.compile(r'^(\s*)', re.MULTILINE)
def prettify_2space(s, encoding=None, formatter="minimal"):
return r.sub(r'\1\1', s.prettify(encoding, formatter))
实际上,我在课堂上用猴子补丁prettify_2space
代替了prettify
。这对解决方案来说不是必需的,但无论如何让我们这样做,并将缩进宽度作为参数而不是将其硬编码为 2:
orig_prettify = bs4.BeautifulSoup.prettify
r = re.compile(r'^(\s*)', re.MULTILINE)
def prettify(self, encoding=None, formatter="minimal", indent_width=4):
return r.sub(r'\1' * indent_width, orig_prettify(self, encoding, formatter))
bs4.BeautifulSoup.prettify = prettify
所以:
x = '''<section><article><h1></h1><p></p></article></section>'''
soup = bs4.BeautifulSoup(x)
print(soup.prettify(indent_width=3))
…给出:
<html>
<body>
<section>
<article>
<h1>
</h1>
<p>
</p>
</article>
</section>
</body>
</html>
显然,如果你想修补Tag.prettify
和BeautifulSoup.prettify
,你必须在那里做同样的事情。 (您可能想要创建一个可以应用于两者的通用包装器,而不是重复自己。)如果有任何其他 prettify
方法,同样的处理。
【讨论】:
中断<pre>
【参考方案2】:
据我所知,这个功能不是内置的,因为有一些解决方案可以解决这个问题。
假设您使用的是 BeautifulSoup 4,这是我想出的解决方案
硬编码。这需要最少的更改,如果您不需要缩进在不同情况下有所不同,这很好:
myTab = 4 # add this
if pretty_print:
# space = (' ' * (indent_level - 1))
space = (' ' * (indent_level - myTab))
#indent_contents = indent_level + 1
indent_contents = indent_level + myTab
先前解决方案的另一个问题是文本内容不会完全一致地缩进,但仍然很吸引人。如果您需要更灵活/一致的解决方案,您只需修改类即可。
找到美化函数并修改成这样(它位于element.py中的Tag类中):
#Add the myTab keyword to the functions parameters (or whatever you want to call it), set it to your preferred default.
def prettify(self, encoding=None, formatter="minimal", myTab=2):
Tag.myTab= myTab # add a reference to it in the Tag class
if encoding is None:
return self.decode(True, formatter=formatter)
else:
return self.encode(encoding, True, formatter=formatter)
然后向上滚动到 Tag 类中的 decode 方法并进行以下更改:
if pretty_print:
#space = (' ' * (indent_level - 1))
space = (' ' * (indent_level - Tag.myTab))
#indent_contents = indent_level + Tag.myTab
indent_contents = indent_level + Tag.myTab
然后转到 Tag 类中的 decode_contents 方法并进行这些更改:
#s.append(" " * (indent_level - 1))
s.append(" " * (indent_level - Tag.myTab))
现在 BeautifulSoup('
<root>
<child>
<desc>
Text
</desc>
</child>
</root>
**无需修补 BeautifulSoup 类,因为它继承了 Tag 类。修补 Tag 类足以达到目的。
【讨论】:
这应该很容易转换成针对bs4源代码树的补丁,很方便。 OP 可以自己创建 bzr 树的分支并对其进行修补,向上游提交修补程序,等等。 谢谢大家。我简直不敢相信这些年只有一个人有这个问题并提出了一个补丁,它仍然没有被合并。我已经修改了函数以获取可变长度(因为我讨厌硬编码)。它几乎可以满足您的建议。但问题是你需要为indent_level
提供一些东西,因为这条线pretty_print = (indent_level is not None)
而我看到indent_level
的默认值是None
,并且没有动态的方法来改变它。 <_>【参考方案3】:
这是一种在不干预原始函数等的情况下增加缩进的方法。创建以下函数:
# Increase indentation of 'text' by 'n' spaces
def add_indent(text,n):
sp = " "*n
lsep = chr(10) if text.find(chr(13)) == -1 else chr(13)+chr(10)
lines = text.split(lsep)
for i in range(len(lines)):
spacediff = len(lines[i]) - len(lines[i].lstrip())
if spacediff: lines[i] = sp*spacediff + lines[i]
return lsep.join(lines)
然后用上面的函数转换你得到的文本:
x = '''<section><article><h1></h1><p></p></article></section>'''
soup = bs4.BeautifulSoup(x, 'html.parser') # I don't know if you need 'html.parser'
text = soup.prettify() # I do, otherwise I get a warning
text = add_indent(text,1) # Increase indentation by 1 space
print(text)
'''
Output:
<html>
<body>
<section>
<article>
<h1>
</h1>
<p>
</p>
</article>
</section>
</body>
</html>
'''
【讨论】:
中断<pre>
@Mila Nautijus, <pre>
???
是的,<pre>。空格必须保留在前标签中以上是关于BeautifulSoup .prettify() 的自定义缩进宽度的主要内容,如果未能解决你的问题,请参考以下文章