Пользовательская ширина отступа для BeautifulSoup.prettify() - программирование
Подтвердить что ты не робот

Пользовательская ширина отступа для 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, дайте мне знать.

4b9b3361

Ответ 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 достаточно для достижения цели.