Generieren von HTML-Dokumenten in Python

70

Was ist in Python die eleganteste Methode zum Generieren von HTML-Dokumenten? Derzeit hänge ich alle Tags manuell an eine riesige Zeichenfolge an und schreibe sie in eine Datei. Gibt es eine elegantere Möglichkeit, dies zu tun?

Schuhe
quelle
3
Mögliches Duplikat des Python-HTML-Generators . Wenn Sie XHTML generieren, sollten Sie auch ein XML-Tool verwenden.
Sie
1
Für Python stehen mehrere Template-Systeme zur Verfügung. Ist es das, wonach du suchst?
George Cummins

Antworten:

61

Ich finde Yattag die eleganteste Art, dies zu tun.

from yattag import Doc

doc, tag, text = Doc().tagtext()

with tag('html'):
    with tag('body'):
        with tag('p', id = 'main'):
            text('some text')
        with tag('a', href='/my-url'):
            text('some link')

result = doc.getvalue()

Es liest sich wie HTML, mit dem zusätzlichen Vorteil, dass Sie keine Tags schließen müssen.

John Smith Optional
quelle
Es gibt eine ähnliche, aber einfachere Alternative: airium: stackoverflow.com/a/63952611/2823074
Mikaelblomkvistsson
33

Ich würde vorschlagen, eine der vielen für Python verfügbaren Vorlagensprachen zu verwenden, zum Beispiel die in Django integrierte (Sie müssen den Rest von Django nicht verwenden, um die Vorlagen-Engine zu verwenden) - eine Google-Abfrage sollte Ihnen viele andere Alternativen bieten Vorlagenimplementierungen.

Ich finde, dass das Erlernen einer Vorlagenbibliothek in vielerlei Hinsicht hilfreich ist: Wenn Sie eine E-Mail, eine HTML-Seite, eine Textdatei oder ähnliches erstellen müssen, schreiben Sie einfach eine Vorlage, laden sie mit Ihrer Vorlagenbibliothek und lassen den Vorlagencode erstellen Das fertige Produkt.

Hier ist ein einfacher Code, um Ihnen den Einstieg zu erleichtern:

#!/usr/bin/env python

from django.template import Template, Context
from django.conf import settings
settings.configure() # We have to do this to use django templates standalone - see
# http://stackoverflow.com/questions/98135/how-do-i-use-django-templates-without-the-rest-of-django

# Our template. Could just as easily be stored in a separate file
template = """
<html>
<head>
<title>Template {{ title }}</title>
</head>
<body>
Body with {{ mystring }}.
</body>
</html>
"""

t = Template(template)
c = Context({"title": "title from code",
             "mystring":"string from code"})
print t.render(c)

Es ist noch einfacher, wenn Sie Vorlagen auf der Festplatte haben - sehen Sie sich die Funktion render_to_string für django 1.7 an, mit der Vorlagen von einer vordefinierten Liste von Suchpfaden von der Festplatte geladen, mit Daten aus einem Wörterbuch gefüllt und in eine Zeichenfolge gerendert werden können - alles in einem Funktionsaufruf. (ab django 1.8 entfernt, vergleichbare Aktion siehe Engine.from_string )

Erik Forsberg
quelle
7
Ich habe darüber nachgedacht, aber ich denke nicht, dass es genau das ist, was das OP verlangt. Es hört sich so an, als ob sie den HTML-Code selbst programmgesteuert aufbauen möchten, während eine Vorlage davon ausgeht, dass Sie den HTML-Code bereits haben, aber nur einige Variablen eingeben müssen.
Daniel Roseman
2
Es hört sich eher so an, als hätten sie den Inhalt fertig und müssten dann HTML um den Inhalt einfügen. Genau dafür ist ein Template-Motor gedacht.
Wilduck
5
Wenn Sie eine Template-Engine wie die in Django möchten, verwenden Sie Jinja2. Es ist schneller, leistungsfähiger und ein eigenständiges Projekt. jinja.pocoo.org/docs
Wilduck
Ich arbeite an einem Projekt, bei dem ich genau so etwas brauche. Ich habe den Code in PyScripter eingefügt. Wie kann ich die HTML-Ausgabe sehen? Speichere ich es als .py-Datei oder .html? Öffne ich es in meinem Browser?
Anon
11

