Convertir des entités XML / HTML en chaîne de caractères Unicode en Python [dupliquer]

cette question a déjà une réponse ici:

  • décoder les entités HTML en chaîne Python? 5 réponses

je fais du raclage web et les sites utilisent fréquemment des entités HTML pour représenter des caractères non ascii. Python a-t-il un utilitaire qui prend une chaîne de caractères avec des entités HTML? et retourne un type unicode?

par exemple:

je serai de retour:

ǎ

qui représente un "pond" avec une tonalité. En binaire, cela est représenté comme le 16 bit 01ce. Je veux convertir l'entité html en la valeur u'u01ce'

67
demandé sur Josh Lee 2008-09-12 01:28:46

10 réponses

Python a le module htmlentitydefs , mais cela ne comprend pas une fonction pour désencaper les entités HTML.

développeur Python Fredrik Lundh (auteur d'elementtree, entre autres choses) a une telle fonction sur son site web , qui fonctionne avec décimal, hexagone et entités nommées:

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)
59
répondu dF. 2015-09-01 17:12:56

l'Analyseur htmlparser de lib standard possède une fonction non documentée unescape () qui fait exactement ce que vous pensez qu'il fait:

import HTMLParser
h = HTMLParser.HTMLParser()
h.unescape('© 2010') # u'\xa9 2010'
h.unescape('© 2010') # u'\xa9 2010'
49
répondu Vladislav 2012-09-27 05:34:44

utiliser le builtin unichr -- BeautifulSoup n'est pas nécessaire:

>>> entity = '&#x01ce'
>>> unichr(int(entity[3:],16))
u'\u01ce'
18
répondu chryss 2008-09-11 23:09:08

une alternative, si vous avez lxml:

>>> import lxml.html
>>> lxml.html.fromstring('&#x01ce').text
u'\u01ce'
16
répondu pragmar 2012-02-09 19:01:45

si vous êtes sous Python 3.4 ou plus récent, vous pouvez simplement utiliser le html.unescape :

import html

s = html.unescape(s)
12
répondu Markus Amalthea Magnuson 2018-07-20 19:35:48

vous pouvez trouver une réponse ici -- obtenir des caractères internationaux à partir d'une page web?

EDIT : il semble que BeautifulSoup ne convertisse pas les entités écrites sous forme hexadécimale. Il peut être réparé:

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'

MODIFIER :

unescape() fonction mentionnée par @DF qui utilise htmlentitydefs module standard et unichr() pourraient être plus appropriés dans ce cas.

8
répondu jfs 2017-05-23 11:47:17

il s'agit d'une fonction qui devrait vous aider à le faire correctement et à convertir les entités en caractères 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)
5
répondu karlcow 2009-02-21 19:45:58

Je ne sais pas pourquoi le thread de débordement de la pile n'inclut pas le ';' dans la recherche/remplacer (i.e. lambda m: '& # % d* ; *') si vous ne le faites pas, BeautifulSoup peut barf parce que le caractère adjacent peut être interprété comme faisant partie du code HTML (i.e. 'B for 'Blackout).

cela a mieux fonctionné pour moi:

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. the int(m. group (1), 16) convertit le nombre (spécifié dans la base-16) format de retour à un entier.
  2. M. group (0) renvoie la totalité du match, M. Groupe (1) renvoie le groupe de capture regexp
  3. utiliser essentiellement markupMessage est le même que:

    html_string = re.sub ('&#x([^;]+);', lambda m: '& #%d;' % int(M. group (1), 16), html_string)
3
répondu rogerhu 2013-03-14 15:58:17

une autre solution est la bibliothèque XML intégrée.Saxo.saxutils (pour html et xml). Cependant, il ne convertira que >, & et & lt.

from xml.sax.saxutils import unescape

escaped_text = unescape(text_to_escape)
1
répondu 2015-11-02 20:41:37

Voici la version Python 3 de réponse DE dF :

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)

les principaux changements concernent htmlentitydefs qui est maintenant html.entities et unichr qui est maintenant chr . Voir ce Guide de portage Python 3 .

0
répondu Victor 2017-05-23 12:03:02