[技術メモ] PythonでExcelファイルをCSVに変換する方法

Pythonを使ってExcelファイルをCSVファイルに変換する処理のメモです。試したときの環境は以下の通りです。

  • Python: 3.6.0
  • openpyxl: 2.4.1
  • xlrd: 1.0.0

openpyxlを使用

openpyxlを使ってExcelファイルを読み込む方法です。

openpyxlのインストール

pipを使ってインストールできます。

$ pip install openpyxl

openpyxlを使ったサンプル

下記サンプルではdata/test.xlsxを読み込んで、ブックに含まれる全てのシートをCSV形式で出力しています。出力はoutput/openpyxl_sampleの下に、シート名.csvという形式で作成されます。

# coding: utf-8
import os
import csv
import openpyxl


def main():
    # ブックを読み込みます。
    filepath = os.path.join('data', 'test.xlsx')
    book = openpyxl.load_workbook(filepath, read_only=True, keep_vba=False)

    dest_dir = os.path.join('output', 'openpyxl_sample')
    os.makedirs(dest_dir, exist_ok=True)

    # シートでループ
    for sheet in book.worksheets:
        sheet_name = sheet.title  # シート名を取得
        dest_path = os.path.join(dest_dir, sheet_name + '.csv')

        with open(dest_path, 'w', encoding='utf-8') as fp:
            writer = csv.writer(fp)

            for cols in sheet.rows:
                writer.writerow([str(col.value or '') for col in cols])


if __name__ == '__main__':
    main()

githubで表示

openpyxlで気になったこと

ドキュメントにあるように、.xlsには対応していないみたいです。

Openpyxl is a Python library for reading and writing Excel 2010 xlsx/xlsm/xltx/xltm files.

実際に.xlsを読み込むと以下の様なExceptionが発生しました。

raise InvalidFileException(msg)
openpyxl.utils.exceptions.InvalidFileException: openpyxl does not support the old .xls file format,
please use xlrd to read this file, or convert it to the more recent .xlsx file format.`

xlrd

xlrdを使ってExcelファイルを読み込む方法です。

xlrdのインストール

openpyxlと同様、pipでインストール可能です。

$ pip install xlrd

xlrdを使ったサンプル

openpyxlのサンプルと同様に、data/test.xlsxを読み込んで、ブックに含まれる全てのシートをCSV形式で出力しています。

# coding: utf-8
import os
import csv
import re
import datetime
import xlrd


def main():
    # ブックを読み込みます。
    filepath = os.path.join('data', 'test.xlsx')
    book = xlrd.open_workbook(filepath)

    dest_dir = os.path.join('output', 'xlrd_sample')
    os.makedirs(dest_dir, exist_ok=True)

    # シートでループ
    for sheet in book.sheets():
        sheet_name = sheet.name
        dest_path = os.path.join(dest_dir, sheet_name + '.csv')

        with open(dest_path, 'w', encoding='utf-8') as fp:
            writer = csv.writer(fp)

            for row in range(sheet.nrows):
                li = []
                for col in range(sheet.ncols):
                    cell = sheet.cell(row, col)

                    if cell.ctype == xlrd.XL_CELL_NUMBER:  # 数値
                        val = cell.value

                        if val.is_integer():
                            # 整数に'.0'が付与されていたのでintにcast
                            val = int(val)

                    elif cell.ctype == xlrd.XL_CELL_DATE:  # 日付
                        dt = get_dt_from_serial(cell.value)
                        val = dt.strftime('%Y-%m-%d %H:%M:%S')

                    else:  # その他
                        val = cell.value

                    li.append(val)
                writer.writerow(li)


def get_dt_from_serial(serial):
    """日付のシリアル値をdatetime型に変換します。"""
    base_date = datetime.datetime(1899, 12, 30)
    d, t = re.search(r'(\d+)(\.\d+)', str(serial)).groups()
    return base_date + datetime.timedelta(days=int(d)) \
        + datetime.timedelta(seconds=float(t) * 86400)


main()

githubで表示

xlrdで気になったこと

openpyxlのときと違い、整数に小数点が付いていました。例えば、セルに99と入力されていた場合は、99.0と取得されていました。そのため、整数の場合はint型にキャストしています。

日付がシリアル値で取得されていました。例えば、セルに2017-01-01 23:13:30と入力されていた場合は、42736.9677199074と取得されていました。そのため、シリアル値をYYYY-mm-dd HH:MM:SSという形式に変換しています。

openpyxlとは違って、xlrdだと.xlsも読み込むことができました。古いExcelファイルを扱う必要がある場合、xlrdが選択肢にあがってくると思います。

その他

このサイトにExcelに関連するPythonのパッケージがまとまっています。

この記事が役に立った場合、シェアしていただけると励みになります!!

この記事に関する質問は@ysk_murayamaでご連絡ください。可能な内容であれば回答します!