web-dev-qa-db-fra.com

Comment imprimer assez HTML dans un fichier, avec une indentation

J'utilise lxml.html pour générer du HTML. Je veux imprimer assez (avec indentation) mon résultat final dans un fichier html. Comment je fais ça?

C'est ce que j'ai essayé et obtenu jusqu'à présent (je suis relativement nouveau pour Python et 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")

Comme vous pouvez le voir, j'utilise le pretty_print=True attribut. Je pensais que cela donnerait du code en retrait, mais cela n'aide pas vraiment. Voici la sortie:

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

55
bcosynot

J'ai fini par utiliser BeautifulSoup directement. C'est quelque chose que lxml.html.soupparser utilise pour analyser HTML.

BeautifulSoup a une méthode prettify qui fait exactement ce qu'elle dit. Il embellit le HTML avec des retraits appropriés et tout.

BeautifulSoup ne corrigera PAS le code HTML, donc le code cassé reste cassé. Mais dans ce cas, puisque le code est généré par lxml, le code HTML doit être au moins sémantiquement correct.

Dans l'exemple donné dans ma question, je devrai faire ceci:

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
80
bcosynot

Bien que ma réponse ne soit peut-être pas utile maintenant, je la laisse tomber ici pour servir de référence à quelqu'un d'autre à l'avenir.

lxml.html.tostring(), en effet, n'imprime pas assez le HTML fourni malgré pretty_print=True.

Cependant, le "frère" de lxml.html - lxml.etree fonctionne bien.

On pourrait donc l'utiliser comme suit:

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))

La sortie est comme ceci:

<html>
  <body>
    <h1>hello world</h1>
  </body>
</html>
31
Jayesh Bhoot

Si vous stockez le code HTML sous forme de chaîne non formatée, dans une variable html_string, cela peut être fait en utilisant beautifulsoup4 comme suit:

from bs4 import BeautifulSoup
print(BeautifulSoup(html_string, 'html.parser').prettify())
11
AlexG

Sous le capot, lxml utilise libxml2 pour sérialiser l'arborescence dans une chaîne. Voici l'extrait de code pertinent qui détermine s'il faut ajouter une nouvelle ligne après la fermeture d'une balise:

    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;

Donc, si un nœud est un élément, n'est pas une balise en ligne et est suivi d'un nœud frère (cur->next != NULL) et ne fait pas partie de p, pre, param alors il affichera une nouvelle ligne.

3
samplebias

Si l'ajout d'une dépendance supplémentaire n'est pas un problème, vous pouvez utiliser le package html5print . L'avantage par rapport aux autres solutions, c'est qu'il embellit également le code CSS et Javascript incorporé dans le document HTML.

Pour l'installer, exécutez:

pip install html5print

Ensuite, vous pouvez soit l'utiliser comme une commande:

html5-print ugly.html -o pretty.html

ou comme Python code:

from html5print import HTMLBeautifier
html = '<title>Page Title</title><p>Some text here</p>'
print(HTMLBeautifier.beautify(html, 4))
3
pgmank

J'ai essayé les solutions prettify de BeautifulSoup et HTMLBeautifier de html5print mais comme j'utilise yattag pour générer du HTML, il semble plus approprié d'utiliser sa fonction indent , qui produit une sortie bien en retrait.

from yattag import indent

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

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

print(result)
2
Vadym Pasko

Ne pourriez-vous pas simplement le diriger dans HTML Tidy ? Soit depuis le Shell, soit via os.system().

2
tsm

Si vous ne vous souciez pas du HTMLness original (par exemple, vous devez absolument prendre en charge ces hordes de clients utilisant Netscpae 2.0, donc avoir <br> au lieu de <br /> est un must), vous pouvez toujours changer votre méthode en "xml", ce qui semble fonctionner. C'est probablement un bogue dans lxml ou dans libxml, mais je n'ai pas pu en trouver la raison.

1
Boaz Yaniv

pas vraiment mon code, je l'ai choisi quelque part

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

Je l'utilise avec:

indent(page)
tostring(page)
1
sherpya