web-dev-qa-db-fra.com

Fichier délimité par des tabulations utilisant csv.reader ne délimitant pas où je m'attends à ce qu'il

J'essaie de parcourir un fichier délimité par des tabulations des résultats des élections à l'aide de Python. Le code suivant ne fonctionne pas, mais lorsque j'utilise un fichier local avec les mêmes résultats (la ligne commentée), il fonctionne comme prévu.

La seule chose à laquelle je peux penser est quelques en-têtes ou type de contenu dont j'ai besoin pour passer l'URL, mais je ne peux pas le comprendre.

Pourquoi cela arrive-t-il?

import csv
import requests

r = requests.get('http://vote.wa.gov/results/current/export/MediaResults.txt') 
data = r.text
#data = open('data/MediaResults.txt', 'r')
reader = csv.reader(data, delimiter='\t')
for row in reader:
    print row

Résulte en:

...
['', '']
['', '']
['2']
['3']
['1']
['1']
['8']
['', '']
['D']
['a']
['v']
['i']
['d']
[' ']
['F']
['r']
['a']
['z']
['i']
['e']
['', '']
...
19
foxyNinja7

donc ce qui se passe, eh bien, un appel à help peut nous éclairer.

>>> help(csv.reader)
 reader(...)
    csv_reader = reader(iterable [, dialect='Excel']
                            [optional keyword args])
        for row in csv_reader:
            process(row)

    The "iterable" argument can be any object that returns a line
    of input for each iteration, such as a file object or a list.  The
    optional "dialect" parameter is discussed below.  The function
    also accepts optional keyword arguments which override settings
    provided by the dialect.

il semble donc que csv.reader attend un itérateur d'une sorte qui retournera une ligne, mais nous passons une chaîne qui itère sur une base de caractères, c'est pourquoi son analyse caractère par caractère, une façon de résoudre ce problème serait pour générer un fichier temporaire, mais nous n'en avons pas besoin, nous avons juste besoin de passer tout objet itérable.

notez ce qui suit, qui divise simplement la chaîne en une liste de lignes, avant de la transmettre au lecteur.

import csv
import requests

r = requests.get('http://vote.wa.gov/results/current/export/MediaResults.txt') 
data = r.text
reader = csv.reader(data.splitlines(), delimiter='\t')
for row in reader:
    print row

cela semble fonctionner.

Je recommande également d'utiliser csv.DictReader, C'est très utile.

>>> reader = csv.DictReader(data.splitlines(), delimiter='\t')
>>> for row in reader:
...      print row
{'Votes': '417141', 'BallotName': 'Michael Baumgartner', 'RaceID': '2', 'RaceName': 'U.S. Senator', 'PartyName': '(Prefers Republican Party)', 'TotalBallotsCastByRace': '1387059', 'RaceJurisdictionTypeName': 'Federal', 'BallotID': '23036'}
{'Votes': '15005', 'BallotName': 'Will Baker', 'RaceID': '2', 'RaceName': 'U.S. Senator', 'PartyName': '(Prefers Reform Party)', 'TotalBallotsCastByRace': '1387059', 'RaceJurisdictionTypeName': 'Federal', 'BallotID': '27435'}

fondamentalement, il renvoie un dictionnaire pour chaque ligne, en utilisant l'en-tête comme clé, de cette façon, nous n'avons pas besoin de garder une trace de la commande, mais à la place, le nom nous facilite un peu, c'est-à-dire que row['Votes'] semble plus lisible. alors row[4] ...

37
Samy Vilar

Problème simple: Le csv.reader ne s'attendait pas à une chaîne pour son entrée.

Solution simple: Modifiez l'entrée en: data.splitlines().

Le lecteur csv attend un itérable qui renvoie les lignes une à la fois. Une chaîne, malheureusement, itère un caractère à la fois. Pour résoudre le problème, utilisez splitlines () pour transformer la chaîne en une liste de lignes:

reader = csv.reader(data.splitlines(), delimiter='\t')
for row in reader:
    print row
5
Raymond Hettinger

Cela fonctionne parfaitement:

import csv

reader = csv.reader(open('./MediaResults.txt'),
                    delimiter='\t')
for row in reader:
    print row

Le premier paramètre à csv.readerdevrait être:

tout objet qui prend en charge le protocole itérateur et renvoie une chaîne chaque fois que sa méthode suivante () est appelée

selon les docs , et vous passez une chaîne, pas un objet fichier. Une chaîne se comporte comme une liste de caractères uniques, d'où le comportement que vous observez.

5
gauden

Vous souhaitez peut-être flairer le dialecte via l'API csv:

csvfile = open("example.csv", "rb")
dialect = csv.Sniffer().sniff(csvfile.read(1024))
csvfile.seek(0)
reader = csv.reader(csvfile, dialect)

Cela produira la sortie correcte.

Voir également

http://docs.python.org/library/csv.html#csv.Sniffer

1
Andreas Jung