353 votes

Décoder les entités HTML en chaîne Python ?

J'analyse un fichier HTML avec Beautiful Soup 3, mais il contient des entités HTML que Beautiful Soup 3 ne décode pas automatiquement pour moi :

>>> from BeautifulSoup import BeautifulSoup

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

>>> print text
&pound;682m

Comment puis-je décoder les entités HTML dans text pour obtenir "£682m" au lieu de "&pound;682m" .

3 votes

684voto

luc Points 13564

Python 3.4 et plus

Utilice html.unescape() :

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

FYI html.parser.HTMLParser.unescape est déprécié, et était censé être supprimé en 3.5 bien qu'il ait été laissé là par erreur. Il sera bientôt supprimé de la langue.


Python 2.6-3.3

Vous pouvez utiliser HTMLParser.unescape() de la bibliothèque standard :

  • Pour Python 2.6-2.7, il se trouve dans HTMLParser
  • Pour Python 3, il se trouve dans html.parser

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

Vous pouvez également utiliser le six pour simplifier l'importation :

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

9 votes

Cette méthode ne semble pas échapper aux caractères comme "'" sur le moteur d'application google, bien qu'elle fonctionne localement sur python2.6. Elle décode tout de même les entités (comme ") au moins.

0 votes

Comment une API non documentée peut-elle être dépréciée ? Réponse éditée.

0 votes

MarkusUnterwaditzer : il n'y a aucune raison pour qu'une méthode non documentée ne soit pas dépréciée. Celle-ci génère des avertissements de dépréciation - voir ma modification de la réponse.

71voto

Ben James Points 41165

Beautiful Soup s'occupe de la conversion des entités. Dans Beautiful Soup 3, vous devrez spécifier l'option de conversion des entités. convertEntities à l'argument BeautifulSoup (voir le Conversion des entités des documents archivés). Dans Beautiful Soup 4, les entités sont décodées automatiquement.

Magnifique soupe 3

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

Magnifique soupe 4

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

0 votes

+1. Je ne sais pas comment j'ai pu manquer ça dans la documentation : merci pour l'info. Je vais accepter la réponse de Luc car il utilise la librairie standard que j'ai spécifiée dans la question (ce qui n'est pas important pour moi) et elle est probablement d'un usage plus général pour d'autres personnes.

7 votes

BeautifulSoup4 utilise HTMLParser surtout. Voir le source

4 votes

Comment obtenir la conversion dans Beautiful Soup 4 sans tout le HTML étranger qui ne faisait pas partie de la chaîne originale ? (c'est-à-dire <html> et <body>)

7voto

Loïc Points 86

Beautiful Soup 4 vous permet de définir un formateur pour votre sortie

Si vous passez dans formatter=None , Beautiful Soup ne modifiera pas les chaînes de caractères à la sortie. C'est l'option la plus rapide, mais elle peut conduire à ce que Beautiful Soup génère du HTML/XML invalide, comme dans ces exemples :

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>

0 votes

Cela ne répond pas à la question. (De plus, je n'ai aucune idée de ce que les docs disent être invalide à propos de la dernière partie du HTML ici).

0 votes

<<Sacré bleu!>> est la partie invalide, car elle comporte des < et > non encodés et brisera le html qui l'entoure. Je sais que c'est un message tardif de ma part, mais au cas où quelqu'un regarderait et se demanderait...

5voto

Rob Points 421

J'aurais voulu simplement ajouter un commentaire à Neil Aggarwal réponse, mais n'avait pas la réputation nécessaire.

Sur la base de sa réponse informative, mais dans l'espoir de réduire le nombre de copies de chaînes de caractères potentiellement volumineuses dans la boucle for, j'ai trouvé l'alternative suivante. Elle fonctionne environ 40 fois plus vite sur ma plateforme :

import re
import HTMLParser

# 1500000 character long string
long_test_string = "abcdefg &pound;" * 10**5
parser = HTMLParser.HTMLParser()
# supply a lambda function to re.sub() to handle unescaping
# of any matched string segments
re.sub("(&.+?;)", lambda m: parser.unescape(m.group()), long_test_string)

-7voto

Neil Aggarwal Points 125

Ce n'est probablement pas pertinent ici. Mais pour éliminer ces entités html d'un document entier, vous pouvez faire quelque chose comme ceci : (Supposons que document = page et s'il vous plaît pardonnez le code bâclé, mais si vous avez des idées sur la façon de l'améliorer, je suis tout ouïe - Je suis nouveau dans ce domaine).

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

9 votes

Non ! Vous n'avez pas besoin de faire correspondre les entités HTML vous-même et de les passer en boucle ; .unescape() fait cela pour vous . Je ne comprends pas pourquoi vous et Rob avez posté ces solutions surcompliquées qui font correspondre leur propre entité alors que la réponse acceptée montre déjà clairement que .unescape() peut trouver des entités dans la chaîne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X