使用Pandas Excelwriter将数据写入StringIO对象?

23

我可以将StringIO对象传递给pd.to_csv(),一切都很好:

io = StringIO.StringIO()
pd.DataFrame().to_csv(io)

但是使用Excel写入器时,我遇到了更多的麻烦。

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'的错误。

如何将一个 Pandas 数据框以 Excel 格式保存到一个 StringIO 对象中?


1
我不确定你能否这样做,至少不是很容易。to_excel的参数是指向Excel文件的路径,而不是实际的文件对象。你为什么要创建一个Excel文件的内存表示呢? - BrenBarn
2
使用Flask制作可下载的报告。 - A User
1
在Python 3中,您应该使用io.BytesIO,因为编写Excel文件的输出是一系列字节而不是(Unicode)字符串。 - LeoRochael
4个回答

44
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')

如果你需要在Pandas之外使用输出(例如在Django或Flask中),请记得将写入器倒回到起始位置:output.seek(0)
另请参阅XlsxWriter文档中的将数据帧输出保存为字符串

谢谢 - 这个一行代码的解决方法完美地解决了问题! - A User
5
这个功能刚刚被添加到pandas中,详情请见此链接:https://github.com/pydata/pandas/pull/10376。它将会在0.17.0版本中发布(可能在七月底)。 - Jeff
2
对我来说这很有帮助——但是当将输出传递给Flask时,缺少了一个关键的东西:output.seek(0)。 - Fips

12

这些方法都对我没有用。我想在Django中返回一个Excel工作簿的视图,我在 pandas文档 中找到了解决方案。

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

注意,我使用了该值作为内容类型,因为根据Moziila文档,它是MIME类型中的一种。请查看以下链接中".xlsx"的内容。根据需要进行替换。 https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types


谢谢!这个完美地运行了。对于较新版本的模块,我必须使用writer.close()而不是writer.save() - andzep

6

快速浏览pandas.io.excel源代码,如果您不介意将xlwt作为您的写入器,那么看起来这应该不会太困难。其他引擎可能也不是很难,但是由于xlwt的保存方法接受流或文件路径,因此它变得非常容易。

您需要最初传递一个文件名,只是为了让pandas满意,因为它会检查文件名扩展名是否与引擎匹配,以确保它是一种受支持的格式。但是,在xlwt引擎的情况下,它只是将文件名塞入对象的路径属性中,然后在保存方法中使用它。如果您将路径属性更改为您的流,则在调用保存方法时,它将愉快地保存到该流中。

以下是一个示例:

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)-- 但老实说,在更新路径属性方面涉及到的内容非常少,我选择向您展示简单的方法而不是走稍微长一点的路线。


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方法!

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