Comment gérer les caractères non ascii de CSV lors de l'utilisation de json.loads en Python ?
J'ai regardé quelques réponses, y compris celle-ci, mais aucune ne semble répondre à ma question.
Voici quelques exemples de lignes de CSV :
_id category
ObjectId(56266da778d34fdc048b470b) [{"group":"Home","id":"53cea0be763f4a6f4a8b459e","name":"Cleaning Services","name_singular":"Cleaning Service"}]
ObjectId(56266e0c78d34f22058b46de) [{"group":"Local","id":"5637a1b178d34f20158b464f","name":"Balloon Dí©cor","name_singular":"Balloon Dí©cor"}]
Voici mon code :
import csv
import sys
from sys import argv
import json
def ReadCSV(csvfile):
with open('newCSVFile.csv','wb') as g:
filewriter = csv.writer(g) #, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
with open(csvfile, 'rb') as f:
reader = csv.reader(f) # ceate reader object
next(reader) # skip first row
for row in reader: #go trhough all the rows
listForExport = [] #initialize list that will have two items: id and list of categories
# ID section
vendorId = str(row[0]) #pull the raw vendor id out of the first column of the csv
vendorId = vendorId[9:33] # slice to remove objectdId lable and parenthases
listForExport.append(vendorId) #add evendor ID to first item in list
# categories section
tempCatList = [] #temporarly list of categories for scond item in listForExport
#this is line 41 where the error stems
categories = json.loads(row[1]) #create's a dict with the categoreis from a given row
for names in categories: # loop through the categorie names using the key 'name'
print names['name']
Voici ce que j'obtiens :
Cleaning Services
Traceback (most recent call last):
File "csvtesting.py", line 57, in <module>
ReadCSV(csvfile)
File "csvtesting.py", line 41, in ReadCSV
categories = json.loads(row[1]) #create's a dict with the categoreis from a given row
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 338, in loads
return _default_decoder.decode(s)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 366, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 382, in raw_decode
obj, end = self.scan_once(s, idx)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 9-10: invalid continuation byte
Ainsi, le code extrait la première catégorie Cleaning Services
, mais échoue lorsque nous arrivons aux caractères non ascii.
Comment puis-je gérer cela? Je suis heureux de simplement supprimer tous les éléments non ASCII.
Lorsque vous ouvrez le fichier csv d'entrée en rb
mode, je suppose que vous utilisez une version Python2.x. La bonne nouvelle est que vous n'avez aucun problème dans la partie csv car le lecteur csv lira les octets simples sans essayer de les interpréter. Mais le json
module insistera pour décoder le texte en unicode et utilisera par défaut utf8. Comme votre fichier d'entrée n'est pas codé en utf8, il s'étouffe et génère une erreur UnicodeDecodeError.
Latin1 a une propriété intéressante : la valeur unicode de n'importe quel octet n'est que la valeur de l'octet, vous êtes donc sûr de décoder n'importe quoi - si cela a du sens, cela dépend du fait que l'encodage réel est Latin1...
Donc tu peux juste faire :
categories = json.loads(row[1], encoding="Latin1")
Alternativement, si vous souhaitez ignorer les caractères non ascii, vous pouvez d'abord convertir la chaîne d'octets en Unicode en ignorant les erreurs et ensuite seulement charger le json :
categories = json.loads(row[1].decode(errors='ignore)) # ignore all non ascii characters