18

J'essaie de décoder les entrées HTML d'ici NYTimes.com et je ne peux pas comprendre ce que je fais mal.Décoder des entités HTML avec Python

Prenez par exemple:

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

J'ai essayé BeautifulSoup, decode ('iso-8859-1), et la smart_str de django.utils.encoding sans succès.

+0

Cette question semble beaucoup ne pas trouver de solution satisfaisante. Ça me donne envie d'écrire quelque chose de mon propre ... – Triptych

+0

Ha Je pense que c'est la meilleure solution que j'ai trouvé jusqu'à présent. Je pourrais essayer de le faire moi-même. Si je le fais, je posterai ma solution. – KeyboardInterrupt

+0

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

Répondre

6

Essayez ceci:

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: le codec 'charmap' ne peut pas encoder le caractère u '\ u2019' en position 12: le caractère correspond à Cela semble être l'erreur que je reçois sans me soucier de ce que j'essaie. – KeyboardInterrupt

+0

Pourriez-vous fournir plus de code, alors? Je l'ai juste essayé avec la fonction que j'ai écrite et le personnage 2019 fonctionne très bien. Il apparaît comme suit: ߣ –

+0

Quelques questions sur votre expression rationnelle: (1) Ne devrait-elle pas être au lieu de \ w? L'expression rationnelle correspondra ' ' et ' ' mais elle se bloquera dans int() (2) Permettre à la référence de caractère (ce n'est PAS une entité) de finir dans un espace au lieu de ';' semble très tolérant - ne devriez-vous pas le mentionner? (3) La dernière partie ne serait-elle pas mieux écrite sous la forme [; \ s]? –

18

Cela fonctionne:

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

Si vous voulez une chaîne au lieu d'un objet Unicode, vous aurez besoin de le décoder à un codage supports les caractères utilisés; ISO-8859-1 n'a pas:

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

Il est malheureux que vous ayez besoin d'un module externe pour quelque chose comme ceci; le décodage d'entité HTML/XML simple devrait être dans la bibliothèque standard, et ne pas exiger que j'utilise une bibliothèque avec des noms de classes insignifiants comme "BeautifulStoneSoup". (Les noms de classe et de fonction ne doivent pas être "créatifs", ils doivent être significatifs.)

+2

lxml, hélas aussi pas dans la bibliothèque standard, fournit également un analyseur Beautiful Soup (et beaucoup plus) avec des noms un peu moins "créatifs". –

+1

La prise en charge du décodage d'entités se fait dans la bibliothèque standard (module htmlentitydefs). Ce que l'OP a sont des références numériques (décimales), pas des entités. –

+0

Fonctionne aussi bien avec BeautifulSoup au lieu de BeautifulStoneSoup - un pas moins "créatif" :) –

20

En fait ce que vous avez n'est pas une entité HTML. Il y a TROIS variétés de ceux & .....; thingies - par exemple       tous signifient U + 00A0 NO-BREAK SPACE.

  (le type que vous avez) est une "référence de caractère numérique" (décimal).
  est une "référence de caractère numérique" (hexadécimal).
  est une entité.

Pour en savoir plus: http://htmlhelp.com/reference/html40/entities/

Vous trouverez ici le code pour python2.X qui fait tous les trois dans un balayage par l'entrée: http://effbot.org/zone/re-sub.htm#unescape-html

+0

+1 pour le lien effbot.org, très utile! –

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 fonction est en situation irrégulière en Python 2. It is fixed in Python 3.4+: il est exposé comme html.unescape() there.

+4

Pour les futurs utilisateurs, cette réponse semble avoir si peu de upvotes simplement parce qu'elle est venue 4 ans plus tard que les réponses existantes. Cela semble être au moins une bonne réponse. Cette réponse a l'avantage qu'elle est simple (contrairement à l'écriture de votre propre fonction pour interpréter les standards HTML en utilisant une regex) et utilise une bibliothèque standard (contrairement à BeautifulSoup). Il a l'inconvénient d'utiliser une fonction non documentée. –

+0

Upvote ce peuple! – Private

Questions connexes