【问题标题】:Read Excel XML .xls file with pandas使用 pandas 读取 Excel XML .xls 文件
【发布时间】:2016-02-01 21:27:51
【问题描述】:

我知道一些先前提出的问题,但给出的解决方案均不适用于我在下面提供的可重现示例。

我正在尝试从http://www.eia.gov/coal/data.cfm#production 读取.xls 文件——特别是历史详细的煤炭生产数据(1983-2013) coalpublic2012.xls 文件,该文件可通过下拉列表免费获得。熊猫无法阅读它。

相比之下,最近一年可用的文件,2013,coalpublic2013.xls 文件,可以正常工作:

import pandas as pd
df1 = pd.read_excel("coalpublic2013.xls")

但下一个十年的 .xls 文件 (2004-2012) 不会加载。我用 Excel 查看了这些文件,它们打开了,没有损坏。

我从 pandas 得到的错误是:

---------------------------------------------------------------------------
XLRDError                                 Traceback (most recent call last)
<ipython-input-28-0da33766e9d2> in <module>()
----> 1 df = pd.read_excel("coalpublic2012.xlsx")

/Users/jonathan/anaconda/lib/python2.7/site-packages/pandas/io/excel.pyc in read_excel(io, sheetname, header, skiprows, skip_footer, index_col, parse_cols, parse_dates, date_parser, na_values, thousands, convert_float, has_index_names, converters, engine, **kwds)
    161 
    162     if not isinstance(io, ExcelFile):
--> 163         io = ExcelFile(io, engine=engine)
    164 
    165     return io._parse_excel(

/Users/jonathan/anaconda/lib/python2.7/site-packages/pandas/io/excel.pyc in __init__(self, io, **kwds)
    204                 self.book = xlrd.open_workbook(file_contents=data)
    205             else:
--> 206                 self.book = xlrd.open_workbook(io)
    207         elif engine == 'xlrd' and isinstance(io, xlrd.Book):
    208             self.book = io

/Users/jonathan/anaconda/lib/python2.7/site-packages/xlrd/__init__.pyc in open_workbook(filename, logfile, verbosity, use_mmap, file_contents, encoding_override, formatting_info, on_demand, ragged_rows)
    433         formatting_info=formatting_info,
    434         on_demand=on_demand,
--> 435         ragged_rows=ragged_rows,
    436         )
    437     return bk

/Users/jonathan/anaconda/lib/python2.7/site-packages/xlrd/book.pyc in open_workbook_xls(filename, logfile, verbosity, use_mmap, file_contents, encoding_override, formatting_info, on_demand, ragged_rows)
     89         t1 = time.clock()
     90         bk.load_time_stage_1 = t1 - t0
---> 91         biff_version = bk.getbof(XL_WORKBOOK_GLOBALS)
     92         if not biff_version:
     93             raise XLRDError("Can't determine file's BIFF version")

/Users/jonathan/anaconda/lib/python2.7/site-packages/xlrd/book.pyc in getbof(self, rqd_stream)
   1228             bof_error('Expected BOF record; met end of file')
   1229         if opcode not in bofcodes:
-> 1230             bof_error('Expected BOF record; found %r' % self.mem[savpos:savpos+8])
   1231         length = self.get2bytes()
   1232         if length == MY_EOF:

/Users/jonathan/anaconda/lib/python2.7/site-packages/xlrd/book.pyc in bof_error(msg)
   1222         if DEBUG: print("reqd: 0x%04x" % rqd_stream, file=self.logfile)
   1223         def bof_error(msg):
-> 1224             raise XLRDError('Unsupported format, or corrupt file: ' + msg)
   1225         savpos = self._position
   1226         opcode = self.get2bytes()

XLRDError: Unsupported format, or corrupt file: Expected BOF record; found '<?xml ve'

我还尝试了其他各种方法:

df = pd.ExcelFile("coalpublic2012.xls", encoding_override='cp1252')
import xlrd
wb = xlrd.open_workbook("coalpublic2012.xls")

无济于事。我的熊猫版本:0.17.0

我也将此作为一个错误提交给 pandas github issues 列表。