Wenn Sie HTML-Dokumente erstellen, empfehle ich dringend, ein Vorlagensystem (wie jinja2 ) zu verwenden, wie andere vorgeschlagen haben. Wenn Sie eine Low-Level-Generierung von HTML-Bits benötigen (möglicherweise als Eingabe für eine Ihrer Vorlagen), ist das Paket xml.etree ein Standard-Python-Paket und passt möglicherweise gut zur Rechnung.

import sys
from xml.etree import ElementTree as ET

html = ET.Element('html')
body = ET.Element('body')
html.append(body)
div = ET.Element('div', attrib={'class': 'foo'})
body.append(div)
span = ET.Element('span', attrib={'class': 'bar'})
div.append(span)
span.text = "Hello World"

if sys.version_info < (3, 0, 0):
  # python 2
  ET.ElementTree(html).write(sys.stdout, encoding='utf-8',
                             method='html')
else:
  # python 3
  ET.ElementTree(html).write(sys.stdout, encoding='unicode',
                             method='html')

Druckt Folgendes:

<html><body><div class="foo"><span class="bar">Hello World</span></div></body></html>
cheshirekow
quelle
1
Die letzte Zeile Ihres Beispiels schlägt für mich mit dem Argument "TypeError: write () muss str, nicht bytes" fehl, es sei denn, ich ändere es in "sys.stdout.write (ET.tostring (html) .decode (" utf-8 "). )) "
Raúl Salinas-Monteagudo
1
@ RaúlSalinas-Monteagudo: Das ursprüngliche Snippet funktionierte für Python 2 (getestet auf 2.7). Ich habe es so aktualisiert, dass es jetzt auch für Python 3 funktionieren sollte (getestet auf 3.5).
Cheshirekow
Seien Sie sich der Sicherheitsrisiken mit ElementTreeWarning The xml.etree.ElementTree module is not secure against maliciously constructed data. If you need to parse untrusted or unauthenticated data see XML vulnerabilities.
jtpereyda
1
@jtpereyda Es ist gut, diese Tatsache zu beachten, jedoch besteht diese Warnung / Sicherheitsanfälligkeit beim Parsen von XML, während das OP explizit nach dem Generieren (nicht Parsen) von HTML fragt .
Cheshirekow
8

Ich würde empfehlen, xml.dom zu verwenden, um dies zu tun.

http://docs.python.org/library/xml.dom.html

Lesen Sie diese Handbuchseite, sie enthält Methoden zum Aufbau von XML (und damit XHTML). Es erleichtert alle XML-Aufgaben erheblich, einschließlich des Hinzufügens von untergeordneten Knoten, Dokumenttypen, Hinzufügen von Attributen und Erstellen von Textknoten. Dies sollte Ihnen bei den meisten Aufgaben zur Erstellung von HTML behilflich sein.

Es ist auch sehr nützlich für die Analyse und Verarbeitung vorhandener XML-Dokumente.

Hoffe das hilft

PS

Hier ist ein Tutorial, das Ihnen beim Anwenden der Syntax helfen soll

http://www.postneo.com/projects/pyxml/

Scheich Yerbouti
quelle
3
HTML ist keine Teilmenge von XML. Wenn Sie ein XML-Tool verwenden, generieren Sie XHTML, nicht HTML.
Sie
1
Es ist ein schwerwiegender Mangel, dass Python keine Nicht-XML-, HTML-spezifische (z. B. Methoden wie div (id = 'myid', otherattr = '...'), ul () usw.) Version als Standard hat (Es gibt Drittanbieter). Perl und Ruby tun es beide.
JDonner
3

Ich verwende das Code-Snippet, das throw_out_your_templatesfür einige meiner eigenen Projekte bekannt ist:

https://github.com/tavisrudd/throw_out_your_templates

https://bitbucket.org/tavisrudd/throw-out-your-templates/src

Leider gibt es kein Pypi-Paket dafür und es ist nicht Teil einer Distribution, da dies nur als Proof-of-Concept gedacht ist. Ich konnte auch niemanden finden, der den Code nahm und anfing, ihn als tatsächliches Projekt zu pflegen. Trotzdem denke ich, dass es einen Versuch wert ist, auch wenn es bedeutet, dass Sie Ihre eigene Kopie throw_out_your_templates.pymit Ihrem Code versenden müssen.

