Как Pretty Print HTML в файл, с отступом - PullRequest
54 голосов
/ 27 мая 2011

Я использую lxml.html для генерации HTML. Я хочу распечатать (с отступом) мой окончательный результат в HTML-файл. Как мне это сделать?

Это то, что я пробовал и получил до сих пор (я относительно новичок в Python и lxml):

import lxml.html as lh
from lxml.html import builder as E
sliderRoot=lh.Element("div", E.CLASS("scroll"), style="overflow-x: hidden; overflow-y: hidden;")
scrollContainer=lh.Element("div", E.CLASS("scrollContainer"), style="width: 4340px;")
sliderRoot.append(scrollContainer)
print lh.tostring(sliderRoot, pretty_print = True, method="html")

Как видите, я использую атрибут pretty_print=True. Я думал, что это даст код с отступом, но это не очень помогает. Это вывод:

<div style="overflow-x: hidden; overflow-y: hidden;" class="scroll"><div style="width: 4340px;" class="scrollContainer"></div></div>

Ответы [ 9 ]

79 голосов
/ 29 мая 2011

Я использовал BeautifulSoup напрямую.Это то, что lxml.html.soupparser использует для анализа HTML.

BeautifulSoup имеет метод prettify, который выполняет именно то, что говорит.Он корректирует HTML правильными отступами и всем прочим.

BeautifulSoup НЕ исправит HTML, поэтому неработающий код остается неработающим.Но в этом случае, поскольку код генерируется с помощью lxml, HTML-код должен быть как минимум семантически правильным.

В примере, приведенном в моем вопросе, я должен буду сделать это:

from BeautifulSoup import BeautifulSoup as bs
root = lh.tostring(sliderRoot) #convert the generated HTML to a string
soup = bs(root)                #make BeautifulSoup
prettyHTML = soup.prettify()   #prettify the html
31 голосов
/ 12 мая 2013

Хотя мой ответ сейчас может оказаться бесполезным, я опускаю его здесь, чтобы он мог служить ссылкой на кого-то еще в будущем.

lxml.html.tostring(), действительно, не очень хорошо печатает предоставленный HTML, несмотря на pretty_print=True.

Однако у «брата» из lxml.html - lxml.etree все работает хорошо.

Так что можно использовать его следующим образом:

from lxml import etree, html

document_root = html.fromstring("<html><body><h1>hello world</h1></body></html>")
print(etree.tostring(document_root, encoding='unicode', pretty_print=True))

Вывод выглядит так:

<html>
  <body>
    <h1>hello world</h1>
  </body>
</html>
11 голосов
/ 13 ноября 2017

Если вы храните HTML в виде неотформатированной строки в переменной html_string, это можно сделать с помощью beautifulsoup4 следующим образом:

from bs4 import BeautifulSoup
print(BeautifulSoup(html_string, 'html.parser').prettify())
3 голосов
/ 19 марта 2018

Если добавление еще одной зависимости не является проблемой, вы можете использовать пакет html5print .Преимущество перед другими решениями заключается в том, что он также украшает как CSS, так и код JavaScript, встроенный в документ HTML.

Чтобы установить его, выполните:это как команда:

html5-print ugly.html -o pretty.html

или как код Python:

from html5print import HTMLBeautifier
html = '<title>Page Title</title><p>Some text here</p>'
print(HTMLBeautifier.beautify(html, 4))
3 голосов
/ 27 мая 2011

Под капотом lxml использует libxml2 для сериализации дерева обратно в строку.Вот соответствующий фрагмент кода, который определяет, следует ли добавлять новую строку после закрытия тега:

    xmlOutputBufferWriteString(buf, ">");
    if ((format) && (!info->isinline) && (cur->next != NULL)) {
        if ((cur->next->type != HTML_TEXT_NODE) &&
            (cur->next->type != HTML_ENTITY_REF_NODE) &&
            (cur->parent != NULL) &&
            (cur->parent->name != NULL) &&
            (cur->parent->name[0] != 'p')) /* p, pre, param */
            xmlOutputBufferWriteString(buf, "\n");
    }
    return;

Так что, если узел является элементом, он не является встроенным тегом и за ним стоит , за которым следует брат или сестраузел (cur->next != NULL) и не является одним из p, pre, param, тогда он выведет новую строку.

2 голосов
/ 06 мая 2018

Я попробовал оба решения BeautifulSoup prettify и html5print HTMLBeautifier, но, поскольку я использую yattag для генерации HTML, кажется более уместным использовать его функцию indent, которая производит вывод с хорошим отступом.

from yattag import indent

rawhtml = "String with some HTML code..."

result = indent(
    rawhtml,
    indentation = '    ',
    newline = '\r\n',
    indent_text = True
)

print(result)
2 голосов
/ 27 мая 2011

Не могли бы вы просто передать это в HTML Tidy ?Либо из оболочки, либо через os.system().

1 голос
/ 27 мая 2011

не совсем мой код, я его где-то выбрал

def indent(elem, level=0):
    i = '\n' + level * '  '
    if len(elem):
        if not elem.text or not elem.text.strip():
            elem.text = i + '  '
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
        for elem in elem:
            indent(elem, level+1)
        if not elem.tail or not elem.tail.strip():
            elem.tail = i
    else:
        if level and (not elem.tail or not elem.tail.strip()):
            elem.tail = i

Я использую его с:

indent(page)
tostring(page)
1 голос
/ 27 мая 2011

Если вас не волнует причудливость HTMLness (например, вы должны поддерживать абсолютную поддержку тех орд клиентов Netscpae 2.0, которые используют, поэтому наличие <br> вместо <br /> является обязательным), вы всегда можете изменить свой метод на «XML», который, кажется, работает. Вероятно, это ошибка в lxml или libxml, но я не смог найти причину для этого.

...