Program Tip

XML / HTML 엔터티를 Python에서 유니 코드 문자열로 변환

programtip 2020. 11. 3. 18:52
반응형

XML / HTML 엔터티를 Python에서 유니 코드 문자열로 변환


이 질문에 이미 답변이 있습니다.

일부 웹 스크래핑을 수행하고 있으며 사이트는 비 ASCII 문자를 나타내는 데 HTML 엔티티를 자주 사용합니다. Python에 HTML 엔티티가있는 문자열을 가져와 유니 코드 유형을 반환하는 유틸리티가 있습니까?

예를 들면 :

난 돌아가 겠어:

ǎ

톤 마크가있는 "ǎ"를 나타냅니다. 바이너리에서는 16 비트 01ce로 표시됩니다. html 엔티티를 값으로 변환하고 싶습니다.u'\u01ce'


표준 lib의 HTMLParser에는 문서화되지 않은 함수 unescape ()가 있습니다.

import HTMLParser
h = HTMLParser.HTMLParser()
h.unescape('© 2010') # u'\xa9 2010'
h.unescape('© 2010') # u'\xa9 2010'

Python에는 htmlentitydefs 모듈이 있지만 여기에는 HTML 엔티티를 이스케이프 해제하는 기능이 포함되어 있지 않습니다.

Python 개발자 Fredrik Lundh (특히 elementtree의 저자)는 그의 웹 사이트 에서 십진수, 16 진수 및 명명 된 엔티티와 함께 ​​작동하는 다음과 같은 기능 가지고 있습니다 .

import re, htmlentitydefs

##
# Removes HTML or XML character references and entities from a text string.
#
# @param text The HTML (or XML) source text.
# @return The plain text, as a Unicode string, if necessary.

def unescape(text):
    def fixup(m):
        text = m.group(0)
        if text[:2] == "&#":
            # character reference
            try:
                if text[:3] == "&#x":
                    return unichr(int(text[3:-1], 16))
                else:
                    return unichr(int(text[2:-1]))
            except ValueError:
                pass
        else:
            # named entity
            try:
                text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
            except KeyError:
                pass
        return text # leave as is
    return re.sub("&#?\w+;", fixup, text)

내장 사용-BeautifulSoup unichr은 필요하지 않습니다.

>>> entity = '&#x01ce'
>>> unichr(int(entity[3:],16))
u'\u01ce'

lxml이있는 경우 대안 :

>>> import lxml.html
>>> lxml.html.fromstring('&#x01ce').text
u'\u01ce'

Python 3.4 이상을 사용하는 경우 간단히 다음을 사용할 수 있습니다 html.unescape.

import html

s = html.unescape(s)

여기에서 답을 찾을 수 있습니다. 웹 페이지에서 국제 문자를 얻습니까?

편집 : BeautifulSoup16 진수 형식으로 작성된 엔티티를 변환하지 않는 것 같습니다 . 다음과 같이 수정할 수 있습니다.

import copy, re
from BeautifulSoup import BeautifulSoup

hexentityMassage = copy.copy(BeautifulSoup.MARKUP_MASSAGE)
# replace hexadecimal character reference by decimal one
hexentityMassage += [(re.compile('&#x([^;]+);'), 
                     lambda m: '&#%d;' % int(m.group(1), 16))]

def convert(html):
    return BeautifulSoup(html,
        convertEntities=BeautifulSoup.HTML_ENTITIES,
        markupMassage=hexentityMassage).contents[0].string

html = '<html>&#x01ce;&#462;</html>'
print repr(convert(html))
# u'\u01ce\u01ce'

편집 :

unescape()표준 모듈 을 사용 하는 @dF에서 언급 한 함수 이며이 경우 더 적합 할 수 있습니다.htmlentitydefsunichr()


이것은 당신이 그것을 올바르게하고 엔티티를 다시 utf-8 문자로 변환하는 데 도움이 될 함수입니다.

def unescape(text):
   """Removes HTML or XML character references 
      and entities from a text string.
   @param text The HTML (or XML) source text.
   @return The plain text, as a Unicode string, if necessary.
   from Fredrik Lundh
   2008-01-03: input only unicode characters string.
   http://effbot.org/zone/re-sub.htm#unescape-html
   """
   def fixup(m):
      text = m.group(0)
      if text[:2] == "&#":
         # character reference
         try:
            if text[:3] == "&#x":
               return unichr(int(text[3:-1], 16))
            else:
               return unichr(int(text[2:-1]))
         except ValueError:
            print "Value Error"
            pass
      else:
         # named entity
         # reescape the reserved characters.
         try:
            if text[1:-1] == "amp":
               text = "&amp;amp;"
            elif text[1:-1] == "gt":
               text = "&amp;gt;"
            elif text[1:-1] == "lt":
               text = "&amp;lt;"
            else:
               print text[1:-1]
               text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
         except KeyError:
            print "keyerror"
            pass
      return text # leave as is
   return re.sub("&#?\w+;", fixup, text)

Stack Overflow 스레드에 ';'가 포함되지 않은 이유를 잘 모르겠습니다. 검색 / 바꾸기에서 (예 : lambda m : '& # % d * ; *') 그렇지 않은 경우 인접한 문자가 HTML 코드의 일부로 해석 될 수 있기 때문에 BeautifulSoup이 barf 할 수 있습니다 (예 : & #의 경우 & # 39B). 39 블랙 아웃).

이것은 나를 위해 더 잘 작동했습니다.

import re
from BeautifulSoup import BeautifulSoup

html_string='<a href="/cgi-bin/article.cgi?f=/c/a/2010/12/13/BA3V1GQ1CI.DTL"title="">&#x27;Blackout in a can; on some shelves despite ban</a>'

hexentityMassage = [(re.compile('&#x([^;]+);'), 
lambda m: '&#%d;' % int(m.group(1), 16))]

soup = BeautifulSoup(html_string, 
convertEntities=BeautifulSoup.HTML_ENTITIES, 
markupMassage=hexentityMassage)
  1. int (m.group (1), 16)은 숫자 (16 진수로 지정됨) 형식을 다시 정수로 변환합니다.
  2. m.group (0)은 전체 일치 항목을 반환하고 m.group (1)은 regexp 캡처 그룹을 반환합니다.
  3. 기본적으로 markupMessage를 사용하는 것은 다음과 같습니다.
    html_string = re.sub ( '& # x ([^;] +);', lambda m : '& # % d;'% int (m.group (1), 16) , html_string)

Another solution is the builtin library xml.sax.saxutils (both for html and xml). However, it will convert only &gt, &amp and &lt.

from xml.sax.saxutils import unescape

escaped_text = unescape(text_to_escape)

Here is the Python 3 version of dF's answer:

import re
import html.entities

def unescape(text):
    """
    Removes HTML or XML character references and entities from a text string.

    :param text:    The HTML (or XML) source text.
    :return:        The plain text, as a Unicode string, if necessary.
    """
    def fixup(m):
        text = m.group(0)
        if text[:2] == "&#":
            # character reference
            try:
                if text[:3] == "&#x":
                    return chr(int(text[3:-1], 16))
                else:
                    return chr(int(text[2:-1]))
            except ValueError:
                pass
        else:
            # named entity
            try:
                text = chr(html.entities.name2codepoint[text[1:-1]])
            except KeyError:
                pass
        return text # leave as is
    return re.sub("&#?\w+;", fixup, text)

The main changes concern htmlentitydefs that is now html.entities and unichr that is now chr. See this Python 3 porting guide.

참고URL : https://stackoverflow.com/questions/57708/convert-xml-html-entities-into-unicode-string-in-python

반응형