it-swarm.dev

Lendo um arquivo CSV UTF8 com Python

Eu estou tentando ler um arquivo CSV com caracteres acentuados com Python (apenas caracteres franceses e/ou espanhóis). Baseado na documentação do Python 2.5 para o csvreader ( http://docs.python.org/library/csv.html ), eu criei o seguinte código para ler o Arquivo CSV, já que o csvreader suporta apenas 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:
        ...

Abaixo está um extrato do arquivo CSV que estou tentando ler:

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
...

Embora eu tente codificar/decodificar para UTF-8, ainda estou recebendo a seguinte exceção:

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)

Como faço para corrigir isso?

86
Martin

O método .encode é aplicado a uma string Unicode para criar uma string de bytes; mas você está chamando isto em uma corda de byte ao invés ... o caminho errado 'redondo! Observe o módulo codecs na biblioteca padrão e codecs.open em particular para obter melhores soluções gerais para a leitura de arquivos de texto codificados em UTF-8. No entanto, para o módulo csv em particular, você precisa passar os dados utf-8, e é isso que você já está obtendo, então seu código pode ser muito mais simples:

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 

PS: se os dados de entrada NÃO estiverem em utf-8, mas, por exemplo, em ISO-8859-1, então você precisa de uma "transcodificação" (se você estiver interessado em usar o utf-8 no nível do módulo csv), da forma line.decode('whateverweirdcodec').encode('utf-8') - mas provavelmente você pode simplesmente usar o nome do seu existente A codificação na linha yield no meu código acima, em vez de 'utf-8', como csv está realmente indo bem com ISO-8859- * bytestrings codificadas.

108
Alex Martelli

Python 2.X

Existe uma biblioteca nicode-csv que deve resolver seus problemas, com o benefício adicional de não navegar para escrever qualquer novo código relacionado ao csv.

Aqui está um exemplo do seu readme:

>>> 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]
é ñ

Python 3.X

Em python 3 isto é suportado fora da caixa pelo módulo csv do build. Veja este exemplo:

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

Confira também a resposta neste post: https://stackoverflow.com/a/9347871/1338557

Sugere o uso da biblioteca chamada ucsv.py. Substituição simples e curta para CSV escrita para resolver o problema de codificação (utf-8) para Python 2.7. Também fornece suporte para csv.DictReader

Edit : Adicionando código de exemplo que eu usei:

import ucsv as csv

#Read CSV file containing the right tags to produce
fileObj = open('awol_title_strings.csv', 'rb')
dictReader = csv.DictReader(fileObj, fieldnames = ['titles', 'tags'], delimiter = ',', quotechar = '"')
#Build a dictionary from the CSV file-> {<string>:<tags to produce>}
titleStringsDict = dict()
for row in dictReader:
    titleStringsDict.update({unicode(row['titles']):unicode(row['tags'])})
3
Atripavan

Se você quiser ler um arquivo CSV com a codificação utf-8, uma abordagem minimalista que eu recomendo é usar algo assim:

        with open(file_name, encoding="utf8") as csv_file:

Com essa afirmação, você pode usar mais tarde um leitor de CSV para trabalhar.

3
Nick Cuevas

Usando codecs.open como sugeriu Alex Martelli provou ser útil para mim.

import codecs

delimiter = ';'
reader = codecs.open("your_filename.csv", 'r', encoding='utf-8')
for line in reader:
    row = line.split(delimiter)
    # do something with your row ...
2
user1154664

O link para a página de ajuda é o mesmo para python 2.6 e, até onde eu sei, não houve alteração no módulo csv desde 2.5 (além das correções de bugs). Aqui está o código que simplesmente funciona sem nenhuma codificação/decodificação (o arquivo da.csv contém os mesmos dados que os dados da variável ). Eu suponho que seu arquivo deve ser lido corretamente sem qualquer conversão.

test.py:

## -*- coding: utf-8 -*-
#
# NOTE: this first line is important for the version b) read from a string(unicode) variable
#

import csv

data = \
"""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"""

# a) read from a file
print 'reading from a file:'
for (f1, f2, f3) in csv.reader(open('da.csv'), dialect=csv.Excel):
    print (f1, f2, f3)

# b) read from a string(unicode) variable
print 'reading from a list of strings:'
reader = csv.reader(data.split('\n'), dialect=csv.Excel)
for (f1, f2, f3) in reader:
    print (f1, f2, f3)

da.csv:

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
1
van

Tive o mesmo problema em outro servidor, mas percebi que as localidades estão confusas.

export LC_ALL="en_US.UTF-8"

resolveu o problema

0
Piotr Pęczek

Olhando para o Latin-1 unicode table , vejo o código do caractere 00E9 " LATIN PEQUENO E LETRA E COM AGUDO ". Este é o caractere acentuado em seus dados de amostra. Um teste simples em Python mostra que a codificação UTF-8 para este caractere é diferente da codificação unicode (quase UTF-16).

>>> u'\u00e9'
u'\xe9'
>>> u'\u00e9'.encode('utf-8')
'\xc3\xa9'
>>> 

Eu sugiro que você tente encode("UTF-8") os dados unicode antes de chamar o especial unicode_csv_reader(). Simplesmente ler os dados de um arquivo pode ocultar a codificação, portanto, verifique os valores reais dos caracteres.

0
gimel