Python / Django를 사용하여 HTML 디코딩 / 인코딩을 어떻게 수행합니까?


127

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 # 에서는 이것을 수행하는 방법을 찾았 지만 파이썬 에서는 그렇지 않습니다 . 누군가 나를 도울 수 있습니까?

관련

답변:


118

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 %}

1
장고 나 치타를 사용하지 않겠습니까?
Mat

4
django.utils.html.escape와 반대되는 것은 없습니까?
Mat

12
템플릿 렌더링 중 Django에서만 이스케이프가 발생한다고 생각합니다. 따라서 이스케이프 처리가 필요하지 않습니다. 템플릿 엔진에서 이스케이프하지 않도록 지시하면됩니다. 중 {{context_var |} 안전} 또는 {% 할인 %의 autoescape} {{context_var}} {%가 endautoescape의 %}
다니엘 NAAB

3
@Daniel : 투표를하려면 댓글로 답을 바꾸십시오! | 안전하다는 것은이 질문에 대한 답으로 내가 찾은 것입니다.
Wayne Koorts

1
html.parser.HTMLParser().unescape()3.5에서는 더 이상 사용되지 않습니다. html.unescape()대신 사용하십시오 .
pjvandehaar

114

표준 라이브러리로 :

  • HTML 탈출

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

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

12
이것이 가장 간단하고 '배터리 포함'이며 정답이라고 생각합니다. 사람들이 왜 Django / Cheetah에 투표하는지 모르겠습니다.
Daniel Baktiar

이 답변이 완전하지 않은 것 외에는 나도 그렇게 생각합니다. HTMLParser서브 클래 싱해야하고 여기에 표시된대로 개체의 모든 부분에 대해 무엇을해야하는지 알려주고 구문 분석 할 개체를 여기에 표시 합니다 . 또한 name2codepointdict 를 사용하여 각 HTML ID를 실제 문자로 변환하려고합니다.
Marconius

네가 옳아. HTMLParserHTML 엔터티를 넣으면 원하는대로 서브 클래스 가 작동하지 않았습니다. 어쩌면 숨기려면로 이름 htmlparser을 바꿔야 _htmlparser하며 unescape메서드를 도우미 함수처럼 노출 시켜야 합니다.
Jiangge Zhang

3
2015 년에 대한 참고 사항 인 HTMLParser.unescape는 py 3.4에서 더 이상 사용되지 않으며 3.5에서 제거됩니다. 사용 from html import unescape대신에
카롤 Ryselis

2
이 ( "U") 독일어 모음 변이와 같은 특수 문자를 처리하지 않습니다
576i와

80

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

인코딩 된 문자 세트가 상대적으로 제한된 경우 다니엘의 솔루션을 사용하십시오. 그렇지 않으면 수많은 HTML 구문 분석 라이브러리 중 하나를 사용하십시오.

형식이 잘못된 XML / HTML을 처리 할 수 ​​있기 때문에 BeautifulSoup을 좋아합니다.

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!'

BeautifulSoup은 16 진 엔티티 (& # x65;)를 변환하지 않습니다. stackoverflow.com/questions/57708/…
jfs

1
BeautifulSoup4의 경우, 이에 상응하는 내용은 다음과 같습니다.from bs4 import BeautifulSoup BeautifulSoup("Sacr&eacute; bl&#101;u!").contents[0]
radicand



6

답변으로 다니엘의 의견 :

"이스케이프는 템플릿 렌더링 중에 Django에서만 발생합니다. 따라서 이스케이프 처리 할 필요가 없습니다. 템플릿 엔진이 이스케이프하지 않도록 지시하면됩니다. {{context_var | safe}} 또는 {% autoescape off %} {{context_var}} { endautoescape %} "


내 장고 버전에 '안전'이 없다는 것을 제외하고는 효과가 있습니다. 대신 '탈출'을 사용합니다. 나는 그것이 같은 것이라고 가정합니다.
willem

1
@ willem : 그들은 반대입니다!
Asherah

5

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]

re를 사용하면 얻을 수있는 장점은 & # 039; & # 39; 같은 검색을 사용합니다.
Neal Stublen

이 처리하지 않습니다 &#xA0;같은 일을 디코딩해야하는 &#160;&nbsp;.
Mike Samuel

3

django 템플릿을 통해이 작업을 수행하는 간단한 방법을 찾고 있다면 언제든지 다음과 같은 필터를 사용할 수 있습니다.

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

공급 업체에서 가져온 데이터가 있었으며 게시 한 모든 내용에는 소스를보고있는 것처럼 렌더링 된 페이지에 실제로 html 태그가 작성되었습니다. 위의 코드는 크게 도움이되었습니다. 이것이 다른 사람들을 돕기를 바랍니다.

건배!!


3

이것은 정말 오래된 질문이지만 이것이 효과가있을 수 있습니다.

장고 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" />'

1
이것은 html 엔티티로 인코딩 된 대리 쌍을 디코딩 할 수있는 유일한 방법 "&#55349;&#56996;"입니다. 그런 다음 result.encode('utf-16', 'surrogatepass').decode('utf-16')나는 다시 원래를 가지고 갔다.
rescdsk

1

나는 이것을 치타 소스 코드에서 찾았습니다 ( here )

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를 목록 목록이 아닌 튜플 목록으로 변경하려고합니다 ... 이것은 내 라이브러리에서 진행됩니다 :)

제목이 인코딩을 요청한 것을 보았으므로 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

2
디코드 및 인코딩 대체는 항상 대칭으로 이루어져야하므로 목록이 반전됩니다. 반전없이 예를 들어. '& amp; lt;'변환 '& lt;'로 바꾼 다음 다음 단계에서 '<'로 잘못 변환하십시오.
bobince

1

django.utils.html.escape를 사용할 수도 있습니다.

from django.utils.html import escape

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

OP는 탈출이 아닌 탈출에 대해 물었습니다.
claymation

제목 itsellf에서 그는 인코딩을 요청했습니다. 방금 답변을 찾은 것에 감사드립니다.
Simon Steinberger

1
OP가 요청한 내용은 아니지만 이것이 유용하다는 것을 알았습니다.
rectangletangle

0

아래는 module을 사용하는 python 함수입니다 htmlentitydefs. 완벽하지 않습니다. 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;"

0

이것은이 문제에 대한 가장 쉬운 해결책입니다.

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

에서 이 페이지 .


0

Django와 Python 에서이 질문의 가장 간단한 해결책을 검색하여 내장 함수를 사용하여 HTML 코드를 이스케이프 / 이스케이프 처리 할 수 ​​있음을 발견했습니다.

나는 당신의 HTML 코드를 저장 scraped_html하고 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> = 1.0이 필요합니다

언 스케이프

긁힌 HTML 코드를 이스케이프 처리하려면 다음 과 같이 django.utils.text.unescape_entities 를 사용할 수 있습니다 .

모든 명명 된 및 숫자 참조를 해당 유니 코드 문자로 변환하십시오.

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

파이썬

파이썬이 필요합니다> = 3.4

언 스케이프

긁힌 HTML 코드를 이스케이프 해제하려면 html.unescape 를 사용 하면됩니다 .

모든 이름과 숫자 참조 (예 : 변환 &gt;, &#62;, &x3e;해당 유니 코드 문자를 문자열의 인치).

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

탈출

깨끗한 html 코드를 피하기 위해 html.escape 를 사용할 수 있습니다 .

문자 변환 &, <>HTML 안전 시퀀스에 문자열의한다.

>>> from html import escape
>>> scraped_html == escape(clean_html)
True
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.