xls 到 csv 转换器

Posted

技术标签:

【中文标题】xls 到 csv 转换器【英文标题】:xls to csv converter 【发布时间】:2012-04-10 16:16:48 【问题描述】:

我在 python 中使用 win32.client 将我的 .xlsx 和 .xls 文件转换为 .csv。当我执行此代码时,它给出了一个错误。我的代码是:

def convertXLS2CSV(aFile):
    '''converts a MS Excel file to csv w/ the same name in the same directory'''

    print "------ beginning to convert XLS to CSV ------"

    try:
        import win32com.client, os
        from win32com.client import constants as c
        excel = win32com.client.Dispatch('Excel.Application')

        fileDir, fileName = os.path.split(aFile)
        nameOnly = os.path.splitext(fileName)
        newName = nameOnly[0] + ".csv"
        outCSV = os.path.join(fileDir, newName)
        workbook = excel.Workbooks.Open(aFile)
        workbook.SaveAs(outCSV, c.xlCSVMSDOS) # 24 represents xlCSVMSDOS
        workbook.Close(False)
        excel.Quit()
        del excel

        print "...Converted " + nameOnly + " to CSV"
    except:
        print ">>>>>>> FAILED to convert " + aFile + " to CSV!"

convertXLS2CSV("G:\\hello.xlsx")

我无法在此代码中找到错误。请帮忙。

【问题讨论】:

请发布错误和完整的回复 首先删除 try/except,你不会得到这样的有用错误。 【参考方案1】:

我会使用 xlrd - 它更快、跨平台并且可以直接处理文件。

As of version 0.8.0、xlrd 读取 XLS 和 XLSX 文件。

但是as of version 2.0.0,支持减少回 XLS。

import xlrd
import csv

def csv_from_excel():
    wb = xlrd.open_workbook('your_workbook.xls')
    sh = wb.sheet_by_name('Sheet1')
    your_csv_file = open('your_csv_file.csv', 'wb')
    wr = csv.writer(your_csv_file, quoting=csv.QUOTE_ALL)

    for rownum in xrange(sh.nrows):
        wr.writerow(sh.row_values(rownum))

    your_csv_file.close()

【讨论】:

不应该是wr.writerow(sh.row_values(rownum))吗?见here。 是否支持从 xls datmode 到普通日期时间的日期时间转换 如果您不知道工作表的名称(即不是Sheet1),那么您可以使用wb.sheet_by_index(0) 获取第一张工作表,无论其名称如何。 注意:这种方法不会保留某些数字的 Excel 格式。整数格式的数值将以十进制形式写入(例如 2 -> 2.0),整数格式的公式也将以十进制格式写入(例如 =A1/B2 显示为 1 但导出为 0.9912319),以及文本的前导零-格式化的数值将被剥离(例如“007”->“7.0”)。祝您在秘密特工数据库中查询邦德先生好运!如果你幸运的话,这些问题会在明显的失败中突然出现。如果您不走运,他们可能会默默地毒害您的数据。 对于python 3:使用your_csv_file = open(xls_path, 'w')(不是'wb')。 csv 模块以文本模式而不是字节模式接受输入。否则,你会得到:TypeError: a bytes-like object is required, not 'str'【参考方案2】:

我会使用pandas。计算量大的部分是用 cython 或 c-extensions 编写的,以加快处理速度,语法非常简洁。例如,如果要将文件“your_workbook.xls”中的“Sheet1”转换为文件“your_csv.csv”,只需使用***函数read_excelDataFrame 中的方法to_csv类如下:

import pandas as pd
data_xls = pd.read_excel('your_workbook.xls', 'Sheet1', index_col=None)
data_xls.to_csv('your_csv.csv', encoding='utf-8')

设置encoding='utf-8' 可以缓解其他答案中提到的UnicodeEncodeError

【讨论】:

如果行中有一些其他语言的文本,它不起作用。它显示???在文本中 @philE 这太慢了。使用 xlsx2csv 有关处理可能在 excel 单元格内容中的换行符的任何提示?【参考方案3】:

也许有人发现这段即用型代码很有用。它允许从 Excel 工作簿中的所有电子表格创建 CSV。

Python 2:

