web-dev-qa-db-fra.com

Comment analyser correctement du HTML encodé en UTF-8 en chaînes Unicode avec BeautifulSoup?

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

Cependant, lorsque 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'])

L'exécution de ceci donne le résultat:

# u'Hier k\u0102\u015bnnen Sie sich kostenlos registrieren und / oder einloggen!'

Mais je m'attendrais à ce qu'une chaîne Python Unicode rende ö Dans le mot können Sous la forme \xf6 :

# u'Hier k\xf6bnnen 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 cela ne fait aucune différence ou jette un Erreur.

Avec la commande curl www.voxnow.de | hexdump -C, Je peux voir que la page Web est en effet encodée en UTF-8 (c'est-à-dire qu'elle 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à de la limite de mes capacités Python, donc je ne sais pas comment déboguer davantage. Un conseil?

26
Christopher Orr

Comme la moitié le souligne ci-dessus, ma question ici est essentiellement un double de cette question .

Le contenu HTML s'est présenté comme codé UTF-8 et, pour la plupart, il l'a été, à l'exception d'un ou deux caractères UTF-8 non valides.

Cela confond apparemment BeautifulSoup sur le codage utilisé et lors de la première tentative de décodage en UTF-8 lors du passage du contenu à BeautifulSoup comme ceci:

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é incorrectement codé comme séquence d'octets non valide 0xe3 0x9c, plutôt que le bon 0xc3 0x9c .

Comme l'indique actuellement réponse la mieux notée sur cette question, les caractères UTF-8 non valides peuvent être supprimés lors de l'analyse, de sorte que seules les données valides sont transmises à BeautifulSoup:

soup = BeautifulSoup(response.read().decode('utf-8', 'ignore'))
28
Christopher Orr

Encodage du résultat en utf-8 semble fonctionner pour moi:

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

Il donne:

Hier können Sie sich kostenlos registrieren und / oder einloggen!
3
Birei