it-swarm.com.de

Wie führe ich HTML-Dekodierung/Kodierung mit Python/Django durch

Ich habe eine Zeichenfolge, die HTML kodiert ist: 

<img class="size-medium wp-image-113" 
  style="margin-left: 15px;" title="su1" 
  src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" 
  alt="" width="300" height="194" />

Ich möchte das ändern in:

<img class="size-medium wp-image-113" style="margin-left: 15px;" 
  title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" 
  alt="" width="300" height="194" /> 

Ich möchte, dass dies als HTML registriert wird, sodass es vom Browser als Bild dargestellt wird und nicht als Text angezeigt wird. 

Ich habe gefunden, wie man dies in C # macht, aber nicht in Python. Kann mir jemand helfen?

Vielen Dank.

Edit: Jemand hat gefragt, warum meine Zeichenketten so gespeichert werden. Dies liegt daran, dass ich ein Web-Scraping-Tool verwende, das eine Webseite "scannt" und bestimmte Inhalte von ihr erhält. Das Tool (BeautifulSoup) gibt die Zeichenfolge in diesem Format zurück.

Verbunden

113
rksprst

Im Django-Anwendungsfall gibt es zwei Antworten. Hier ist die Django.utils.html.escape-Funktion als Referenz:

def escape(html):
    """Returns the given HTML with ampersands, quotes and carets encoded."""
    return mark_safe(force_unicode(html).replace('&', '&amp;').replace('<', '&l
t;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;'))

Um dies umzukehren, sollte die in Jakes Antwort beschriebene Cheetah-Funktion funktionieren, jedoch fehlt das einfache Anführungszeichen. Diese Version enthält ein aktualisiertes Tupel, wobei die Reihenfolge des Austauschs umgekehrt wird, um symmetrische Probleme zu vermeiden:

def html_decode(s):
    """
    Returns the ASCII decoded version of the given HTML string. This does
    NOT remove normal HTML tags like <p>.
    """
    htmlCodes = (
            ("'", '&#39;'),
            ('"', '&quot;'),
            ('>', '&gt;'),
            ('<', '&lt;'),
            ('&', '&amp;')
        )
    for code in htmlCodes:
        s = s.replace(code[1], code[0])
    return s

unescaped = html_decode(my_string)

Dies ist jedoch keine generelle Lösung; es ist nur für mit Django.utils.html.escape codierte Zeichenfolgen geeignet. Im Allgemeinen ist es eine gute Idee, bei der Standardbibliothek zu bleiben:

# Python 2.x:
import HTMLParser
html_parser = HTMLParser.HTMLParser()
unescaped = html_parser.unescape(my_string)

# Python 3.x:
import html.parser
html_parser = html.parser.HTMLParser()
unescaped = html_parser.unescape(my_string)

# >= Python 3.5:
from html import unescape
unescaped = unescape(my_string)

Als Vorschlag: Es kann sinnvoller sein, den HTML-Code in Ihrer Datenbank zu speichern. Es lohnt sich, nach Möglichkeit unausgetauschte Ergebnisse von BeautifulSoup zu erhalten, und diesen Vorgang vollständig zu vermeiden.

Bei Django tritt das Escaping nur beim Rendern von Vorlagen auf. Um zu verhindern, dass Sie entkommen, teilen Sie der Templating Engine mit, dass Sie Ihre Zeichenfolge nicht verlassen dürfen. Verwenden Sie dazu eine der folgenden Optionen in Ihrer Vorlage:

{{ context_var|safe }}
{% autoescape off %}
    {{ context_var }}
{% endautoescape %}
105
Daniel Naab

Mit der Standardbibliothek:

  • HTML-Flucht

    try:
        from html import escape  # python 3.x
    except ImportError:
        from cgi import escape  # python 2.x
    
    print(escape("<"))
    
  • HTML Unescape

    try:
        from html import unescape  # python 3.4+
    except ImportError:
        try:
            from html.parser import HTMLParser  # python 3.x (<3.4)
        except ImportError:
            from HTMLParser import HTMLParser  # python 2.x
        unescape = HTMLParser().unescape
    
    print(unescape("&gt;"))
    
106
Jiangge Zhang

Für die HTML-Codierung gibt es cgi.escape aus der Standardbibliothek:

>> help(cgi.escape)
cgi.escape = escape(s, quote=None)
    Replace special characters "&", "<" and ">" to HTML-safe sequences.
    If the optional flag quote is true, the quotation mark character (")
    is also translated.

Für die HTML-Dekodierung verwende ich Folgendes:

import re
from htmlentitydefs import name2codepoint
# for some reason, python 2.5.2 doesn't have this one (apostrophe)
name2codepoint['#39'] = 39

def unescape(s):
    "unescape HTML code refs; c.f. http://wiki.python.org/moin/EscapingHtml"
    return re.sub('&(%s);' % '|'.join(name2codepoint),
              lambda m: unichr(name2codepoint[m.group(1)]), s)

Für alles, was komplizierter ist, verwende ich BeautifulSoup.

80
user26294

Verwenden Sie die Lösung von Daniel, wenn der Satz codierter Zeichen relativ eingeschränkt ist .. Ansonsten verwenden Sie eine der zahlreichen HTML-Parsing-Bibliotheken.

Ich mag BeautifulSoup, weil es mit falschem XML/HTML umgehen kann:

http://www.crummy.com/software/BeautifulSoup/

für Ihre Frage gibt es ein Beispiel in ihrer Dokumentation

from BeautifulSoup import BeautifulStoneSoup
BeautifulStoneSoup("Sacr&eacute; bl&#101;u!", 
                   convertEntities=BeautifulStoneSoup.HTML_ENTITIES).contents[0]
# u'Sacr\xe9 bleu!'
20
vincent

In Python 3.4+:

import html

html.unescape(your_string)
8
Collin Anderson

Siehe unten auf dieser Seite im Python-Wiki , es gibt mindestens zwei Optionen für das "unescape" -Html.

8
zgoda

Daniels Kommentar als Antwort:

"Escape ist nur in Django während des Renderns von Vorlagen möglich. Daher ist keine Unescape erforderlich. Sie müssen der Templating Engine nur mitteilen, dass sie nicht entkommen kann. Entweder % endautoescape%} "

6
dfrankow

Ich habe eine gute Funktion gefunden unter: http://snippets.dzone.com/posts/show/4569

def decodeHtmlentities(string):
    import re
    entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8});")

    def substitute_entity(match):
        from htmlentitydefs import name2codepoint as n2cp
        ent = match.group(2)
        if match.group(1) == "#":
            return unichr(int(ent))
        else:
            cp = n2cp.get(ent)

            if cp:
                return unichr(cp)
            else:
                return match.group()

    return entity_re.subn(substitute_entity, string)[0]
5
slowkvant

Obwohl dies eine wirklich alte Frage ist, kann dies funktionieren.

Django 1.5.5

In [1]: from Django.utils.text import unescape_entities
In [2]: unescape_entities('&lt;img class=&quot;size-medium wp-image-113&quot; style=&quot;margin-left: 15px;&quot; title=&quot;su1&quot; src=&quot;http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;194&quot; /&gt;')
Out[2]: u'<img class="size-medium wp-image-113" style="margin-left: 15px;" title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" alt="" width="300" height="194" />'
3
James

Wenn jemand nach einem einfachen Weg sucht, dies über die Django-Vorlagen zu tun, können Sie immer Filter wie folgt verwenden:

<html>
{{ node.description|safe }}
</html>

Ich hatte einige Daten von einem Anbieter und alles, was ich gepostet hatte, hatte tatsächlich HTML-Tags auf die gerenderte Seite geschrieben, als ob Sie die Quelle betrachten würden. Der obige Code hat mir sehr geholfen. Hoffentlich hilft das anderen.

Prost!!

3
Chris Harty

Sie können auch Django.utils.html.escape verwenden

from Django.utils.html import escape

something_Nice = escape(request.POST['something_naughty'])
1
Seth Gottlieb

Ich habe dies im Cheetah-Quellcode gefunden ( hier )

htmlCodes = [
    ['&', '&amp;'],
    ['<', '&lt;'],
    ['>', '&gt;'],
    ['"', '&quot;'],
]
htmlCodesReversed = htmlCodes[:]
htmlCodesReversed.reverse()
def htmlDecode(s, codes=htmlCodesReversed):
    """ Returns the ASCII decoded version of the given HTML string. This does
        NOT remove normal HTML tags like <p>. It is the inverse of htmlEncode()."""
    for code in codes:
        s = s.replace(code[1], code[0])
    return s

nicht sicher, warum sie die Liste umkehren, Ich denke, es hat mit der Art und Weise zu tun, wie sie kodieren, also muss es bei Ihnen möglicherweise nicht rückgängig gemacht werden .. Auch wenn ich Sie wäre, würde ich htmlCodes ändern, um eine Liste von Tupeln zu sein, anstatt eine Liste von Listen ... das geht zwar in meine Bibliothek :)

