Un de ces jours, il faudra qu’on fasse un petit post sur la gestion de l’encoding en Python. En attendant, voici une astuce pour éviter une des erreurs les plus énervantes pour un débutant :
UnicodeDecodeError: 'utf8' codec can't decode byte machin in position truc |
De quoi choper un SMIC d’amende pour infraction au code de moralité du langage.
Contrairement à BeautifulSoup, Mechanize n’essaie pas de détecter l’encoding de la page, et vous retourne directement la soupe de bytes qu’il reçoit en réponse. Ça marche, jusqu’à ce que vous tombiez sur un site avec un encodage différent de celui de votre système.
Heureusement, maintenant, la plupart des sites ont la politesse de déclarer leur encoding dans une balise meta, que l’on peut récupérer dans les headers. Du coup, on peut convertir facilement le HTML de la page en unicode :
import re import mechanize response = mechanize.Browser().open('http://google.com') # on chope l'encoding dans les headers # si ça marche pas on beugle une exception content_type = response.info().getheader('content-type') try: encoding = re.search(r'charset=([^\s]+)', content_type).groups()[0] except AttributeError, IndexError: raise ValueError('Unable to guess the page encoding') # et on decode tout ça return response.read().decode(encoding) |
Par facilité, nous on utilise carrément une sous-classe, vu que 99% du temps on a besoin que du HTML, et qu’on se sert essentiellement de Mechanize comme un gros urllib2 avec plein de paramètres :
import re import mechanize class Browser(mechanize.Browser): def get_content_as_unicode(self, url): response = self.open(url) content_type = response.info().getheader('content-type') try: encoding = re.search(r'charset=([^\s]+)', content_type).groups()[0] except AttributeError, IndexError: raise ValueError('Unable to guess the page encoding') return response.read().decode(encoding) |
Hop :
>>> type(Browser().get_content_as_unicode('http://google.com')) <type 'unicode'> |
Plus besoin de coquillages maintenant !
fallait le savoir !
merci !