【问题标题】:how to output xlsx generated by Openpyxl to browser?如何将 Openpyxl 生成的 xlsx 输出到浏览器?
【发布时间】:2012-08-30 12:18:43
【问题描述】:

我现在使用 stackoverflow 有一段时间了,它经常帮助我。现在我有一个问题,我自己或通过搜索无法解决。 我正在尝试在浏览器中输出由 openpyxl 生成的 excel 文件,就像我使用 phpexcel 一样。该方法似乎是相同的,但我只得到损坏的文件。我的代码如下所示:

from openpyxl.workbook import Workbook
from openpyxl.writer.excel import ExcelWriter
from openpyxl.writer.excel import save_virtual_workbook
from openpyxl.cell import get_column_letter
from StringIO import StringIO

print 'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
print 'Content-Disposition: attachment;filename="results.xlsx"'
print 'Cache-Control: max-age=0\n'

output = StringIO()

wb = Workbook()

ws = wb.worksheets[0]

ws.cell('A1').value = 3.14

wb.save(output)
print output.getvalue()
#print save_virtual_workbook(wb)

我使用版本 1.5.8 和 python 2.7。 这些方法都不起作用。当我只是从桌面而不是浏览器使用它时,它可以完美运行。 非常感谢您的帮助。

附:请不要告诉我使用其他语言或程序会更容易。我需要用python解决这个问题。

【问题讨论】:

  • 从这个问题来看,我想你对 python 中的 web 编程没有经验。您不能将此代码放在文档根目录的 *.py 中并期望它像 *.php 一样运行。
  • 您的 Content-* 标头看起来有缺陷。他们应该使用 CR/LF 行尾。你能得到这个脚本正确提供的简单text/html 示例吗?如果不是,请先解决此问题。
  • 我有足够的经验知道从 cgi-bin 运行它。我有其他脚本正在运行。这是第一个没有输出我需要的东西。是的,干净的 text/html 可以完美地工作,至少就我测试而言。我不明白为什么我应该使用 CR/LF...
  • @tripleee 他正在设置他想要提供的文件的 MIME 类型,这是正确的,尽管在这里基本上不相关。

标签: python excel browser cgi openpyxl


【解决方案1】:

如果您想构建一个看起来像电子表格的 HTML 表格,您可能希望使用 CSV。要么这样做,而不是 Excel,要么在构建 Excel 后将其转换为 CSV。

无论如何,一旦您拥有 CSV 格式的数据,那么只需使用 python 构建 HTML 页面并循环遍历 CSV 数据,同时插入您的 <table><tr> 和 @987654323 @ 标记,视情况而定。

【讨论】:

  • 是的,我在 python 中的 web 编程方面没有太多经验。我的莫克是将一些此类应用程序从 php 转换为 python,现在我被 phppyton -> openpyxl 卡住了。我需要同样的行为。这是从另一个脚本获取数据,将其发送到该脚本,将其放入 excel 文件并作为下载输出到浏览器。可能之前没有将其保存到服务器。
  • @David 这个问题专门针对提供 Excel 文件。
【解决方案2】:

您的脚本可以按照您的期望为我工作,无需更改。

我只能假设您的 cgi 脚本设置有问题。

确保您的脚本所在的目录实际由 Web 服务器提供服务。在 apache 上,您可以通过以下方式实现:

  ScriptAlias /cgi-bin/ /home/WWW/localhost/cgi-bin/

通过设置脚本权限确保脚本是可执行的。对于不必要的命令行操作(python scriptname),对于您的网络浏览器来说就是这样。并确保网络服务器的所有者可以执行脚本,因为网络服务器可能不会像你一样运行。

【讨论】:

    【解决方案3】:

    将 xlsx 输出写入磁盘,然后通过 Apache 提供它运行良好,但直接将其输出会导致 Excel 出错和其他问题。

    我添加了几个额外的步骤并对您的代码进行了一个小改动:

    buffer=output.getvalue()
    

    在 HTTP 标头中:

    print "Content-Length: " + str(len(buffer))
    

    并使用write()而不是print()将缓冲区推入标准输出流:

    stdout.write(buffer)
    

    【讨论】:

    • +1 用于包含 Content-Length 标头。没有它,我无法让它工作。当我使用print save_virtual_workbook(wb) 时,我生成的压缩文件有两个额外的字节。如果我使用stdout.write() 它有一个额外的字节。提供Content-Length 修复它。
    【解决方案4】:

    这对我有用。我使用烧瓶中的python 2.7 和最新的openpyxlsend_file

    ... code ...
    
    import StringIO
    from openpyxl import Workbook
    wb = Workbook()
    ws = wb.active # worksheet
    ws.title = "Excel Using Openpyxl"
    c = ws.cell(row=5, column=5)
    c.value = "Hi on 5,5"
    out = StringIO.StringIO()
    wb.save(out)
    out.seek(0)
    
    return send_file(out, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                attachment_filename='xxl.xlsx', as_attachment=True)
    

    【讨论】:

    • 那是可怕的混叠! from io import BytesIO 是这样做的方法。
    【解决方案5】:

    因为 Excel 使用二进制格式,所以应该使用 BytesIO 来缓冲。

    from io import BytesIO

    但是,如果您使用 save_virtual_workbook() 为您执行此操作,您会遇到什么错误?

    【讨论】:

      【解决方案6】:
      output = HttpResponse(mimetype='application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
      file_name = "Test.xlsx"
      output['Content-Disposition'] = 'attachment; filename='+ file_name
      
      wb = Workbook()
      
      ws = wb.worksheets[0]
      
      ws.cell('A1').value = 3.14
      
      wb.save(output)
      
      return output
      

      我使用这个技巧通过 openpyxl 下载我的文件。希望对您有所帮助

      【讨论】:

      • 这在 Django 2.0 中完美运行。经过数小时的编码问题、NamedTemporaryFile 问题以及这最终解决了问题!
      【解决方案7】:

      我也有同样的问题。 解决方法是将stdout切换到bin模式:

      import msvcrt
      
      print 'Content-Type:application/octet-stream; name="{}"'.format(os.path.basename(xls_file))
      print 'Content-Disposition:attachment; filename="{}"'.format(os.path.basename(xls_file))
      print "Content-Length: " + str(os.path.getsize(xls_file))
      print 'Cache-Control: max-age=0\r\n'
      
      msvcrt.setmode (1, os.O_BINARY) # stdout = 1
      sys.stdout.flush()
      with open(xls_file, 'rb') as fobj:
          copyfileobj(fobj, sys.stdout)
      

      【讨论】:

        猜你喜欢
        • 2011-12-14
        • 1970-01-01
        • 2012-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-16
        • 2011-07-25
        相关资源
        最近更新 更多