ich habe auch bemerkt, dass dein Titel nach encode gefragt wurde. Hier ist Cheetahs encode-Funktion.

def htmlEncode(s, codes=htmlCodes):
    """ Returns the HTML encoded version of the given string. This is useful to
        display a plain ASCII text string on a web page."""
    for code in codes:
        s = s.replace(code[0], code[1])
    return s
1
Jake

Bei der Suche nach der einfachsten Lösung dieser Frage in Django und Python habe ich festgestellt, dass Sie die eingebauten Funktionen verwenden können, um HTML-Code zu entgehen/zu entschlüsseln.

Beispiel

Ich habe Ihren HTML-Code in scraped_html und clean_html gespeichert:

scraped_html = (
    '&lt;img class=&quot;size-medium wp-image-113&quot; '
    'style=&quot;margin-left: 15px;&quot; title=&quot;su1&quot; '
    'src=&quot;http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg&quot; '
    'alt=&quot;&quot; width=&quot;300&quot; height=&quot;194&quot; /&gt;'
)
clean_html = (
    '<img class="size-medium wp-image-113" style="margin-left: 15px;" '
    'title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" '
    'alt="" width="300" height="194" />'
)

Django

Du brauchst Django> = 1.0

unescape

Um den gescrapeten HTML-Code aufzuheben, können Sie Django.utils.text.unescape_entities verwenden.

