使用 Pandas Excelwriter 写入 StringIO 对象?
Posted
技术标签:
【中文标题】使用 Pandas Excelwriter 写入 StringIO 对象?【英文标题】:Write to StringIO object using Pandas Excelwriter? 【发布时间】:2015-03-19 11:04:39 【问题描述】:我可以将 StringIO 对象传递给 pd.to_csv() 就好了:
io = StringIO.StringIO()
pd.DataFrame().to_csv(io)
但是在使用 excel writer 时,我遇到了很多麻烦。
io = StringIO.StringIO()
writer = pd.ExcelWriter(io)
pd.DataFrame().to_excel(writer,"sheet name")
writer.save()
返回一个
AttributeError: StringIO instance has no attribute 'rfind'
我正在尝试创建一个ExcelWriter
对象而不调用pd.ExcelWriter()
,但我遇到了一些麻烦。这是我迄今为止尝试过的:
from xlsxwriter.workbook import Workbook
writer = Workbook(io)
pd.DataFrame().to_excel(writer,"sheet name")
writer.save()
但现在我收到了AttributeError: 'Workbook' object has no attribute 'write_cells'
如何将 excel 格式的 pandas 数据框保存到 StringIO
对象?
【问题讨论】:
我不确定你能做到,至少不容易。to_excel
的参数是 Excel 文件的路径,而不是实际的文件对象。为什么还要在内存中创建 Excel 文件的表示形式?
使用 Flask 制作可下载的报告。
在 Python 3 中,您应该使用 io.BytesIO
,因为写入 Excel 文件的输出是一系列字节,而不是(unicode)字符串。
【参考方案1】:
如果您不介意使用 xlwt 作为您的编写器,浏览 pandas.io.excel 源代码看起来应该不是什么大问题。其他引擎可能也不是那么困难,但 xlwt 跳出来很容易,因为它的保存方法需要一个流或文件路径。
您最初需要传入一个文件名,只是为了让 pandas 满意,因为它会根据引擎检查文件扩展名以确保它是受支持的格式。但在 xlwt 引擎的情况下,它只是将文件名填充到对象的路径属性中,然后在保存方法中使用它。如果您将路径属性更改为流,当您调用 save 方法时,它会很高兴地保存到该流。
这是一个例子:
import pandas as pd
import StringIO
import base64
df = pd.DataFrame.from_csv('http://moz.com/top500/domains/csv')
xlwt_writer = pd.io.excel.get_writer('xlwt')
my_writer = xlwt_writer('whatever.xls') #make pandas happy
xl_out = StringIO.StringIO()
my_writer.path = xl_out
df.to_excel(my_writer)
my_writer.save()
print base64.b64encode(xl_out.getvalue())
这是一种快速、简单且略显肮脏的方法。顺便说一句...一种更简洁的方法是将 ExcelWriter 子类化(或其中一个现有的子类,例如 _XlwtWriter)——但老实说,更新路径属性很少涉及,我投票向您展示简单的方法而不是去稍长的路线。
【讨论】:
【参考方案2】:Pandas 期望 ExcelWriter 构造函数的文件名路径,尽管每个编写器引擎都支持StringIO
。也许这应该作为 Pandas 中的错误/功能请求提出。
同时,这里有一个使用 Pandas xlsxwriter
引擎的解决方法示例:
import pandas as pd
import StringIO
io = StringIO.StringIO()
# Use a temp filename to keep pandas happy.
writer = pd.ExcelWriter('temp.xlsx', engine='xlsxwriter')
# Set the filename/file handle in the xlsxwriter.workbook object.
writer.book.filename = io
# Write the data frame to the StringIO object.
pd.DataFrame().to_excel(writer, sheet_name='Sheet1')
writer.save()
xlsx_data = io.getvalue()
更新:从 Pandas 0.17 开始,现在可以更直接地执行此操作:
# Note, Python 2 example. For Python 3 use: output = io.BytesIO().
output = StringIO.StringIO()
# Use the StringIO object as the filehandle.
writer = pd.ExcelWriter(output, engine='xlsxwriter')
另请参阅 XlsxWriter 文档中的 Saving the Dataframe output to a string。
【讨论】:
谢谢——单行解决方法效果很好! 这是刚刚在 pandas 中添加的,请参见此处:github.com/pydata/pandas/pull/10376。将在 0.17.0 版本中发布(可能 7 月底) 对我来说帮助很大——但在将输出提供给 Flask 时缺少一件关键的事情:output.seek(0)【参考方案3】:对于那些不使用xlsxwriter
作为engine=
的to_excel
的人,这是在内存中使用openpyxl
的解决方案:
in_memory_file = StringIO.StringIO()
xlw = pd.ExcelWriter('temp.xlsx', engine='openpyxl')
# ... do many .to_excel() thingies
xlw.book.save(in_memory_file)
# if you want to read it or stream to a client, don't forget this
in_memory_file.seek(0)
说明:ExcelWriter
包装类通过 .book
属性公开引擎的各个工作簿。对于openpyxl
,您可以照常使用Workbook.save
方法!
【讨论】:
【参考方案4】:这些都不是我的工作。我有一个观点,我想从 Django 中返回一个 excel 工作簿。我找到了我的解决方案from the pandas documentation。
import io
bio = io.BytesIO()
writer = pd.ExcelWriter(bio, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
bio.seek(0)
# BONUS CONTENT
# .. because I wanted to return from an api
response = HttpResponse(bio, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=myfile.xlsx'
return response # returned from a view here
注意,我使用该值作为内容类型,因为根据 mozzilla 文档,它是 mime 类型。来自以下链接中的“.xlsx”。根据需要更换。 https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
【讨论】:
以上是关于使用 Pandas Excelwriter 写入 StringIO 对象?的主要内容,如果未能解决你的问题,请参考以下文章
Pandas ExcelWriter .save() 出错;权限错误 [WinError 32]
Python:在多张工作表上将 Pandas DataFrame 写入 Excel 的最快方法