web-dev-qa-db-ja.com

csv.readerを使用したタブ区切りファイルで、期待する場所が区切られていない

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']
['', '']
...
19
foxyNinja7

何が起こっているのか、まあ、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は、行を返すある種のイテレータを期待しているようですが、文字ベースで反復する文字列を渡しています。これが、文字ごとに解析する理由です。これを修正する1つの方法は、一時ファイルを生成しますが、必要はありません。 どれか 反復可能なオブジェクト。

次の点に注意してください。これは、文字列を行のリストに分割し、それをリーダーに渡す前に行います。

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

37
Samy Vilar

簡単な問題:csv.readerは、入力に文字列を予期していませんでした。

シンプルなソリューション:入力をdata.splitlines()に変更します。

Csvリーダーは、一度に1行ずつ返す反復可能オブジェクトを想定しています。文字列は、残念ながら一度に1文字ずつ反復します。この問題を解決するには、splitlines()を使用して文字列を行のリストに変換します。

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

これは完全に機能します:

import csv

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

csv.readerの最初のパラメーターは次のようになります。

反復子プロトコルをサポートし、そのnext()メソッドが呼び出されるたびに文字列を返すオブジェクト

the docs に従って、ファイルオブジェクトではなく文字列を渡します。文字列は単一の文字のリストとして動作するため、観察されている動作になります。

5
gauden

おそらく、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

1
Andreas Jung