使用csv.reader的制表符分隔文件未按预期进行分隔

22
我正在尝试使用Python循环遍历选举结果的制表符分隔文件。以下代码不起作用,但是当我使用具有相同结果的本地文件(注释掉的行)时,它按预期工作。
我能想到的唯一问题是我需要传递url的某些标头或内容类型,但我无法弄清楚。
为什么会发生这种情况?
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

结果为:

...
['', '']
['', '']
['2']
['3']
['1']
['1']
['8']
['', '']
['D']
['a']
['v']
['i']
['d']
[' ']
['F']
['r']
['a']
['z']
['i']
['e']
['', '']
...
4个回答

43

那么发生了什么,好的,调用help可能会有所启示。

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

看起来csv.reader期望一个迭代器返回一行数据,但是我们传递的是一个基于字符迭代的字符串,这就是为什么它会逐个字符解析。解决这个问题的一种方法是生成临时文件,但我们不需要这样做,只需要传递任何可迭代对象即可。

请注意以下内容,它只是将字符串拆分为行列表,然后再提供给reader。

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

这似乎是有效的。

我还建议使用csv.DictReader,它非常有用。

>>> 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'}

基本上,它为每一行返回一个字典,使用标题作为键,这样我们就不需要跟踪顺序,而只需要记住名称,这使得代码更易读,例如row['Votes']row[4]更容易理解...


8

这个完美地工作:

import csv

reader = csv.reader(open('./MediaResults.txt'),
                    delimiter='\t')
for row in reader:
    print row
csv.reader的第一个参数应该是:

支持迭代协议并每次调用其next()方法时返回一个字符串的任何对象

根据文档,您传递的是一个字符串而不是文件对象。字符串表现为单个字符列表,因此您观察到的行为。

6

简单问题:csv.reader没有预期输入为字符串。

简单解决方案:将输入更改为:data.splitlines()

csv读取器希望迭代一次返回一行的可迭代对象。不幸的是,字符串会逐个字符迭代。为了解决这个问题,使用splitlines()将字符串转换为行列表:

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

1

也许您想通过CSV API来嗅探方言:

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

这将产生正确的输出。
另请参阅。

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


原始代码实际上是直接将数据传递给reader()构造函数,而不是文件句柄。 - user2665694

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接