# -*- coding: utf-8 -*-
import xlrd
import csv
from os import sys
 
def csv_from_excel(excel_file):
    workbook = xlrd.open_workbook(excel_file)
    all_worksheets = workbook.sheet_names()
    for worksheet_name in all_worksheets:
        worksheet = workbook.sheet_by_name(worksheet_name)
        with open(u'.csv'.format(worksheet_name), 'wb') as your_csv_file:
            wr = csv.writer(your_csv_file, quoting=csv.QUOTE_ALL)
            for rownum in xrange(worksheet.nrows):
                wr.writerow([unicode(entry).encode("utf-8") for entry in worksheet.row_values(rownum)])

if __name__ == "__main__":
    csv_from_excel(sys.argv[1])

Python 3:

import xlrd
import csv
from os import sys

def csv_from_excel(excel_file):
    workbook = xlrd.open_workbook(excel_file)
    all_worksheets = workbook.sheet_names()
    for worksheet_name in all_worksheets:
        worksheet = workbook.sheet_by_name(worksheet_name)
        with open(u'.csv'.format(worksheet_name), 'w', encoding="utf-8") as your_csv_file:
            wr = csv.writer(your_csv_file, quoting=csv.QUOTE_ALL)
            for rownum in range(worksheet.nrows):
                wr.writerow(worksheet.row_values(rownum))

if __name__ == "__main__":
    csv_from_excel(sys.argv[1])

【讨论】:

只是几个注释:一些工作表可能是空的。我看不到生成空 CSV 文件的实用程序,最好在做任何事情之前先对 worksheet.nrows > 0 进行评估。 另外,最好为 CSV 文件使用上下文;) 您可以使用if worksheet.nrows == 0: continue跳过空白工作表 我收到File "<ipython-input-24-5fa644cde9f8>", line 15, in <module> csv_from_excel("Analyse Article Lustucru PF.xlsx") File "<ipython-input-24-5fa644cde9f8>", line 6, in csv_from_excel with open('.csv'.format(worksheet_name), 'wb') as your_csv_file: UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 2: ordinal not in range(128) 你知道怎么处理吗? @OrhanYazar 尝试使用 u'.csv'.format(worksheet_name) 通知 u 在开头代表 unciode【参考方案4】:

我会使用 csvkit,它使用 xlrd(用于 xls)和 openpyxl(用于 xlsx)将几乎所有表格数据转换为 csv。

一旦安装,它的依赖关系,这是一个问题:

python in2csv myfile > myoutput.csv

它会处理所有格式检测问题,因此您几乎可以传递任何表格数据源。它也是跨平台的(不依赖于 win32)。

【讨论】:

也喜欢这个工具。与这个问题不太相关,但我在this book 中提到了这个 csvkit 的东西,以及其他一些允许您在 shell 内转换数据的数据处理工具。【参考方案5】:

首先将您的 excel 电子表格读入 pandas,下面的代码会将您的 excel 电子表格作为 OrderedDict 类型导入 pandas,其中包含您所有的工作表作为数据框。然后只需使用 worksheet_name 作为键以将特定工作表作为数据框访问,并使用 df.to_csv() 仅将所需的工作表保存为 csv 文件。希望这会在你的情况下得到锻炼。

import pandas as pd
df = pd.read_excel('YourExcel.xlsx', sheet_name=None)
df['worksheet_name'].to_csv('YourCsv.csv')  

如果您的 Excel 文件只包含一个工作表,则只需使用以下代码:

import pandas as pd
df = pd.read_excel('YourExcel.xlsx')
df.to_csv('YourCsv.csv') 

如果有人想将所有 excel 工作表从单个 excel 工作簿转换为不同的 csv 文件,请尝试以下代码:

import pandas as pd
def excelTOcsv(filename):
    df = pd.read_excel(filename, sheet_name=None)  
    for key, value in df.items(): 
        return df[key].to_csv('%s.csv' %key)

此功能作为同一个 Excel 工作簿的多个 Excel 工作表到多个 csv 文件转换器。其中 key 是工作表名称,value 是工作表内的内容。

【讨论】:

【参考方案6】:

@andi 我测试了你的代码,效果很好,但是

在我的工作表中有这样的一列

