18

Sto tentando di decodificare le voci HTML da qui NYTimes.com e non riesco a capire cosa sto facendo male.Decodifica di entità HTML con Python

Prendiamo ad esempio:

"U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’" 

Ho provato BeautifulSoup, decodificare ('iso-8859-1'), e smart_str di django.utils.encoding senza alcun successo.

+0

Questa domanda sembra venire molto senza una buona soluzione. Mi fa venir voglia di scrivere qualcosa di mio ... – Triptych

+0

Ha penso che sia la soluzione migliore che ho trovato finora. Potrei davvero provare a farlo da solo. Se lo faccio, pubblicherò la mia soluzione. – KeyboardInterrupt

+0

@Triptych: c'è ['unescape()'] (http://stackoverflow.com/a/20715131/4279). – jfs

risposta

6

Prova questo:

import re 

def _callback(matches): 
    id = matches.group(1) 
    try: 
     return unichr(int(id)) 
    except: 
     return id 

def decode_unicode_references(data): 
    return re.sub("&#(\d+)(;|(?=\s))", _callback, data) 

data = "U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’" 
print decode_unicode_references(data) 
+0

UnicodeEncodeError: il codec 'charmap' non può codificare il carattere u '\ u2019' in posizione 12: mappe dei caratteri su Questo sembra essere l'errore che continuo a ottenere indipendentemente da ciò che provo. – KeyboardInterrupt

+0

Potresti fornire più codice, quindi? L'ho appena provato con la funzione che ho scritto e il personaggio 2019 funziona bene. Si presenta come: 23 –

+0

Alcune domande sul tuo regexp: (1) Non dovrebbe essere \ d invece di \ w? Regexp corrisponderà a ' ' e ' ' ma poi si bloccherà in int() (2) Permettendo al riferimento di carattere (NON è un'entità) di finire in uno spazio bianco invece di ';' sembra molto tollerante - non dovresti dirlo? (3) L'ultima parte non sarebbe meglio scritta come [; \ s]? –

18

Questo funziona:

from BeautifulSoup import BeautifulStoneSoup 
s = "U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’" 
decoded = BeautifulStoneSoup(s, convertEntities=BeautifulStoneSoup.HTML_ENTITIES) 

Se si desidera una stringa invece di un oggetto Unicode, è necessario per decodificare ad una codifica che supporti i personaggi usati; ISO-8859-1 non:

result = decoded.encode("UTF-8") 

È spiacevole che sia necessario un modulo esterno per qualcosa di simile; la semplice decodifica dell'entità HTML/XML dovrebbe essere nella libreria standard e non richiedere l'utilizzo di una libreria con nomi di classe privi di significato come "BeautifulStoneSoup". (I nomi delle classi e delle funzioni non devono essere "creativi", dovrebbero essere significativi.)

+2

lxml, ahimè anche non nella libreria standard, fornisce anche un parser Beautiful Soup (e molto altro) con nomi un po 'meno "creativi". –

+1

Il supporto per la decodifica delle entità si trova nella libreria standard (module htmlentitydefs). Ciò che l'OP ha sono riferimenti numerici (decimali) ai caratteri, non entità. –

+0

Funziona anche con BeautifulSoup anziché BeautifulStoneSoup - one step less "creative" :) –

20

In realtà ciò che hai non sono entità HTML. Ci sono TRE varietà di quelle & .....; thingies - per esempio       significa U + 00A0 NO-BREAK SPACE.

  (il tipo che hai) è un "riferimento di carattere numerico" (decimale).
  è un "riferimento di carattere numerico" (esadecimale).
  è un'entità.

Ulteriori approfondimenti: http://htmlhelp.com/reference/html40/entities/

Qui troverete il codice per python2.X fa tutti e tre in una sola scansione attraverso l'ingresso: http://effbot.org/zone/re-sub.htm#unescape-html

+0

+1 per il collegamento effbot.org, molto prezioso! –

16
>>> from HTMLParser import HTMLParser 
>>> print HTMLParser().unescape('U.S. Adviser’s Blunt Memo on Iraq: ' 
...        'Time ‘to Go Home’') 
U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’ 

La funzione è documentato in Python 2. It is fixed in Python 3.4+: è esposto come html.unescape() there.

+4

Per gli utenti futuri, questa risposta sembra avere così pochi voti semplicemente perché è arrivata 4 anni più tardi rispetto alle risposte esistenti. Sembra essere almeno una buona risposta. Questa risposta ha il vantaggio che è semplice (diversamente dalla scrittura della propria funzione per interpretare gli standard HTML usando una regex) e utilizza una libreria standard (a differenza di BeautifulSoup). Ha lo svantaggio che sta usando una funzione non documentata. –

+0

Upvote questa gente! – Private