Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 0: unexpected end of data

+1 vote

Avec Trigger-Happy, je recupere des flux RSS et le seul qui me pose les problemes ci-dessous, proviennent de linuxfr.org (http://linuxfr.org/news.atom)

la trace :

Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 277, in 'calling callback function'
  File "[...]/lib/python3.4/site-packages/tidylib/sink.py", line 79, in put_byte
    write_func(byte.decode('utf-8'))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 0: unexpected end of data
Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 277, in 'calling callback function'
  File "[...]/lib/python3.4/site-packages/tidylib/sink.py", line 79, in put_byte
    write_func(byte.decode('utf-8'))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xaa in position 0: invalid start byte
INFO foxmask - ServiceRss - ServiceEvernote - LinuxFr - 1 new data

version de la tidylib python installée

(trigger-happy) foxmask@foxmask:trigger-happy $ pip freeze --local |grep tidy
pytidylib==0.2.4

Python 3.4 installée

version de la lib tidy sur le systeme :

(trigger-happy) foxmask@foxmask:trigger-happy $ dpkg -S tidy
libtidy-0.99-0: /usr/share/doc/libtidy-0.99-0/copyright
libtidy-0.99-0: /usr/lib/libtidy-0.99.so.0.0.0
libtidy-0.99-0: /usr/lib/libtidy.so
vim-runtime: /usr/share/vim/vim74/syntax/tidy.vim
libtidy-0.99-0: /usr/lib/libtidy-0.99.so.0
vim-runtime: /usr/share/vim/vim74/compiler/tidy.vim
libtidy-0.99-0: /usr/share/doc/libtidy-0.99-0

le bout de code qui utilise tidylib :

# coding: utf-8
import re
from tidylib import tidy_document
from xml.dom.minidom import parseString

def sanitize(html):
    document, errors = tidy_document(
        html, options={"output-xhtml": 1, "force-output": 1})

Qu'est ce que ca vous inspire ?

demandé 29-Sep-2016 par foxmask (2,652 points)

ça ressemble à un unicode hell à la sauce python 2.7...

Tu as 2 possibilités :
* Utiliser unidecode pour tout décoder vers du str, avec remplacement des accents /cédilles... (pas propre, mais ça rend service)
* T'assurer que toute la chaine supporte l'unicode, à base codecs.open pour les flux sous forme de fichier unicode aware...

Bon courage !

Qu'appelles tu fichier unicode aware ?

utiliser la fonction codecs.open(f, "rB", 'utf-8)' pour ouvrir le fichier, ce qui transforme le contenu du fichier "bytes" en chaine unicode

J'ouvre aucun fichier.
Le parm html que je passe à sanitize est le contenu d'un article
Je verrai si codecs.lookup ferait l'affaire pour encoder/décoder en utf8

1 Réponse

0 votes

Le problème vient du fait que byte contient du texte qui n'est pas encodé en UTF8, tandis que la lib essaye de le decoder en UTF8. Ce n'est pas un "unicode hell", c'est juste ce qui est supposé arriver dans n'importe quel langage.

Ce qui est difficile à savoir, c'est la raison pour laquelle byte ne contient pas de l'utf8. Il faut donc que tu mettes un ipdb à ce niveau, vérifie le contenu de la variable et vérifie si ça vient de la lib ou du site. Utilise aussi chardet pour detecter le vrai encoding utilisé. Attention, peut être qu'il n'y a qu'un bout de texte dans le mauvais encoding et que c'est le flux atom qui est corrompu car leur site fait de la merde.

Après, la solution c'est de proposer un patch à la lib pour detecter le bon encoding (avec utilisation de l'en-tête xml puis chardet en fallback), mais également pour le fallback de decoder avec errors="replace" pour permette l'affichage partiel d'un texte irrécupérable.

répondu 4-Oct-2016 par Sam (4,974 points)

pour chardet aucun doute possible :

chardetect3 news.atom 
news.atom: utf-8 with confidence 0.99

donc ca semble pencher coté tidylib ... donc pour tester j'ai fait ca

import feedparser
d = feedparser.parse('news.atom')
contenu = d.entries[0].content[0].value
print(contenu)

j'ai redirigé ca dans un toto.html puis quand je tente tidy -ashtml -i toto.html

ca me sort une bonne paire de warning m'indiquant remplacer les car accentuées par leur équivalent 'html' mais pas que voyez :

tidy -utf8 -i -ashtml toto.html 
line 1 column 1 - Warning: missing <!DOCTYPE> declaration
line 1 column 1 - Warning: inserting implicit <body>
line 1 column 1 - Warning: inserting missing 'title' element
line 39 column 1 - Warning: <h3> attribute "id" has invalid value "Évolutions"
line 71 column 1 - Warning: <h3> attribute "id" has invalid value "détails-techniques-de-la-migration"
line 82 column 1 - Warning: <h3> attribute "id" has invalid value "hébergement"
line 85 column 1 - Warning: <h2> attribute "id" has invalid value "rétrospective-sur-lannée-passée"
line 88 column 1 - Warning: <h2> attribute "id" has invalid value "Évolutions-à-venir"
line 89 column 1 - Warning: <h3> attribute "id" has invalid value "finalisation-de-la-réécriture-domnipresence"
line 92 column 1 - Warning: <h3> attribute "id" has invalid value "réouverture-et-nettoyage-des-domaines-personnalisés"
line 95 column 1 - Warning: <h3> attribute "id" has invalid value "réouverture-des-inscriptions-aux-services-web"
line 101 column 1 - Warning: <h3> attribute "id" has invalid value "recherche-de-volontaires-pour-la-mise-à-jour-du-wiki"
line 104 column 1 - Warning: <h3> attribute "id" has invalid value "spécifications-pour-les-clients-et-serveurs"

les 2 premiers cas c'est normal puisque c'est pas "encore" du html
par contre la suite... d'où on colle des ID avec des car accentués ?

si c'est valide, http://validator.w3.org/feed/check.cgi?url=http%3A%2F%2Flinuxfr.org%2Fnews.atom, alors la tidylib sait pas gérer :/

Post un script stand alone et une source de données fixe (pas un flux qui change tout le temps) qui démontre le problème, comme ça je peux plus facilement trouver ce qui couille car là ça m'a l'air d'être un sous ensemble de caractères qui est mal encodé.

Je regarderai pour le script, mais pour le flux, il pète tout le temps, c'est invariable quelque soit son contenu

voila le bout de code qui declenche le zinzin

import feedparser
from pprint import pprint as pp

from tidylib import tidy_document


def sanitize(html):
    document, errors = tidy_document(
        html, options={"output-xhtml": 1, "force-output": 1})
    return document

feeds = feedparser.parse('http://linuxfr.org/news.atom')

for entry in feeds.entries:
    content = entry.get('content')[0].value
    # pp(content)
    pp(sanitize(content))
...