从URL读取.csv文件到Python 3.x - _csv.Error:迭代器应该返回字符串,而不是字节(你是否在文本模式下打开文件?)

Chr*_*ris 30 python csv url python-3.x

我一直在努力解决这个简单的问题,所以我想我会寻求帮助.我正在尝试将国家医学图书馆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]
Run Code Online (Sandbox Code Playgroud)

它会导致以下错误:

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?)
Run Code Online (Sandbox Code Playgroud)

我认为我应该使用字符串而不是字节?任何有关简单问题的帮助,以及对出现问题的解释都将非常感激.

Die*_*anz 44

问题依赖于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]
Run Code Online (Sandbox Code Playgroud)

最后一行也可以是: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
Run Code Online (Sandbox Code Playgroud)

请注意,出于同样的原因,不会创建列表.

  • 弄清楚了.Python 3的流式传输方式是使用`codecs.iterdecode`. (4认同)

Irv*_* H. 9

即使已经有一个已经接受的答案,我还是想通过展示我是如何使用requests包来实现类似的东西(有时被视为替代方法urlib.request)来增加知识体系.

codecs.itercode()用于解决原始问题的基础仍然与接受的答案相同.

import codecs
from contextlib import closing
import csv
import requests

url = "ftp://ftp.ncbi.nlm.nih.gov/pub/pmc/file_list.csv"

with closing(requests.get(url, stream=True)) as r:
    reader = csv.reader(codecs.iterdecode(r.iter_lines(), 'utf-8'))
    for row in reader:
        print row   
Run Code Online (Sandbox Code Playgroud)

在这里,我们还看到通过包提供的的使用,requests以避免必须首先通过网络将整个文件加载到内存中(如果文件很大,可能需要很长时间).

我认为它可能有用,因为它帮助了我,因为我使用的requests而不是urllib.requestPython 3.6.

一些想法(例如使用closing())是从这个类似的帖子中挑选出来