Пользовательская ширина отступа для BeautifulSoup.prettify()
Есть ли способ определить пользовательскую ширину отступа для функции .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, дайте мне знать.
Ответы
Ответ 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
в классе. Это не является существенным для решения, но пусть это все равно, и сделайте ширину отступа вместо параметра hardcoding до 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
, то же дело.
Ответ 2
Насколько я могу судить, эта функция не встроена, поскольку для этой проблемы существует несколько решений.
Предполагая, что вы используете BeautifulSoup 4, вот решения, которые я придумал
Hardcode it in. Это требует минимальных изменений, это нормально, если вам не нужно, чтобы отступ был другим в разных обстоятельствах:
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
Еще одна проблема с предыдущим решением заключается в том, что текстовое содержимое не будет отступать полностью, но привлекательно. Если вам нужно более гибкое/последовательное решение, вы можете просто изменить класс.
Найдите функцию prettify и измените ее как таковую (она находится в классе Tag в элементе .py):
#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 и внесите следующие изменения:
if pretty_print:
#space = (' ' * (indent_level - 1))
space = (' ' * (indent_level - Tag.myTab))
#indent_contents = indent_level + Tag.myTab
indent_contents = indent_level + Tag.myTab
Затем перейдите к методу decode_contents в классе Tag и внесите следующие изменения:
#s.append(" " * (indent_level - 1))
s.append(" " * (indent_level - Tag.myTab))
Теперь BeautifulSoup ('<root> <child> <desc> Text </desc> </child> </root> '). prettify (myTab = 4) вернет:
<root>
<child>
<desc>
Text
</desc>
</child>
</root>
** Не нужно исправлять класс BeautifulSoup, поскольку он наследует класс Tag. Класс Patching Tag достаточно для достижения цели.