Comment analyser correctement les chaînes codées HTML UTF-8 en Unicode avec BeautifulSoup?

j'exécute un programme Python qui récupère une page Web encodée en UTF-8, et j'extrait du texte du HTML en utilisant BeautifulSoup.

cependant, quand j'écris ce texte dans un fichier (ou l'imprime sur la console), il est écrit dans un encodage inattendu.

exemple de programme:

import urllib2
from BeautifulSoup import BeautifulSoup

# Fetch URL
url = 'http://www.voxnow.de/'
request = urllib2.Request(url)
request.add_header('Accept-Encoding', 'utf-8')

# Response has UTF-8 charset header,
# and HTML body which is UTF-8 encoded
response = urllib2.urlopen(request)

# Parse with BeautifulSoup
soup = BeautifulSoup(response)

# Print title attribute of a <div> which uses umlauts (e.g. können)
print repr(soup.find('div', id='navbutton_account')['title'])

cette exécution donne le résultat:

# u'Hier ku0102u015bnnen Sie sich kostenlos registrieren und / oder einloggen!'

mais je m'attendrais à une chaîne Unicode Python rendre ö dans le mot können comme xf6 :

# u'Hier kxf6bnnen Sie sich kostenlos registrieren und / oder einloggen!'

j'ai essayé de passer le paramètre" fromEncoding "à BeautifulSoup, et d'essayer de read() et decode() l'objet response , mais il ne fait pas de différence, ou jette une erreur.

avec la commande curl www.voxnow.de | hexdump -C , je peux voir que la page web est en effet encodé UTF-8 (i.e. il contient 0xc3 0xb6 ) pour le ö caractère:

      20 74 69 74 6c 65 3d 22  48 69 65 72 20 6b c3 b6  | title="Hier k..|
      6e 6e 65 6e 20 53 69 65  20 73 69 63 68 20 6b 6f  |nnen Sie sich ko|
      73 74 65 6e 6c 6f 73 20  72 65 67 69 73 74 72 69  |stenlos registri|

je suis au-delà des limites de mes capacités Python, donc je ne sais pas comment déboguer plus avant. Tous les conseils?

21
demandé sur Christopher Orr 2013-11-26 03:15:43

2 réponses

comme le fait remarquer justhalf ci-dessus, ma question est essentiellement une réplique de cette question .

le contenu HTML s'est présenté comme codé UTF-8 et, pour la plupart, il l'était, à l'exception d'un ou deux caractères UTF-8 invalides.

cela confond apparemment BeautifulSoup à propos de quel encodage est utilisé, et en essayant de décoder d'abord comme UTF-8 en passant le contenu à BeautifulSoup comme ce qui suit:

soup = BeautifulSoup(response.read().decode('utf-8'))

j'obtiendrais l'erreur:

UnicodeDecodeError: 'utf8' codec can't decode bytes in position 186812-186813: 
                    invalid continuation byte

en regardant de plus près la sortie, il y avait une instance du caractère Ü qui a été codée à tort comme la séquence d'octets non valide 0xe3 0x9c , plutôt que le correct 0xc3 0x9c .

comme le suggère la réponse la plus cotée sur cette question, les caractères UTF-8 invalides peuvent être supprimés pendant l'analyse, de sorte que seules les données valides sont transmises à BeautifulSoup:

soup = BeautifulSoup(response.read().decode('utf-8', 'ignore'))
21
répondu Christopher Orr 2017-05-23 10:31:15

encoder le résultat en utf-8 semble fonctionner pour moi:

print (soup.find('div', id='navbutton_account')['title']).encode('utf-8')

Il produit:

Hier können Sie sich kostenlos registrieren und / oder einloggen!
3
répondu Birei 2013-11-25 23:35:45