【问题标题】:Write to StringIO object using Pandas Excelwriter?使用 Pandas Excelwriter 写入 StringIO 对象?
【发布时间】: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)字符串。

标签: python excel pandas stringio xlsxwriter


【解决方案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

      【讨论】:

        猜你喜欢
        • 2021-06-06
        • 1970-01-01
        • 1970-01-01
        • 2013-08-15
        • 2018-11-30
        • 2021-07-26
        • 2016-04-17
        • 2019-05-21
        • 2019-07-21
        相关资源
        最近更新 更多