HTML-Entitäten in Python-String dekodieren?

265

Ich analysiere HTML mit Beautiful Soup 3, aber es enthält HTML-Entitäten, die Beautiful Soup 3 für mich nicht automatisch dekodiert:

>>> from BeautifulSoup import BeautifulSoup

>>> soup = BeautifulSoup("<p>&pound;682m</p>")
>>> text = soup.find("p").string

>>> print text
&pound;682m

Wie kann ich die HTML-Entitäten dekodieren text, um "£682m"statt zu erhalten "&pound;682m".

jkp
quelle

Antworten:

520

Python 3.4+

Verwendung html.unescape():

import html
print(html.unescape('&pound;682m'))

FYI html.parser.HTMLParser.unescapeist veraltet und sollte in 3.5 entfernt werden , obwohl es versehentlich belassen wurde. Es wird bald aus der Sprache entfernt.


Python 2.6-3.3

Sie können HTMLParser.unescape()aus der Standardbibliothek verwenden:

>>> try:
...     # Python 2.6-2.7 
...     from HTMLParser import HTMLParser
... except ImportError:
...     # Python 3
...     from html.parser import HTMLParser
... 
>>> h = HTMLParser()
>>> print(h.unescape('&pound;682m'))
£682m

Sie können auch die sixKompatibilitätsbibliothek verwenden, um den Import zu vereinfachen:

>>> from six.moves.html_parser import HTMLParser
>>> h = HTMLParser()
>>> print(h.unescape('&pound;682m'))
£682m
luc
quelle
9
Diese Methode scheint Zeichen wie "& # 8217;" nicht zu entgehen. auf Google App Engine, obwohl es lokal auf Python2.6 funktioniert. Es dekodiert immer noch Entitäten (wie & quot;) mindestens
gfxmonk
Wie kann eine undokumentierte API veraltet sein? Antwort bearbeitet.
Markus Unterwaditzer
@MarkusUnterwaditzer Es gibt keinen Grund, warum eine undokumentierte Methode nicht veraltet sein kann. Dieser wirft Verfallswarnungen aus - siehe meine Bearbeitung zur Antwort.
Mark Amery
Es erscheint logischer, dass nicht nur die unescapeMethode , sondern das gesamte HTMLParserModul zugunsten von abgelehnt wurde html.parser.
Tom Russell
Bemerkenswert für Python 2: Sonderzeichen werden durch ihre lateinischen (ISO-8859-1) Codierungsgegenstücke ersetzt. ZB kann es notwendig sein h.unescape(s).encode("utf-8"). Die Dokumente: "" Die hier bereitgestellte Definition enthält alle durch XHTML 1.0 definierten Entitäten, die durch einfache Textsubstitution im Latin-1-Zeichensatz (ISO-8859-1) ""
anonymer Feigling
65

Beautiful Soup kümmert sich um die Konvertierung von Entitäten. In Beautiful Soup 3 müssen Sie das convertEntitiesArgument für den BeautifulSoupKonstruktor angeben (siehe Abschnitt 'Entity Conversion' der archivierten Dokumente). In Beautiful Soup 4 werden Entitäten automatisch dekodiert.

Schöne Suppe 3

>>> from BeautifulSoup import BeautifulSoup
>>> BeautifulSoup("<p>&pound;682m</p>", 
...               convertEntities=BeautifulSoup.HTML_ENTITIES)
<p682m</p>

Schöne Suppe 4

>>> from bs4 import BeautifulSoup
>>> BeautifulSoup("<p>&pound;682m</p>")
<html><body><p682m</p></body></html>
Ben James
quelle
+1. Keine Ahnung, wie ich das in den Dokumenten verpasst habe: Danke für die Info. Ich werde lucs Antwort akzeptieren, weil er die Standardbibliothek verwendet, die ich in der Frage angegeben habe (für mich nicht wichtig) und die für andere wahrscheinlich allgemeiner ist.
JKP
5
BeautifulSoup4verwendet HTMLParser, meistens. Siehe die Quelle
scharfmn
4
Wie erhalten wir die Konvertierung in Beautiful Soup 4 ohne all das überflüssige HTML, das nicht Teil der ursprünglichen Zeichenfolge war? (dh <html> und <body>)
Praxiteles
@Praxiteles: BeautifulSoup ('& Pfund; 682m', "html.parser") stackoverflow.com/a/14822344/4376342
Soitje
13

