Как мне выполнить декодирование / кодирование HTML с использованием Python / Django? - PullRequest
116 голосов
/ 08 ноября 2008

У меня есть строка в кодировке 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" />'''

Я хочу изменить это на:

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

Я хочу, чтобы это было зарегистрировано как HTML, чтобы оно отображалось браузером как изображение, а не как текст.

Строка хранится таким образом, потому что я использую инструмент для очистки веб-страниц с именем BeautifulSoup, он «сканирует» веб-страницу и получает от нее определенный контент, а затем возвращает строку формат.

Я нашел, как это сделать в C # , но не в Python . Кто-нибудь может мне помочь?

Относящиеся

Ответы [ 15 ]

107 голосов
/ 17 августа 2011

со стандартной библиотекой:

  • 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 голосов
/ 09 ноября 2008

Учитывая вариант использования Django, есть два ответа на это. Вот его django.utils.html.escape функция, для справки:

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

Чтобы изменить это, функция Cheetah, описанная в ответе Джейка, должна работать, но в ней отсутствует одинарная кавычка. Эта версия включает в себя обновленный кортеж, порядок замены которого изменен, чтобы избежать симметричных проблем:

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)

Это, однако, не является общим решением; он подходит только для строк, закодированных с django.utils.html.escape. В целом, лучше придерживаться стандартной библиотеки:

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

В качестве предложения: может иметь больше смысла хранить неэкранированный HTML-код в вашей базе данных. Было бы целесообразно по возможности вернуть неэкранированные результаты из BeautifulSoup и вообще избежать этого процесса.

В Django экранирование происходит только во время рендеринга шаблона; поэтому, чтобы избежать побега, просто скажите шаблонизатору, чтобы он не избегал строки. Для этого воспользуйтесь одним из следующих параметров в вашем шаблоне:

{{ context_var|safe }}
{% autoescape off %}
    {{ context_var }}
{% endautoescape %}
80 голосов
/ 16 января 2009

Для html-кодирования есть cgi.escape из стандартной библиотеки:

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

Для html-декодирования я использую следующее:

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)

Для чего-то более сложного я использую BeautifulSoup.

20 голосов
/ 09 ноября 2008

Используйте решение Даниэля, если набор закодированных символов относительно ограничен. В противном случае используйте одну из многочисленных библиотек HTML-парсинга.

Мне нравится BeautifulSoup, потому что он может работать с искаженным XML / HTML:

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

на ваш вопрос, есть пример в их документации

from BeautifulSoup import BeautifulStoneSoup
BeautifulStoneSoup("Sacr&eacute; bl&#101;u!", 
                   convertEntities=BeautifulStoneSoup.HTML_ENTITIES).contents[0]
# u'Sacr\xe9 bleu!'
9 голосов
/ 08 июля 2015

В Python 3.4 +:

import html

html.unescape(your_string)
8 голосов
/ 23 ноября 2008

См. В нижней части этой страницы в Python wiki , есть как минимум 2 варианта "unescape" html.

6 голосов
/ 25 октября 2009

Комментарий Даниила как ответ:

"экранирование происходит только в Django во время рендеринга шаблона. Следовательно, нет необходимости в unescape - вы просто указываете шаблонизатору не выходить из системы. }} {% endautoescape%} "

5 голосов
/ 17 июля 2010

Я нашел прекрасную функцию в: 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]
3 голосов
/ 02 февраля 2015

Даже если это действительно старый вопрос, это может сработать.

Джанго 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 голосов
/ 21 декабря 2011

Если кто-то ищет простой способ сделать это с помощью шаблонов django, вы всегда можете использовать такие фильтры:

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

У меня были некоторые данные, поступающие от поставщика, и все, что я опубликовал, содержало HTML-теги, фактически написанные на визуализированной странице, как если бы вы смотрели на источник. Код выше очень помог мне. Надеюсь, что это помогает другим.

Ура !!

...