41

この単純な問題に長い間悩まされてきたので、助けを求めることにしました。National Library of Medicine ftp サイトから Python 3.3.2 (Windows 7) にジャーナル記事のリストを読み込もうとしています。ジャーナル記事は .csv ファイルにあります。

次のコードを試しました:

import csv
import urllib.request

url = "ftp://ftp.ncbi.nlm.nih.gov/pub/pmc/file_list.csv"
ftpstream = urllib.request.urlopen(url)
csvfile = csv.reader(ftpstream)
data = [row for row in csvfile]

次のエラーが発生します。

Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
data = [row for row in csvfile]
File "<pyshell#4>", line 1, in <listcomp>
data = [row for row in csvfile]
_csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)

バイトではなく文字列で作業する必要があると思いますか? 単純な問題の助けと、何がうまくいかないかについての説明をいただければ幸いです。

4

4 に答える 4

57

urllib問題は、バイトを返すことに依存しています。証拠として、ブラウザーで csv ファイルをダウンロードして、通常のファイルとして開くことを試みると、問題はなくなります。

同様の問題がここで対処されました。

適切なエンコーディングを使用して、バイトを文字列にデコードすることで解決できます。例えば:

import csv
import urllib.request

url = "ftp://ftp.ncbi.nlm.nih.gov/pub/pmc/file_list.csv"
ftpstream = urllib.request.urlopen(url)
csvfile = csv.reader(ftpstream.read().decode('utf-8'))  # with the appropriate encoding 
data = [row for row in csvfile]

最後の行は次のようにすることもできます:data = list(csvfile)読みやすくなります。

ところで、csv ファイルは非常に大きいため、処理が遅くなり、メモリを消費する可能性があります。発電機を使ったほうがいいかもしれません。

編集: Steven Rumbalski によって提案されたコーデックを使用するため、ファイル全体を読み取ってデコードする必要はありません。メモリ消費が減少し、速度が向上しました。

import csv
import urllib.request
import codecs

url = "ftp://ftp.ncbi.nlm.nih.gov/pub/pmc/file_list.csv"
ftpstream = urllib.request.urlopen(url)
csvfile = csv.reader(codecs.iterdecode(ftpstream, 'utf-8'))
for line in csvfile:
    print(line)  # do something with line

同じ理由でリストも作成されないことに注意してください。

于 2013-09-19T14:26:09.740 に答える
0

requestsパッケージとを使用して同様の問題がありましたcsv。投稿リクエストからの応答は typebytesでした。ライブラリを使用するためにcsv、最初にそれらを文字列ファイルとしてメモリに保存し (私の場合はサイズが小さかった)、utf-8 をデコードしました。

import io
import csv
import requests

response = requests.post(url, data)

# response.content is something like: 
# b'"City","Awb","Total"\r\n"Bucuresti","6733338850003","32.57"\r\n'    
csv_bytes = response.content

# write in-memory string file from bytes, decoded (utf-8)
str_file = io.StringIO(csv_bytes.decode('utf-8'), newline='\n')
    
reader = csv.reader(str_file)
for row_list in reader:
    print(row_list)

# Once the file is closed,
# any operation on the file (e.g. reading or writing) will raise a ValueError
str_file.close()

次のようなものを印刷しました:

['City', 'Awb', 'Total']
['Bucuresti', '6733338850003', '32.57']
于 2020-11-17T23:53:30.357 に答える