【问题讨论】:

    标签: python excel pandas xlrd


    【解决方案1】:

    您可以通过编程方式转换此 Excel XML 文件。要求:只有 python 和 pandas。

    import pandas as pd
    from xml.sax import ContentHandler, parse
    
    # Reference https://goo.gl/KaOBG3
    class ExcelHandler(ContentHandler):
        def __init__(self):
            self.chars = [  ]
            self.cells = [  ]
            self.rows = [  ]
            self.tables = [  ]
        def characters(self, content):
            self.chars.append(content)
        def startElement(self, name, atts):
            if name=="Cell":
                self.chars = [  ]
            elif name=="Row":
                self.cells=[  ]
            elif name=="Table":
                self.rows = [  ]
        def endElement(self, name):
            if name=="Cell":
                self.cells.append(''.join(self.chars))
            elif name=="Row":
                self.rows.append(self.cells)
            elif name=="Table":
                self.tables.append(self.rows)
    
    excelHandler = ExcelHandler()
    parse('coalpublic2012.xls', excelHandler)
    df1 = pd.DataFrame(excelHandler.tables[0][4:], columns=excelHandler.tables[0][3])
    

    【讨论】:

    • 您可以使用xlsxwriter 模块而不是整个pandas。当然如果你不需要它:) excel-xml解析器的改进版gist.github.com/Winand/395e7d483434ee3828d04fe5732ca690
    • @jrovegno 这是迄今为止我可以在网上找到的关于 pandas 的最佳答案。问题是它至少在我手中丢失了工作表名称信息。
    • 是否可以获取工作表名称? @jrovegno
    • 在@Winand 链接中实现,您可以访问工作表名称。在 __init__ 和 startElement 中初始化 self.worksheet_names = [] 检查名称是否为工作表,如果是,则通过属性“ss:Name”代码elif name == "Worksheet": self.worksheet_names.append(atts.getValue("ss:Name")) 获取工作表名称
    【解决方案2】:

    问题在于,虽然 2013 年的数据是一个实际的 Excel 文件,但 2012 年的数据是一个 XML 文档,这在 Python 中似乎不受支持。我会说你最好的选择是在 Excel 中打开它,然后将副本另存为适当的 Excel 文件或 CSV。

    【讨论】:

    • 是的,我怀疑你是对的。我将此作为人们将要学习的课程的示例——我不想让他们使用 Excel 来进行这种分析。我希望有一种方法可以通过 python(如果不是 pandas)工具来强制进行这种转换。
    • 看来问题是由于熊猫使用旧版本xlrd ...可能这是可以修复的问题
    • 我在xlrd 这里github.com/python-excel/xlrd/issues/156 提出了一个问题
    • 同意一个更简单的方法是尽可能获取 csv 源。只想指出,Python 支持 XML,使用 ElementTree docs.python.org/2/library/xml.etree.elementtree.html 或 lxml lxml.de 之类的库可能无法直接导入到 Pandas,但那是因为 XML 是一种嵌套数据结构。 Pandas 数据可以包含“类似列表的对象”,但是从 XML 节点和元素到类似列表的对象的转换是不明确的,因此您必须指定映射,或者通过推断或扁平化数据的过程来制作该转换一致。
    • @Davos 啊,是的,我想我一定是想写 pandas 不支持 xml ...顺便说一下,自从写了这个答案后,我 偶尔 b> 使用xmltodict成功将 xml 直接读入 pandas
    【解决方案3】:

    您可以通过编程方式转换此 Excel XML 文件。 要求:已安装 Windows、Office。

    1.在记事本中创建ExcelToCsv.vbs脚本:

    if WScript.Arguments.Count < 3 Then
        WScript.Echo "Please specify the source and the destination files. Usage: ExcelToCsv <xls/xlsx source file> <csv destination file> <worksheet number (starts at 1)>"
        Wscript.Quit
    End If
    
    csv_format = 6
    
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    
    src_file = objFSO.GetAbsolutePathName(Wscript.Arguments.Item(0))
    dest_file = objFSO.GetAbsolutePathName(WScript.Arguments.Item(1))
    worksheet_number = CInt(WScript.Arguments.Item(2))
    
    Dim oExcel
    Set oExcel = CreateObject("Excel.Application")
    
    Dim oBook
    Set oBook = oExcel.Workbooks.Open(src_file)
    oBook.Worksheets(worksheet_number).Activate
    
    oBook.SaveAs dest_file, csv_format
    
    oBook.Close False
    oExcel.Quit
    
    1. 将 Excel XML 文件转换为 CSV:

    $ cscript ExcelToCsv.vbs coalpublic2012.xls coalpublic2012.csv 1

    1. 用 pandas 打开 CSV 文件

    &gt;&gt;&gt; df1 = pd.read_csv('coalpublic2012.csv', skiprows=3)

    参考:Faster way to read Excel files to pandas dataframe

    【讨论】:

      【解决方案4】:

      @JBWhitmore 我已经运行了以下代码:

      import pandas as pd
      #Read and write to excel
      dataFileUrl = r"/Users/stutiverma/Downloads/coalpublic2012.xls"
      data = pd.read_table(dataFileUrl)
      

      这会成功读取文件而不会出现任何错误。但是,它以所提到的确切格式提供所有数据。因此,您可能需要付出额外的努力才能在成功读取数据后对其进行处理。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-21
        • 1970-01-01
        • 2011-02-25
        • 1970-01-01
        • 2023-02-10
        • 1970-01-01
        • 2018-10-24
        相关资源
        最近更新 更多