2013-03-06T04:00:00

日期和时间在同一个单元格中

导出时出现乱码,导出文件中是这样的

41275.0416667

其他列都可以。

另一方面,csvkit 可以处理该列,但只导出一个工作表,而我的文件有很多。

【讨论】:

我也做了同样的事情,我也得到了同样的垃圾。你知道解决这个问题的方法吗? 对不起,我忘了我当时做了什么。我了解到这不是一个随机数,而是 Excel 使用的内部表示或日期时间。所以有一个算法可以得到正确的日期时间。 我不能再精确了,对不起【参考方案7】:

xlsx2csv 比 pandas 和 xlrd

xlsx2csv -s 0 crunchbase_monthly_.xlsx cruchbase

excel文件通常带有n个sheetname。

-s is sheetname index.

然后,会创建 cruchbase 文件夹,每个属于 xlsx 的工作表都将转换为单个 csv。

附言csvkit 也很棒。

【讨论】:

【参考方案8】:

从Scott Ming 引用answer,它适用于包含多个工作表的工作簿:

这里是一个python脚本getsheets.py(mirror),使用前需要安装pandasxlrd

运行这个:

pip3 install pandas xlrd  # or `pip install pandas xlrd`

它是如何工作的?

$ python3 getsheets.py -h
Usage: getsheets.py [OPTIONS] INPUTFILE

Convert a Excel file with multiple sheets to several file with one sheet.

Examples:

    getsheets filename

    getsheets filename -f csv

Options:
-f, --format [xlsx|csv]  Default xlsx.
-h, --help               Show this message and exit.

转换成几个xlsx:

$ python3 getsheets.py goods_temp.xlsx
Sheet.xlsx Done!
Sheet1.xlsx Done!

All Done!

转换成几个csv:

$ python3 getsheets.py goods_temp.xlsx -f csv
Sheet.csv Done!
Sheet1.csv Done!

All Done!

getsheets.py:

# -*- coding: utf-8 -*-

import click
import os
import pandas as pd


def file_split(file):
    s = file.split('.')
    name = '.'.join(s[:-1])  # get directory name
    return name


def getsheets(inputfile, fileformat):
    name = file_split(inputfile)
    try:
        os.makedirs(name)
    except:
        pass

    df1 = pd.ExcelFile(inputfile)
    for x in df1.sheet_names:
        print(x + '.' + fileformat, 'Done!')
        df2 = pd.read_excel(inputfile, sheetname=x)
        filename = os.path.join(name, x + '.' + fileformat)
        if fileformat == 'csv':
            df2.to_csv(filename, index=False)
        else:
            df2.to_excel(filename, index=False)
    print('\nAll Done!')


CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])


@click.command(context_settings=CONTEXT_SETTINGS)
@click.argument('inputfile')
@click.option('-f', '--format', type=click.Choice([
    'xlsx', 'csv']), default='xlsx', help='Default xlsx.')
def cli(inputfile, format):
    '''Convert a Excel file with multiple sheets to several file with one sheet.

    Examples:

    \b
        getsheets filename

    \b
        getsheets filename -f csv
    '''
    if format == 'csv':
        getsheets(inputfile, 'csv')
    else:
        getsheets(inputfile, 'xlsx')


cli()

【讨论】:

【参考方案9】:

我们可以使用 Python 的 Pandas lib 将 xls 文件转换为 csv 文件 下面的代码会将 xls 文件转换为 csv 文件。 将熊猫导入为 pd

从本地路径读取 Excel 文件:

df = pd.read_excel("C:/Users/IBM_ADMIN/BU GPA Scorecard.xlsx",sheetname=1)

修剪列上的空格:

df.columns = df.columns.str.strip()

将数据帧发送到 CSV 文件,该文件将被管道符号分隔且没有索引:

df.to_csv("C:/Users/IBM_ADMIN/BU GPA Scorecard csv.csv",sep="|",index=False)

【讨论】:

使用您的代码,我收到一个错误:>>> dfs = pd.read_excel(file_name, sheet_name=None) >>> dfs.columns = dfs.columns.str.strip() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'collections.OrderedDict' object has no attribute 'columns'【参考方案10】:

