J’ai des difficultés à traiter les caractères unicodes d’un texte extrait de différentes pages Web (sur différents sites). J'utilise BeautifulSoup.
Le problème est que l'erreur n'est pas toujours reproductible ; parfois, cela fonctionne avec certaines pages, et parfois, il y a une erreur UnicodeEncodeError
. J'ai essayé à peu près tout ce à quoi je peux penser, mais je n'ai rien trouvé qui fonctionne de manière constante sans lancer une sorte d'erreur liée à Unicode.
L'une des sections de code qui pose problème est présentée ci-dessous :
agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
Voici une trace de pile produite sur certaines chaînes de caractères lorsque le snippet ci-dessus est exécuté :
Traceback (most recent call last):
File "foobar.py", line 792, in <module>
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)
Je soupçonne que c'est parce que certaines pages (ou plus précisément, les pages de certains des sites) peuvent être encodées, tandis que d'autres peuvent être non encodées. Tous les sites sont basés au Royaume-Uni et fournissent des données destinées à la consommation britannique - il n'y a donc aucun problème d'internalisation ou de traitement de texte écrit dans une langue autre que l'anglais.
Quelqu'un a-t-il une idée de la manière de résoudre ce problème afin que je puisse le résoudre de manière CONSISTANTE ?
Vous devez lire le [HOWTO Unicode] de Python (https://docs.python.org/2.7/howto/unicode.html). Cette erreur est le [tout premier exemple] (https://docs.python.org/2.7/howto/unicode.html#the-unicode-type).
En gros, arrêtez d'utiliser str
pour convertir l'unicode en texte/octets encodés.
A la place, utilisez correctement .encode()
pour encoder la chaîne :
p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()
ou travaillez entièrement en unicode.
Il s'agit d'un problème classique de python unicode ! Considérez ce qui suit :
a = u'bats\u00E0'
print a
=> batsà
Tout va bien jusqu'à présent, mais si nous appelons str(a), voyons ce qui se passe :
str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
Oh dip, ça ne va pas faire du bien à tout le monde ! Pour corriger l'erreur, encodez les octets explicitement avec .encode et indiquez à python le codec à utiliser :
a.encode('utf-8')
=> 'bats\xc3\xa0'
print a.encode('utf-8')
=> batsà
Et voilà !
Le problème est que lorsque vous appelez str(), python utilise le codage de caractères par défaut pour essayer de coder les octets que vous lui avez donnés, qui dans votre cas sont parfois des représentations de caractères unicode. Pour résoudre ce problème, vous devez indiquer à python comment traiter la chaîne de caractères que vous lui donnez en utilisant .encode('whatever_unicode' ;). La plupart du temps, l'utilisation de utf-8 ne devrait pas poser de problème.
Pour un excellent exposé sur ce sujet, consultez la conférence de Ned Batchelder à PyCon : http://nedbatchelder.com/text/unipain.html.