Arquivos CSV
Esta aula explora o módulo csv do Python, abordando leitura e escrita de arquivos CSV, o uso de DictReader/DictWriter para manipulação com dicionários, e cuidados importantes como encoding, delimitadores e injeção de fórmulas.
Arquivos CSV (Comma-Separated Values) são um dos formatos mais comuns para troca de dados tabulares, amplamente utilizados em planilhas, bancos de dados e sistemas legados. Nesta aula, você aprenderá a manipular esses arquivos com o módulo csv da biblioteca padrão do Python, que oferece ferramentas robustas para leitura, escrita e processamento de dados.
Dominar o módulo csv é essencial para qualquer programador Python, pois permite integrar dados externos em seus programas, automatizar tarefas de importação/exportação e lidar com variações de formato (como delimitadores diferentes e cabeçalhos). Vamos explorar desde os conceitos básicos até técnicas mais avançadas, com exemplos práticos e boas práticas.
Módulo csv
O módulo csv implementa classes e funções para ler e escrever dados no formato CSV. Ele oferece uma API que abstrai as peculiaridades do formato, como a necessidade de citar campos que contenham delimitadores, quebras de linha ou aspas. A principal vantagem é que você não precisa se preocupar com esses detalhes manualmente.
O módulo fornece dois objetos principais: reader e writer. O reader permite iterar sobre as linhas de um arquivo CSV, convertendo cada linha em uma lista de strings. O writer faz o inverso: recebe uma lista de strings e a escreve no arquivo, adicionando os delimitadores e aspas necessários. Além disso, existem as classes DictReader e DictWriter, que trabalham com dicionários, como veremos adiante.
Um exemplo simples de leitura de um arquivo CSV:
import csv
with open('dados.csv', mode='r', encoding='utf-8') as arquivo:
leitor = csv.reader(arquivo)
for linha in leitor:
print(linha)
Nesse exemplo, abrimos o arquivo dados.csv no modo leitura, criamos um objeto reader e iteramos sobre ele. Cada linha é uma lista de strings, onde cada elemento corresponde a uma coluna.
Para escrita, usamos o writer:
import csv
with open('saida.csv', mode='w', encoding='utf-8', newline='') as arquivo:
escritor = csv.writer(arquivo, delimiter=';')
escritor.writerow(['Nome', 'Idade'])
escritor.writerow(['Ana', 30])
escritor.writerow(['Bruno', 25])
Observe que passamos newline='' ao abrir o arquivo para evitar problemas com quebras de linha no Windows. O parâmetro delimiter permite escolher o separador de campos (padrão é vírgula).
Leitura e escrita
Vamos aprofundar as operações de leitura e escrita, incluindo o tratamento de cabeçalhos e a conversão de tipos. Ao ler um CSV, muitas vezes precisamos pular a primeira linha (cabeçalho) ou processar os dados como tipos específicos (inteiros, floats). O módulo csv não faz conversão automática; você deve fazer isso manualmente.
Para pular o cabeçalho, podemos usar a função next() no objeto leitor:
import csv
with open('dados.csv', 'r', encoding='utf-8') as arquivo:
leitor = csv.reader(arquivo)
cabecalho = next(leitor) # pula a primeira linha
print('Cabeçalho:', cabecalho)
for linha in leitor:
nome, idade = linha
idade = int(idade)
print(f'{nome} tem {idade} anos')
Na escrita, podemos escrever várias linhas de uma vez com writerows(). Também é possível usar o parâmetro quoting para controlar quando as aspas são adicionadas. Por exemplo, csv.QUOTE_NONNUMERIC cita apenas campos não numéricos.
import csv
dados = [
['Nome', 'Idade', 'Cidade'],
['Ana', 30, 'São Paulo'],
['Bruno', 25, 'Rio de Janeiro']
]
with open('saida.csv', 'w', encoding='utf-8', newline='') as arquivo:
escritor = csv.writer(arquivo, quoting=csv.QUOTE_MINIMAL)
escritor.writerows(dados)
Outro ponto importante é a leitura de arquivos grandes. O reader é um iterador, portanto não carrega todo o arquivo na memória de uma vez. Isso é eficiente para arquivos com milhões de linhas.
DictReader/DictWriter
As classes DictReader e DictWriter são mais convenientes quando o CSV possui cabeçalho, pois permitem acessar os campos pelo nome da coluna, em vez de índices numéricos. O DictReader usa a primeira linha como chaves dos dicionários para as linhas subsequentes.
Exemplo de leitura com DictReader:
import csv
with open('pessoas.csv', 'r', encoding='utf-8') as arquivo:
leitor = csv.DictReader(arquivo)
for linha in leitor:
print(linha['Nome'], linha['Idade'])
O DictWriter funciona de forma semelhante, mas você precisa especificar os nomes dos campos (fieldnames) que serão usados como cabeçalho e chaves dos dicionários.
import csv
campos = ['Nome', 'Idade', 'Cidade']
dados = [
{'Nome': 'Ana', 'Idade': 30, 'Cidade': 'São Paulo'},
{'Nome': 'Bruno', 'Idade': 25, 'Cidade': 'Rio de Janeiro'}
]
with open('saida.csv', 'w', encoding='utf-8', newline='') as arquivo:
escritor = csv.DictWriter(arquivo, fieldnames=campos)
escritor.writeheader() # escreve o cabeçalho
escritor.writerows(dados)
Se o dicionário tiver chaves que não estão em fieldnames, você pode usar o parâmetro extrasaction para ignorar ou gerar erro. O padrão é 'raise', mas é comum usar 'ignore'.
Outra vantagem do DictReader é que ele permite especificar um delimitador diferente, como ponto e vírgula, muito comum em países que usam vírgula como separador decimal.
import csv
with open('dados.csv', 'r', encoding='utf-8') as arquivo:
leitor = csv.DictReader(arquivo, delimiter=';')
for linha in leitor:
print(linha)
Cuidados
Ao trabalhar com arquivos CSV, alguns cuidados são essenciais para evitar erros e problemas de segurança.
- Encoding: Sempre especifique o encoding ao abrir o arquivo (ex.:
utf-8). Arquivos CSV podem vir em outros encodings, comolatin-1oucp1252. Useencoding='utf-8'para garantir compatibilidade, mas se encontrar erros de decodificação, tente outros encodings. No Windows, o padrão pode sercp1252; useencoding='utf-8-sig'para ler arquivos com BOM. - Delimitadores: O padrão é a vírgula, mas em alguns contextos (como Brasil) usa-se ponto e vírgula. Sempre verifique o formato do arquivo e ajuste o parâmetro
delimiter. - Quebras de linha: Ao escrever, use
newline=''noopen()para evitar que o Python converta quebras de linha de forma indesejada. - Injeção de fórmulas: Em planilhas como Excel, campos que começam com
=,+,-ou@podem ser interpretados como fórmulas, causando vulnerabilidades (CSV injection). Para mitigar, você pode prefixar esses campos com uma aspas simples (') ou um espaço. - Tratamento de aspas e caracteres especiais: O módulo
csvlida automaticamente com aspas, mas se você estiver gerando CSV manualmente, cuidado com caracteres como vírgulas dentro dos campos. - Linhas malformadas: Arquivos CSV podem conter linhas com número diferente de colunas. Use
csv.Errorpara tratar exceções ou valide os dados antes de processar.
Aqui está um exemplo de escrita segura contra injeção de fórmulas:
import csv
def sanitizar(valor):
if isinstance(valor, str) and valor.startswith(('=', '+', '-', '@')):
return "'" + valor
return valor
campos = ['Nome', 'Formula']
dados = [
{'Nome': 'Ana', 'Formula': '=SOMA(A1:A2)'},
{'Nome': 'Bruno', 'Formula': '2+2'}
]
with open('seguro.csv', 'w', encoding='utf-8', newline='') as arquivo:
escritor = csv.DictWriter(arquivo, fieldnames=campos)
escritor.writeheader()
for linha in dados:
linha = {k: sanitizar(v) for k, v in linha.items()}
escritor.writerow(linha)
Boas práticas
Ao trabalhar com CSV, use sempre o gerenciador de contexto with para garantir que o arquivo seja fechado corretamente. Prefira DictReader e DictWriter para legibilidade e manutenção. Se estiver lidando com arquivos muito grandes, processe linha por linha em vez de carregar tudo na memória. E lembre-se de testar com diferentes encodings e delimitadores para garantir robustez.
Referências
- Documentação oficial do módulo csv
- Python CSV: Read and Write CSV Files (Real Python)
- Python File Handling (W3Schools)
- CSV - Wikipedia (em português)
- CSV Injection (OWASP)
- Unicode HOWTO (Python)
Exercícios
Crie um script Python que leia um arquivo CSV chamado
alunos.csvcontendo as colunasnomeenota, e imprima na tela o nome de cada aluno com sua nota, formatado comoNome: ... - Nota: ....✓ Resposta:import csv with open('alunos.csv', 'r', encoding='utf-8') as arquivo: leitor = csv.reader(arquivo) next(leitor, None) # pula cabeçalho se existir for linha in leitor: nome, nota = linha print(f'Nome: {nome} - Nota: {nota}')Escreva um script que crie um arquivo CSV chamado
produtos.csvcom as colunasproduto,precoequantidade. Inclua pelo menos 3 produtos com preços decimais.✓ Resposta:import csv produtos = [ ['produto', 'preco', 'quantidade'], ['Caneta', 1.50, 100], ['Caderno', 12.90, 50], ['Lápis', 0.80, 200] ] with open('produtos.csv', 'w', encoding='utf-8', newline='') as arquivo: escritor = csv.writer(arquivo) escritor.writerows(produtos)Usando
DictReader, leia um arquivo CSV chamadovendas.csv(com colunasvendedoretotal) e calcule o total de vendas de todos os vendedores.✓ Resposta:import csv total_geral = 0 with open('vendas.csv', 'r', encoding='utf-8') as arquivo: leitor = csv.DictReader(arquivo) for linha in leitor: total_geral += float(linha['total']) print(f'Total de vendas: R$ {total_geral:.2f}')Escreva um script que use
DictWriterpara criar um arquivo CSV chamadofuncionarios.csvcom os camposnome,departamentoesalario. Os dados devem ser fornecidos como uma lista de dicionários.✓ Resposta:import csv campos = ['nome', 'departamento', 'salario'] funcionarios = [ {'nome': 'Ana', 'departamento': 'TI', 'salario': 5000}, {'nome': 'Bruno', 'departamento': 'RH', 'salario': 4000} ] with open('funcionarios.csv', 'w', encoding='utf-8', newline='') as arquivo: escritor = csv.DictWriter(arquivo, fieldnames=campos) escritor.writeheader() escritor.writerows(funcionarios)Explique como evitar o problema de injeção de fórmulas ao gerar um CSV que será aberto em Excel. Dê um exemplo de código que sanitiza os dados.
✓ Resposta: Para evitar injeção de fórmulas, devemos prefixar campos que começam com=,+,-ou@com uma aspas simples ('). Exemplo:import csv def sanitizar(valor): if isinstance(valor, str) and valor.startswith(('=', '+', '-', '@')): return "'" + valor return valor # Uso no DictWriter: # linha = {k: sanitizar(v) for k, v in linha.items()}