Python 不是完成这项任务的最佳工具。我在 Python 中尝试了几种方法,但没有一种方法能 100% 工作(例如 10% 转换为 0.1,或者列类型被搞砸了,等等)。正确的工具是 PowerShell,因为它是 MS 产品(与 Excel 一样)并且具有最佳集成度。

只需下载this PowerShell 脚本,编辑第 47 行以输入包含 Excel 文件的文件夹的路径,然后使用 PowerShell 运行脚本。

【讨论】:

【参考方案11】:

使用 xlrd 是一种有缺陷的方法,因为您会丢失 Excel 中的日期格式。

我的用例如下。

获取一个包含多个工作表的 Excel 文件,并将每个工作表转换为自己的文件。

我已使用 xlsx2csv 库完成此操作,并使用子进程调用它。

import csv
import sys, os, json, re, time
import subprocess

def csv_from_excel(fname):
    subprocess.Popen(["xlsx2csv " + fname + " --all -d '|' -i -p "
                      "'<New Sheet>' > " + 'test.csv'], shell=True)

    return

lstSheets = csv_from_excel(sys.argv[1])

time.sleep(3) # system needs to wait a second to recognize the file was  written

with open('[YOUR PATH]/test.csv') as f:
    lines = f.readlines()
    firstSheet = True

    for line in lines:
        if line.startswith('<New Sheet>'):
            if firstSheet:
                sh_2_fname = line.replace('<New Sheet>', '').strip().replace(' - ', '_').replace(' ','_')
                print(sh_2_fname)
                sh2f = open(sh_2_fname+".csv", "w")
                firstSheet = False
            else:
                sh2f.close()
                sh_2_fname = line.replace('<New Sheet>', '').strip().replace(' - ', '_').replace(' ','_')
                print(sh_2_fname)
                sh2f = open(sh_2_fname+".csv", "w")
        else:
            sh2f.write(line)
sh2f.close()

【讨论】:

【参考方案12】:

我测试了所有答案,但它们对我来说都太慢了。如果您安装了 Excel,则可以使用 COM。

我最初认为它会更慢,因为它会为实际的 Excel 应用程序加载所有内容,但它不适用于大文件。可能是因为打开和保存文件的算法运行的是经过高度优化的编译代码,毕竟微软人为此赚了很多钱。

import sys
import os
import glob
from win32com.client import Dispatch

def main(path):
    excel = Dispatch("Excel.Application")
    if is_full_path(path):
        process_file(excel, path)
    else:
        files = glob.glob(path)
        for file_path in files:
            process_file(excel, file_path)
    excel.Quit()

def process_file(excel, path):
    fullpath = os.path.abspath(path)
    full_csv_path = os.path.splitext(fullpath)[0] + '.csv'
    workbook = excel.Workbooks.Open(fullpath)
    workbook.Worksheets(1).SaveAs(full_csv_path, 6)
    workbook.Saved = 1
    workbook.Close()


def is_full_path(path):
    return path.find(":") > -1

if __name__ == '__main__':
    main(sys.argv[1])

这是非常原始的代码,不会检查错误、打印帮助或任何内容,它只会为每个与您在函数中输入的模式匹配的文件创建一个 csv 文件,这样您就可以只批处理大量文件启动 excel 应用程序一次。

【讨论】:

【参考方案13】:

尽管我讨厌依赖非跨平台的 Windows Excel 专有软件,但我对 csvkit 的 .xls 测试(它在后台使用 xlrd)未能正确解析日期(即使使用命令行参数指定strptime格式)。

例如,this xls file,当用csvkit 解析时,会将12/31/2002 的单元格G1 转换为37621,而当通过excel 转换为csv 时-> save_as(使用下面)单元格G1将是"December 31, 2002"

import re
import os
from win32com.client import Dispatch
xlCSVMSDOS = 24

