Leer un archivo CSV UTF8 con Python

Resuelto Martin asked hace 15 años • 10 respuestas

Estoy intentando leer un archivo CSV con caracteres acentuados con Python (sólo caracteres franceses y/o españoles). Basado en la documentación de Python 2.5 para csvreader ( http://docs.python.org/library/csv.html ), se me ocurrió el siguiente código para leer el archivo CSV, ya que csvreader solo admite ASCII.

def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
    # csv.py doesn't do Unicode; encode temporarily as UTF-8:
    csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
                            dialect=dialect, **kwargs)
    for row in csv_reader:
        # decode UTF-8 back to Unicode, cell by cell:
        yield [unicode(cell, 'utf-8') for cell in row]

def utf_8_encoder(unicode_csv_data):
    for line in unicode_csv_data:
        yield line.encode('utf-8')

filename = 'output.csv'
reader = unicode_csv_reader(open(filename))
try:
    products = []
    for field1, field2, field3 in reader:
        ...

A continuación se muestra un extracto del archivo CSV que estoy intentando leer:

0665000FS10120684,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Bleu
0665000FS10120689,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Gris
0665000FS10120687,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Vert
...

Aunque intento codificar/decodificar en UTF-8, sigo recibiendo la siguiente excepción:

Traceback (most recent call last):
  File ".\Test.py", line 53, in <module>
    for field1, field2, field3 in reader:
  File ".\Test.py", line 40, in unicode_csv_reader
    for row in csv_reader:
  File ".\Test.py", line 46, in utf_8_encoder
    yield line.encode('utf-8', 'ignore')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 68: ordinal not in range(128)

¿Cómo puedo solucionar esto?

Martin avatar May 24 '09 22:05 Martin
Aceptado

El .encodemétodo se aplica a una cadena Unicode para crear una cadena de bytes; pero en su lugar lo estás llamando a una cadena de bytes... ¡al revés! Mire el codecsmódulo en la biblioteca estándar y, codecs.openen particular, encontrará mejores soluciones generales para leer archivos de texto codificados en UTF-8. Sin embargo, para el csvmódulo en particular, necesitas pasar datos utf-8, y eso es lo que ya estás obteniendo, por lo que tu código puede ser mucho más simple:

import csv

def unicode_csv_reader(utf8_data, dialect=csv.excel, **kwargs):
    csv_reader = csv.reader(utf8_data, dialect=dialect, **kwargs)
    for row in csv_reader:
        yield [unicode(cell, 'utf-8') for cell in row]

filename = 'da.csv'
reader = unicode_csv_reader(open(filename))
for field1, field2, field3 in reader:
  print field1, field2, field3 

PD: si resulta que sus datos de entrada NO están en utf-8, sino, por ejemplo, en ISO-8859-1, entonces necesita una "transcodificación" (si está interesado en usar utf-8 a csvnivel de módulo) , de la forma line.decode('whateverweirdcodec').encode('utf-8')-- pero probablemente puedas usar el nombre de tu codificación existente en la yieldlínea de mi código anterior, en lugar de 'utf-8', como csven realidad estará bien con las cadenas de bytes codificadas ISO-8859-*.

Alex Martelli avatar May 24 '2009 16:05 Alex Martelli

Pitón 2.X

Existe una biblioteca Unicode-csv que debería resolver sus problemas, con el beneficio adicional de no tener que navegar para escribir ningún código nuevo relacionado con csv.

Aquí hay un ejemplo de su archivo Léame:

>>> import unicodecsv
>>> from cStringIO import StringIO
>>> f = StringIO()
>>> w = unicodecsv.writer(f, encoding='utf-8')
>>> w.writerow((u'é', u'ñ'))
>>> f.seek(0)
>>> r = unicodecsv.reader(f, encoding='utf-8')
>>> row = r.next()
>>> print row[0], row[1]
é ñ

Pitón 3.X

En Python 3, esto es compatible desde el primer momento con el módulo integrado csv. Vea este ejemplo:

import csv
with open('some.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)
jb. avatar Feb 09 '2013 09:02 jb.