Sie können replace_entities aus der Bibliothek w3lib.html verwenden

In [202]: from w3lib.html import replace_entities

In [203]: replace_entities("&pound;682m")
Out[203]: u'\xa3682m'

In [204]: print replace_entities("&pound;682m")
£682m
Corvax
quelle
2

Mit Beautiful Soup 4 können Sie einen Formatierer für Ihre Ausgabe festlegen

Wenn Sie übergeben formatter=None, ändert Beautiful Soup die Zeichenfolgen bei der Ausgabe überhaupt nicht. Dies ist die schnellste Option, kann jedoch dazu führen, dass Beautiful Soup ungültiges HTML / XML generiert, wie in den folgenden Beispielen:

print(soup.prettify(formatter=None))
# <html>
#  <body>
#   <p>
#    Il a dit <<Sacré bleu!>>
#   </p>
#  </body>
# </html>

link_soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>')
print(link_soup.a.encode(formatter=None))
# <a href="http://example.com/?foo=val1&bar=val2">A link</a>
LoicUV
quelle
Dies beantwortet die Frage nicht. (Außerdem habe ich keine Ahnung, was die Dokumente über das letzte Stück HTML hier für ungültig erklären.)
Mark Amery
<< Sacré bleu! >> ist der ungültige Teil, da er <und> nicht entkommen ist und das HTML um ihn herum zerstört. Ich weiß, dass dies ein später Beitrag von mir ist, aber für den Fall, dass jemand
hinschaut
0

Ich hatte ein ähnliches Codierungsproblem. Ich habe die normalize () Methode verwendet. Beim Exportieren meines Datenrahmens in eine HTML-Datei in einem anderen Verzeichnis wurde ein Unicode-Fehler mit der Methode pandas .to_html () angezeigt. Am Ende habe ich das gemacht und es hat funktioniert ...

    import unicodedata 

Das Datenrahmenobjekt kann beliebig sein, nennen wir es Tabelle ...

    table = pd.DataFrame(data,columns=['Name','Team','OVR / POT'])
    table.index+= 1

Codieren Sie Tabellendaten, damit wir sie in unsere HTML-Datei im Vorlagenordner exportieren können (dies kann ein beliebiger Speicherort sein :))

     #this is where the magic happens
     html_data=unicodedata.normalize('NFKD',table.to_html()).encode('ascii','ignore')

Exportieren Sie eine normalisierte Zeichenfolge in eine HTML-Datei

    file = open("templates/home.html","w") 

    file.write(html_data) 

    file.close() 

Referenz: Unicodedata-Dokumentation

Alex
quelle
-4

Dies ist hier wahrscheinlich nicht relevant. Aber um diese HTML-Entites aus einem ganzen Dokument zu entfernen, können Sie Folgendes tun: (Nehmen Sie document = page an und verzeihen Sie bitte den schlampigen Code, aber wenn Sie Ideen haben, wie Sie ihn verbessern können, bin ich ganz Ohr - ich bin neu in Dies).

import re
import HTMLParser

regexp = "&.+?;" 
list_of_html = re.findall(regexp, page) #finds all html entites in page
for e in list_of_html:
    h = HTMLParser.HTMLParser()
    unescaped = h.unescape(e) #finds the unescaped value of the html entity
    page = page.replace(e, unescaped) #replaces html entity with unescaped value
Neil Aggarwal
quelle
7
Nein! Sie müssen HTML-Entitäten nicht selbst abgleichen und sie durchlaufen. .unescape()tut das für Sie . Ich verstehe nicht, warum Sie und Rob diese überkomplizierten Lösungen veröffentlicht haben, die ihre eigene Entitätsübereinstimmung rollen, wenn die akzeptierte Antwort bereits deutlich zeigt, dass .unescape()Entitäten in der Zeichenfolge gefunden werden können.
Mark Amery