class CsvConverter(object):
    def __init__(self, *, input_dir, output_dir):
        self._excel = None
        self.input_dir = input_dir
        self.output_dir = output_dir

        if not os.path.isdir(self.output_dir):
            os.makedirs(self.output_dir)

    def isSheetEmpty(self, sheet):
        # https://archive.is/RuxR7
        # WorksheetFunction.CountA(ActiveSheet.UsedRange) = 0 And ActiveSheet.Shapes.Count = 0

        return \
            (not self._excel.WorksheetFunction.CountA(sheet.UsedRange)) \
            and \
            (not sheet.Shapes.Count)

    def getNonEmptySheets(self, wb, as_name=False):
        return [ \
            (sheet.Name if as_name else sheet) \
            for sheet in wb.Sheets \
            if not self.isSheetEmpty(sheet) \
        ]

    def saveWorkbookAsCsv(self, wb, csv_path):
        non_empty_sheet_names = self.getNonEmptySheets(wb, as_name=True)

        assert (len(non_empty_sheet_names) == 1), \
            "Expected exactly 1 sheet but found %i non-empty sheets: '%s'" \
            %(
                len(non_empty_sheet_names),
                "', '".join(name.replace("'", r"\'") for name in non_empty_sheet_names)
            )

        wb.Worksheets(non_empty_sheet_names[0]).SaveAs(csv_path, xlCSVMSDOS)
        wb.Saved = 1

    def isXlsFilename(self, filename):
        return bool(re.search(r'(?i)\.xls$', filename))

    def batchConvertXlsToCsv(self):
        xls_names = tuple( filename for filename in next(os.walk(self.input_dir))[2] if self.isXlsFilename(filename) )

        self._excel = Dispatch('Excel.Application')
        try:
            for xls_name in xls_names:
                csv_path = os.path.join(self.output_dir, '%s.csv' %os.path.splitext(xls_name)[0])
                if not os.path.isfile(csv_path):
                    workbook = self._excel.Workbooks.Open(os.path.join(self.input_dir, xls_name))
                    try:
                        self.saveWorkbookAsCsv(workbook, csv_path)
                    finally:
                        workbook.Close()
        finally:
            if not len(self._excel.Workbooks):
                self._excel.Quit()

            self._excel = None

if __name__ == '__main__':
    self = CsvConverter(
        input_dir='C:\\data\\xls\\',
        output_dir='C:\\data\\csv\\'
    )

    self.batchConvertXlsToCsv()

上面将采用一个包含 .xls 的 input_dir 并将它们作为 .csv 输出到 output_dir - 它会 assert 在 .xls 中恰好有 1 个非空工作表;如果您需要将多个工作表处理成多个 csv,那么您需要编辑 saveWorkbookAsCsv

【讨论】:

【参考方案14】:

我试图使用xlrd 库将格式xlsx 转换为csv,但我收到错误:xlrd.biffh.XLRDError: Excel xlsx file; not supported。这是因为这个包不再读取任何其他格式,除非xls,根据xlrd documentation。

根据Chris Withers 的回答,我能够从pandas 更改函数read_excel() 的引擎,然后我能够创建一个函数来转换您想要成功的Excel 电子表格中的任何工作表. 为了使用下面的功能,别忘了从here 安装openpyxl 库。

功能:

import os
import pathlib
import pandas as pd

# Function to convert excel spreadsheet into csv format
def Excel_to_csv():
    # Excel file full path
    excel_file = os.path.join(os.path.sep, pathlib.Path(__file__).parent.resolve(), "Excel_Spreadsheet.xlsx")    
    # Excel sheets
    excel_sheets = ['Sheet1', 'Sheet2', 'Sheet3']

    for sheet in excel_sheets:
        # Create dataframe for each sheet
        df = pd.DataFrame(pd.read_excel(excel_file, sheet, index_col=None, engine='openpyxl'))
        # Export to csv. i.e: sheet_name.csv
        df.to_csv(os.path.join(os.path.sep, pathlib.Path(__file__).parent.resolve(), sheet + '.csv'), sep=",", encoding='utf-8', index=False, header=True)

# Runs the excel_to_csv function:
Excel_to_csv()

【讨论】:

以上是关于xls 到 csv 转换器的主要内容,如果未能解决你的问题,请参考以下文章

php Zamzar文件转换和下载。示例是XLS到CSV

如何批量将csv文件转换成xls文件

将 xls 文件批量转换为 csv

excel批量转换为CSV格式,xls批量导出csv格式

将 CSV/XLS 转换为 JSON? [关闭]

在命令行上将 XLS 转换为 CSV