web-dev-qa-db-fra.com

Comment puis-je effectuer le décodage/encodage HTML à l'aide de Python/Django?

J'ai une chaîne qui est codée en 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" />

Je veux changer cela en:

<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" /> 

Je veux que cela soit enregistré en HTML afin qu'il soit rendu sous forme d'image par le navigateur au lieu d'être affiché en tant que texte. 

J'ai trouvé comment faire cela en C # mais pas en Python. Est-ce que quelqu'un peut m'aider?

Merci.

Edit: Quelqu'un a demandé pourquoi mes chaînes sont stockées comme ça. C'est parce que j'utilise un outil de nettoyage Web qui "analyse" une page Web et en extrait un certain contenu. L'outil (BeautifulSoup) renvoie la chaîne dans ce format.

En relation

113
rksprst

Étant donné le cas d'utilisation de Django, il y a deux réponses à cela. Voici sa fonction Django.utils.html.escape, pour référence:

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

Pour inverser cela, la fonction Cheetah décrite dans la réponse de Jake devrait fonctionner, mais il manque la citation simple. Cette version inclut un tuple mis à jour, avec l'ordre de remplacement inversé pour éviter les problèmes symétriques:

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)

Ce n’est cependant pas une solution générale; il ne convient que pour les chaînes encodées avec Django.utils.html.escape. Plus généralement, c'est une bonne idée de s'en tenir à la bibliothèque standard:

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

À titre de suggestion: il peut être plus judicieux de stocker le code HTML non échappé dans votre base de données. Dans la mesure du possible, il serait intéressant de chercher à obtenir des résultats non échappés de BeautifulSoup et d'éviter ce processus.

Avec Django, l'échappement ne se produit que lors du rendu du modèle; pour éviter de vous échapper, il vous suffit de dire au moteur de gabarit de ne pas échapper à votre chaîne. Pour ce faire, utilisez l'une des options suivantes dans votre modèle:

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

Avec la bibliothèque standard:

  • HTML Escape

    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

Pour l'encodage HTML, il y a cgi.escape de la bibliothèque standard:

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

Pour le décodage HTML, j'utilise les éléments suivants:

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)

Pour tout ce qui est plus compliqué, j'utilise BeautifulSoup.

80
user26294

Utilisez la solution de daniel si l'ensemble des caractères codés est relativement restreint ..__ Sinon, utilisez l'une des nombreuses bibliothèques d'analyse HTML.

J'aime BeautifulSoup car il peut gérer du XML/HTML mal formé:

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

pour votre question, il y a un exemple dans leur documentation

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

En Python 3.4+:

import html

html.unescape(your_string)
8
Collin Anderson

Voir au bas de cette page sur le wiki Python , il existe au moins deux options pour "détourner" le code HTML.

8
zgoda

Le commentaire de Daniel comme réponse:

"L’échappement ne se produit que dans Django lors du rendu du modèle. Par conséquent, il n’est pas nécessaire de créer unescape. Vous indiquez simplement au moteur de modélisation de ne pas s’échapper. % endautoescape%} "

6
dfrankow

J'ai trouvé une fonction intéressante sur: 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

Même si c'est une question très ancienne, cela peut fonctionner.

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

Si quelqu'un cherche un moyen simple de le faire via les modèles Django, vous pouvez toujours utiliser des filtres comme celui-ci:

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

J'avais des données provenant d'un fournisseur et tout ce que j'ai posté avait des balises HTML réellement écrites sur la page rendue comme si vous regardiez la source. Le code ci-dessus m'a beaucoup aidé . J'espère que cela aidera les autres.

À votre santé!!

3
Chris Harty

Vous pouvez également utiliser Django.utils.html.escape

from Django.utils.html import escape

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

J'ai trouvé cela dans le code source de Cheetah ( ici )

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

je ne sais pas pourquoi ils inversent la liste, Je pense que cela a à voir avec la façon dont ils encodent, donc avec vous ça n’aura peut-être pas besoin d’être inversé . cela va dans ma bibliothèque cependant :)

j'ai remarqué que votre titre demandait aussi un encodage, voici donc la fonction d'encodage de Cheetah.

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

En recherchant la solution la plus simple de cette question dans Django et Python, j’ai trouvé que vous pouvez utiliser leurs fonctions intégrées pour échapper/décompresser le code html.

Exemple

J'ai enregistré votre code HTML dans scraped_html et clean_html:

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

Vous avez besoin de Django> = 1.0

unescape

Pour libérer votre code HTML récupéré, vous pouvez utiliser Django.utils.text.unescape_entities qui:

Convertissez toutes les références de caractères nommés et numériques aux caractères Unicode correspondants.

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

escape

Pour échapper à votre code HTML propre, vous pouvez utiliser Django.utils.html.escape qui:

Retourne le texte donné avec des esperluettes, des guillemets et des chevrons encodés pour une utilisation en HTML.

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

Python

Vous avez besoin de Python> = 3.4

unescape

Pour libérer votre code HTML récupéré, vous pouvez utiliser html.unescape qui:

Convertissez toutes les références de caractères nommés et numériques (par exemple, &gt;, &#62;, &x3e;) de la chaîne s aux caractères unicode correspondants.

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

escape

Pour échapper à votre code HTML propre, vous pouvez utiliser html.escape qui:

Convertissez les caractères &, < et > de la chaîne s en séquences compatibles HTML.

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

Vous trouverez ci-dessous une fonction python utilisant le module htmlentitydefs. Ce n'est pas parfait. La version de htmlentitydefs que j'ai est incomplète et suppose que toutes les entités décodent en un seul point de code, ce qui est faux pour des entités comme &NotEqualTilde;:

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

NotEqualTilde;     U+02242 U+00338    ≂̸

Avec ces mises en garde, voici le 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

C’est la solution la plus simple à ce problème - 

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

De cette page .

0
smilitude