直接将CSV文件下载到Python CSV解析器中

3

我正在尝试从晨星网下载CSV内容,然后解析其内容。如果我直接将HTTP内容注入到Python的CSV解析器中,结果格式不正确。但是,如果我将HTTP内容保存到文件(/tmp/tmp.csv),然后在Python的CSV解析器中导入该文件,则结果是正确的。换句话说:

def finDownload(code,report):
    h = httplib2.Http('.cache')
    url = 'http://financials.morningstar.com/ajax/ReportProcess4CSV.html?t=' + code + '&region=AUS&culture=en_us&reportType='+ report + '&period=12&dataType=A&order=asc&columnYear=5&rounding=1&view=raw&productCode=usa&denominatorView=raw&number=1'
    headers, data = h.request(url)
    return data

balancesheet = csv.reader(finDownload('FGE','is'))
for row in balancesheet:
    print row

返回:

['F']
['o']
['r']
['g']
['e']
[' ']
['G']
['r']
['o']
['u']
     (etc...)

改为:

[Forge Group Limited (FGE) Income Statement']

?

1个回答

9
这个问题的原因是文件迭代是逐行进行的,而字符串迭代是逐字符进行的。
你需要使用 StringIO/cStringIO (Python 2) 或者 io.StringIO (Python 3, 感谢 John Machin 的指点) 将字符串转换为类似文件的对象: Python 2:
mystring = 'a,"b\nb",c\n1,2,3'
import cStringIO
csvio = cStringIO.StringIO(mystring)
mycsv = csv.reader(csvio)

Python 3

mystring = 'a,"b\nb",c\n1,2,3'
import io
csvio = io.StringIO(mystring, newline="")
mycsv = csv.reader(csvio)

两种方法都可以正确地保留引号内部的换行符:

>>> for row in mycsv: print(row)
...
['a', 'b\nb', 'c']
['1', '2', '3']

1
splitlines 在 Python 3 中也消失了吗?我一直比 split('\n') 更喜欢它,因为我患有反斜杠恐惧症。 - PaulMcG
-3 csvstring是一个糟糕的列表名称。通常,CSV文件使用CR LF作为行分隔符;不要使用mystring.split('\n'),请使用 mystring.splitlines()StringIO并未“消失”,它已经搬到了io模块,并更名为 BytesIO。还有一个适用于py3kstr对象的StringIO。请参见http://docs.python.org/py3k/library/io.html#module-io - John Machin
@JohnMachin:谢谢你的评论。我已经多次重写了我的答案,所以我希望它现在能经受住仔细审查的考验 :) - Tim Pietzcker
@Tim:你已经接近成功了。使用py2,使用cStringIO.StringIO。OP的数据中既没有'也没有"。默认(几乎普遍使用的)quotechar"。由于您希望显示带引号的嵌入式LF的正确行为,因此最好放弃' quotechar。您的py3示例以str对象开始是不现实的。Python提供的urllib.request.urlopen(url).read()会生成bytes。请注意,有效负载以UTF-8“BOM”开头(当然,对于py2和py3都是如此),其余所有字节都是ASCII码。希望有所帮助 :) - John Machin

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