如何使用 Python/Django 执行 HTML 解码/编码?

我有一个 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 # 但不在 巨蟒。有人可以帮助我吗?

相关资料

219461 次浏览

我在 Cheetah 源代码(给你)中找到了这个

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

不知道他们为什么要把名单倒过来, 我认为这与他们编码的方式有关,所以对你来说,可能不需要颠倒。 另外,如果我是你,我会将 htmlCodes 改为一个元组列表,而不是一个列表列表..。 这个要放到我的图书馆里

我注意到你的标题也要求编码,所以这里是猎豹的编码功能。

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

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

要逆转这种情况,Jake 的答案中描述的 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 %}

如果编码字符集相对受限,则使用 Daniel 的解决方案。 否则,请使用众多 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!'

在这个 Python 维基页面的底部,至少有两个“ unescape”html 的选项。

对于 html 编码,有来自标准库的 CGI 逃跑:

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

对于任何更复杂的事情,我使用美丽的汤。

丹尼尔的回答是:

”转义仅在模板呈现期间在 Django 中发生。因此,没有必要使用 unescape-您只需告诉模板引擎不要逸出。\{\{ context _ var | safe }}或{% autoescape off% }\{\{ context _ var }}{% endautoescape% }”

我发现了一个很好的功能: 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]

标准图书馆:

  • HTML 转义

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

下面是一个使用模块 htmlentitydefs的 python 函数。这并不完美。我所有的 htmlentitydefs版本是不完整的,它假设所有实体都解码为一个代码点,这对于像 &NotEqualTilde;这样的实体来说是错误的:

Http://www.w3.org/tr/html5/named-character-references.html

NotEqualTilde;     U+02242 U+00338    ≂̸

不过有了这些警告,以下是代码。

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

如果有人正在寻找通过 django 模板实现这一点的简单方法,那么您总是可以使用下面这样的过滤器:

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

我有一些来自供应商的数据,我发布的所有内容都有 html 标签,实际上写在呈现的页面上,就好像你在看源代码一样。

您还可以使用 django.utils.html.escape

from django.utils.html import escape


something_nice = escape(request.POST['something_naughty'])

这是解决这个问题最简单的方法-

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

来自 这一页

尽管这是一个非常古老的问题,但这可能会奏效。

姜戈1.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" />'

Python 3.4 + :

import html


html.unescape(your_string)

通过在 Django 和 Python 中搜索这个问题的最简单的解决方案,我发现可以使用内置的函数来转义/取消转义 html 代码。

例子

我在 scraped_htmlclean_html中保存了你的 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 > = 1.0

无法逃脱

要取消转义你的 html 代码,你可以使用 Django.utils.text.unescape _ entities:

将所有命名和数字字符引用转换为相应的 unicode 字符。

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

逃跑

要转义你的 HTML 代码,你可以使用 Django utils.html.escape:

返回包含与号、引号和尖括号编码的给定文本,以便在 HTML 中使用。

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

巨蟒

您需要 Python > = 3.4

无法逃脱

要取消转义你的 html 代码,你可以使用 无法逃脱:

将字符串 s 中的所有命名和数字字符引用(例如 &gt;&#62;&x3e;)转换为相应的 unicode 字符。

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

逃跑

要转义你的 HTML 代码,你可以使用 Html 逃跑:

将字符串 s 中的字符 &<>转换为 HTML 安全序列。

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