Ähnlich wie bei dem Vorschlag, yattag von John Smith Optional zu verwenden, müssen Sie für dieses Modul keine Vorlagensprache lernen, und Sie müssen auch nie vergessen, Tags zu schließen oder Sonderzeichen zu zitieren. Alles bleibt in Python geschrieben. Hier ist ein Beispiel für die Verwendung:

html(lang='en')[
  head[title['An example'], meta(charset='UTF-8')],
  body(onload='func_with_esc_args(1, "bar")')[
      div['Escaped chars: ', '< ', u'>', '&'],
      script(type='text/javascript')[
           'var lt_not_escaped = (1 < 2);',
           '\nvar escaped_cdata_close = "]]>";',
           '\nvar unescaped_ampersand = "&";'
          ],
      Comment('''
      not escaped "< & >"
      escaped: "-->"
      '''),
      div['some encoded bytes and the equivalent unicode:',
          '你好', unicode('你好', 'utf-8')],
      safe_unicode('<b>My surrounding b tags are not escaped</b>'),
      ]
  ]
josch
quelle
Das wäre ziemlich interessant. Leider ist es ziemlich antik: Es ist in Python 2 geschrieben. Ich habe versucht, es auf Python 3 zu portieren, kann es aber nicht zum HTML5DocLaufen bringen : Es serialisiert die Document Wrapper nicht wie :-(
Regis
2

Es gibt auch eine schöne, moderne Alternative: airium: https://pypi.org/project/airium/

from airium import Airium

a = Airium()

a('<!DOCTYPE html>')
with a.html(lang="pl"):
    with a.head():
        a.meta(charset="utf-8")
        a.title(_t="Airium example")

    with a.body():
        with a.h3(id="id23409231", klass='main_header'):
            a("Hello World.")

html = str(a) # casting to string extracts the value

print(html)

Druckt eine solche Zeichenfolge:

<!DOCTYPE html>
<html lang="pl">
  <head>
    <meta charset="utf-8" />
    <title>Airium example</title>
  </head>
  <body>
    <h3 id="id23409231" class="main_header">
      Hello World.
    </h3>
  </body>
</html>

Der größte Vorteil von airiumist - es hat auch einen Reverse-Übersetzer, der Python-Code aus HTML-String erstellt. Wenn Sie sich fragen, wie Sie ein bestimmtes HTML-Snippet implementieren können, gibt Ihnen der Übersetzer sofort die Antwort.

Das Repository enthält Tests mit Beispielseiten, die automatisch mit airiumin: tests / documents übersetzt werden . Ein guter Ausgangspunkt (jedes vorhandene Tutorial) ist dieser: tests / documents / w3_architects_example_original.html.py

Mikaelblomkvistsson
quelle
Ich habe yattagin der Vergangenheit (aus der aktuell am höchsten bewerteten Antwort) verwendet, aber diese Lösung gefällt mir besser, da es keinen impliziten gemeinsamen Status zwischen Objekten gibt.
SethMMorton
Oh ja, yattagist die vorherige Generation von airium. Ich empfehle dringend, zu zu wechseln, airiumweil 1. es schöner ist, 2. die Generierung großer Dokumente schneller ist airium(effizienterer Komponist), 3. airiumeinen eigenen Transpiler hat, yattagnicht.
Mikaelblomkvistsson
-4

Ja, Sie suchen nach .writelines-Dateien

Eine Sequenz ist im Allgemeinen eine Liste oder ein Array. Fügen Sie also alle Ihre Zeilen in eine Liste oder ein Array ein. Und werfen Sie sie auf die Funktion unten.

Stellen Sie sicher, dass Sie alle neuen Linienkonstanten aus Ihren Zeichenfolgen entfernen, um die Sicherheit zu gewährleisten

Python-Dokumentation (Suche nach file.writelines)

file.writelines (Sequenz) Schreiben Sie eine Sequenz von Zeichenfolgen in die Datei. Die Sequenz kann ein beliebiges iterierbares Objekt sein, das Zeichenfolgen erzeugt, normalerweise eine Liste von Zeichenfolgen. Es gibt keinen Rückgabewert. (Der Name soll mit readlines () übereinstimmen; writelines () fügt keine Zeilentrennzeichen hinzu.)

Michael Hernandez
quelle
Dies beantwortet die Frage überhaupt nicht.
Mikaelblomkvistsson