Decodificare entità HTML nella stringa Python?


266

Sto analizzando un po 'di HTML con Beautiful Soup 3, ma contiene entità HTML che Beautiful Soup 3 non decodifica automaticamente per me:

>>> from BeautifulSoup import BeautifulSoup

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

>>> print text
&pound;682m

Come posso decodificare le entità HTML textper ottenere "£682m"invece di "&pound;682m".


Risposte:


521

Python 3.4+

Utilizzare html.unescape():

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

Il FYI html.parser.HTMLParser.unescapeè deprecato e avrebbe dovuto essere rimosso in 3.5 , anche se è stato lasciato per errore. Presto verrà rimosso dalla lingua.


Python 2.6-3.3

È possibile utilizzare HTMLParser.unescape()dalla libreria standard:

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

Puoi anche utilizzare la sixlibreria di compatibilità per semplificare l'importazione:

>>> from six.moves.html_parser import HTMLParser
>>> h = HTMLParser()
>>> print(h.unescape('&pound;682m'))
£682m

9
questo metodo non sembra sfuggire a caratteri come "& # 8217;" sul motore di app di Google, sebbene funzioni localmente su python2.6.
Decodifica

Come si può deprecare un'API non documentata? Modificata la risposta.
Markus Unterwaditzer il

@MarkusUnterwaditzer non c'è motivo per cui un metodo non documentato non possa essere deprecato. Questo lancia avvisi di deprecazione - vedi la mia modifica alla risposta.
Mark Amery,

Sembrerebbe più logico che, piuttosto che solo il unescapemetodo, l'intero HTMLParsermodulo sia stato deprecato a favore html.parser.
Tom Russell,

Vale la pena notare per Python 2: i caratteri speciali vengono sostituiti con le loro controparti di codifica Latin-1 (ISO-8859-1). Ad esempio, potrebbe essere necessario h.unescape(s).encode("utf-8"). Documenti: "" "La definizione fornita qui contiene tutte le entità definite da XHTML 1.0 che possono essere gestite usando una semplice sostituzione testuale nel set di caratteri Latin-1 (ISO-8859-1)" ""
codardo anonimo

65

Beautiful Soup gestisce la conversione delle entità. In Beautiful Soup 3, dovrai specificare l' convertEntitiesargomento per il BeautifulSoupcostruttore (consulta la sezione "Conversione di entità" dei documenti archiviati). In Beautiful Soup 4, le entità vengono decodificate automaticamente.

Zuppa bella 3

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

Zuppa bella 4

>>> from bs4 import BeautifulSoup
>>> BeautifulSoup("<p>&pound;682m</p>")
<html><body><p682m</p></body></html>

+1. Non ho idea di come mi sia perso questo nei documenti: grazie per le informazioni. Accetterò comunque la risposta di Luc perché usa la lib standard che ho specificato nella domanda (non importante per me) e probabilmente è di uso più generale per altre persone.
jkp,

5
BeautifulSoup4utilizza HTMLParser, principalmente. Vedi la fonte
scharfmn,

4
Come possiamo ottenere la conversione in Beautiful Soup 4 senza tutto l'HTML estraneo che non faceva parte della stringa originale? (ad es. <html> e <body>)
Prassitele il

@Praxiteles: BeautifulSoup ( '& pound; 682m', "html.parser") stackoverflow.com/a/14822344/4376342
Soitje

13

È possibile utilizzare replace_entities dalla libreria w3lib.html

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

2

Beautiful Soup 4 ti consente di impostare un formattatore per il tuo output

Se passi formatter=None, Beautiful Soup non modificherà affatto le stringhe in uscita. Questa è l'opzione più veloce, ma può portare a Beautiful Soup che genera HTML / XML non validi, come in questi esempi:

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>

Questo non risponde alla domanda. (Inoltre, non ho idea di che cosa stiano dicendo i documenti non è valido sull'ultimo codice HTML qui.)
Mark Amery,

<< Sacré bleu! >> è la parte non valida, in quanto è senza caratteri di escape <e> e interromperà l'html che lo circonda. So che questo è un post in ritardo da parte mia, ma nel caso in cui qualcuno stia guardando e si chiedesse ...
GMasucci,

0

Ho avuto un problema di codifica simile. Ho usato il metodo normalize (). Stavo ottenendo un errore Unicode utilizzando il metodo panda .to_html () durante l'esportazione del mio frame di dati in un file .html in un'altra directory. Ho finito per farlo e ha funzionato ...

    import unicodedata 

L'oggetto dataframe può essere quello che ti piace, chiamiamolo tabella ...

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

codifica i dati della tabella in modo che possiamo esportarli nel nostro file .html nella cartella dei modelli (questa può essere la posizione che desideri :))

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

esporta una stringa normalizzata in un file html

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

    file.write(html_data) 

    file.close() 

Riferimento: documentazione unicodedata


-4

Questo probabilmente non è rilevante qui. Ma per eliminare questi entit HTML da un intero documento, puoi fare qualcosa del genere: (Supponi documento = pagina e per favore perdona il codice sciatto, ma se hai idee su come migliorarlo, sono tutto a posto - Sono nuovo a Questo).

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

7
No! Non è necessario abbinare te stesso le entità HTML e passarci sopra; .unescape()lo fa per te . Non capisco perché tu e Rob avete pubblicato queste soluzioni eccessivamente complicate che eseguono il matching della propria entità quando la risposta accettata mostra già chiaramente che .unescape()possono trovare entità nella stringa.
Mark Amery,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.