Konvertieren von XML / HTML-Entities in Unicode-String in Python [Duplikat]
Frage
Diese Frage bereits eine Antwort hier:
- Decode HTML-Entitäten in Python-String? 5 Antworten
Ich mache ein paar Screen Scraping und Websites, HTML-Entitäten häufig nicht ASCII-Zeichen darzustellen verwenden. Ist Python hat ein Dienstprogramm, das einen String mit HTML-Entitäten nimmt und gibt einen Unicode-Typen?
Zum Beispiel:
ich zurück:
ǎ
, die eine „ǎ“ mit einem Ton Zeichen darstellt. In Binär-, wird dies als der 16-Bit-01ce dargestellt. Ich möchte die HTML-Entität in den Wert u'\u01ce'
konvertieren
Lösung
Der eigene HTMLParser Standard lib hat eine nicht dokumentierte Funktion unescape (), die genau das tut, was Sie denken, es tut:
import HTMLParser
h = HTMLParser.HTMLParser()
h.unescape('© 2010') # u'\xa9 2010'
h.unescape('© 2010') # u'\xa9 2010'
Andere Tipps
Python hat den htmlentitydefs Modul, aber das doesn‘ t enthalten eine Funktion unescape HTML-Entitäten.
Python-Entwickler Fredrik Lundh (Autor von elementtree ua) hat eine solche Funktion auf seiner Website , die mit dezimal, hex und benannten Entitäten funktionieren:
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)
Mit der eingebauten unichr
- BeautifulSoup ist nicht notwendig:
>>> entity = 'ǎ'
>>> unichr(int(entity[3:],16))
u'\u01ce'
Eine Alternative, wenn Sie lxml:
>>> import lxml.html
>>> lxml.html.fromstring('ǎ').text
u'\u01ce'
Wenn Sie auf Python 3.4 oder höher sind, können Sie einfach die html.unescape
:
import html
s = html.unescape(s)
Sie können eine Antwort finden Sie hier - Erste internationale Zeichen von a Webseite?
Bearbeiten : Es scheint wie BeautifulSoup
keine Einheiten in hexadezimal geschrieben konvertieren. Es kann festgelegt werden:
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>ǎǎ</html>'
print repr(convert(html))
# u'\u01ce\u01ce'
Bearbeiten :
unescape()
Funktion von @dF die htmlentitydefs
Standardmodul verwendet und unichr()
könnte besser geeignet sein in diesem Fall.
Dies ist eine Funktion, die Sie soll helfen, es richtig zu machen und Einheiten konvertieren zurück in utf-8-Zeichen.
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;"
elif text[1:-1] == "gt":
text = "&gt;"
elif text[1:-1] == "lt":
text = "&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)
Nicht sicher, warum der Stack-Überlauf-Thread umfasst nicht die ‚;‘ im Suchen / Ersetzen (dh Lambda m: '& #% d * ; *') Wenn Sie dies nicht tun, kann BeautifulSoup kotzen, weil das benachbarte Zeichen als Teil des HTML-Codes interpretiert werden kann ( dh & # 39B für & # 39Blackout).
Das funktionierte besser für mich:
import re
from BeautifulSoup import BeautifulSoup
html_string='<a href="/cgi-bin/article.cgi?f=/c/a/2010/12/13/BA3V1GQ1CI.DTL"title="">'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)
- Die int (m.group (1), 16) wandelt die Zahl (spezifiziert in der Basis 16) Format zurück auf eine ganze Zahl.
- m.group (0) gibt das gesamte Spiel, m.group (1) gibt die regexp Erfassungsgruppe
- Im Grunde genommen mit markupMessage ist das gleiche wie:
html_string = re.sub ( '& # x ([^,] +);', lambda m: '& #% d;' % int (m.group (1), 16), html_string)
Eine andere Lösung ist die eingebaute Bibliothek xml.sax.saxutils (sowohl für HTML und XML). Allerdings wird es nur konvertieren > & amp und <.
from xml.sax.saxutils import unescape
escaped_text = unescape(text_to_escape)
Hier ist die Python 3-Version von dF Antwort :
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)
Die wichtigsten Änderungen betreffen htmlentitydefs
, die jetzt html.entities
und unichr
, die jetzt chr
ist. Sehen Sie diese Python 3 Portierungs Führung .