Konvertieren Sie alle benannten und numerischen Zeichenverweise in die entsprechenden Unicode-Zeichen.

>>> from Django.utils.text import unescape_entities
>>> clean_html == unescape_entities(scraped_html)
True

escape

Um Ihrem sauberen HTML-Code zu entgehen, können Sie Django.utils.html.escape verwenden.

Gibt den angegebenen Text mit kaufmännischen Und-Zeichen, Anführungszeichen und spitzen Klammern zur Verwendung in HTML zurück.

>>> from Django.utils.html import escape
>>> scraped_html == escape(clean_html)
True

Python

Du brauchst Python> = 3.4

unescape

Um den gescrapeten HTML-Code aufzuheben, können Sie html.unescape verwenden.

Konvertieren Sie alle benannten und numerischen Zeichenreferenzen (z. B. &gt;, &#62;, &x3e;) in der Zeichenfolge s in die entsprechenden Unicode-Zeichen.

>>> from html import unescape
>>> clean_html == unescape(scraped_html)
True

escape

Um Ihrem sauberen HTML-Code zu entgehen, können Sie html.escape verwenden.

Konvertieren Sie die Zeichen &, < und > in String s in HTML-sichere Sequenzen.

>>> from html import escape
>>> scraped_html == escape(clean_html)
True
0

Nachfolgend finden Sie eine Python-Funktion, die das Modul htmlentitydefs verwendet. Es ist nicht perfekt. Die Version von htmlentitydefs, die ich habe, ist unvollständig und setzt voraus, dass alle Entitäten zu einem Codepunkt decodiert werden, was für Entitäten wie &NotEqualTilde; falsch ist:

http://www.w3.org/TR/html5/named-character-references.html

NotEqualTilde;     U+02242 U+00338    ≂̸

Mit diesen Vorbehalten ist hier jedoch der Code.

def decodeHtmlText(html):
    """
    Given a string of HTML that would parse to a single text node,
    return the text value of that node.
    """
    # Fast path for common case.
    if html.find("&") < 0: return html
    return re.sub(
        '&(?:#(?:x([0-9A-Fa-f]+)|([0-9]+))|([a-zA-Z0-9]+));',
        _decode_html_entity,
        html)

def _decode_html_entity(match):
    """
    Regex replacer that expects hex digits in group 1, or
    decimal digits in group 2, or a named entity in group 3.
    """
    hex_digits = match.group(1)  # '&#10;' -> unichr(10)
    if hex_digits: return unichr(int(hex_digits, 16))
    decimal_digits = match.group(2)  # '&#x10;' -> unichr(0x10)
    if decimal_digits: return unichr(int(decimal_digits, 10))
    name = match.group(3)  # name is 'lt' when '&lt;' was matched.
    if name:
        decoding = (htmlentitydefs.name2codepoint.get(name)
            # Treat &GT; like &gt;.
            # This is wrong for &Gt; and &Lt; which HTML5 adopted from MathML.
            # If htmlentitydefs included mappings for those entities,
            # then this code will magically work.
            or htmlentitydefs.name2codepoint.get(name.lower()))
        if decoding is not None: return unichr(decoding)
    return match.group(0)  # Treat "&noSuchEntity;" as "&noSuchEntity;"
0
Mike Samuel

Dies ist die einfachste Lösung für dieses Problem - 

{% autoescape on %}
   {{ body }}
{% endautoescape %}

Von dieser Seite .

0
smilitude