プログラミング / 言語 / Python

Excel 読み取り
— openpyxl / pandas 完全ガイド

1. ライブラリ比較と選び方

Python で Excel を扱うライブラリは複数あります。用途に合わせて選ぶことが大切です。

ライブラリ 対応形式 読み取り 書き込み 用途・特徴
openpyxl .xlsx / .xlsm 最も汎用的。書式・数式・グラフも操作可能
pandas .xlsx / .xls / .csv データ分析向け。DataFrame として扱える
xlrd .xls(旧形式) × 古い .xls 形式の読み取り専用
xlwt .xls(旧形式) × 古い .xls 形式の書き込み専用(非推奨)
xlsxwriter .xlsx × 書き込み専用。グラフや条件付き書式に強い
選び方の目安: .xlsx の読み書き → openpyxl、データ集計・分析 → pandas、古い .xls ファイルの読み取り → xlrd を選ぶのが基本です。本記事では openpyxl と pandas を中心に解説します。

2. インストール

openpyxl と pandas(および pandas の Excel エンジンに必要な openpyxl)をインストールします。

shell
# openpyxl(.xlsx の読み書き)
pip install openpyxl

# pandas(データ分析。Excel エンジンとして openpyxl を利用)
pip install pandas openpyxl

# 古い .xls 形式も読む場合は xlrd も追加
pip install xlrd
バージョン確認: pip show openpyxl で現在のバージョンを確認できます。本記事は openpyxl 3.x 系、pandas 2.x 系を前提としています。

3. ブック・シートを開く

openpyxl では load_workbook() でファイルを開き、Workbook オブジェクトを取得します。シートは名前またはインデックスで指定します。

python
import openpyxl

# ── ブックを開く ──────────────────────────────────────────
wb = openpyxl.load_workbook("sample.xlsx")

# read_only=True にするとメモリ効率が良い(書き込みは不可)
wb_ro = openpyxl.load_workbook("sample.xlsx", read_only=True)

# data_only=True で数式セルの「表示値」を読む(計算結果が必要な場合)
wb_data = openpyxl.load_workbook("sample.xlsx", data_only=True)

# ── シートを取得 ──────────────────────────────────────────
# アクティブシート(最後に開いていたシート)
ws = wb.active

# シート名で指定
ws = wb["Sheet1"]

# シート一覧を確認
print(wb.sheetnames)        # ['Sheet1', '売上データ', '設定']

# インデックスで取得
ws = wb.worksheets[0]       # 先頭シート

# ブックを閉じる(read_only モードの場合は必ず閉じる)
wb.close()
data_only=True の注意: 数式の計算結果は Excel が最後に保存したときのキャッシュ値を読みます。Excel で一度も開いていないファイルや、Python で書き込んだ直後のファイルでは None になることがあります。

4. セルの値を読み取る

セルの指定には「A1 形式」と「行・列番号」の 2 通りがあります。どちらも同じセルを指します。

python
import openpyxl

wb = openpyxl.load_workbook("sample.xlsx")
ws = wb.active

# ── A1 形式で取得 ─────────────────────────────────────────
val = ws["A1"].value
print(val)                  # セルの値

# ── 行・列番号で取得(1 始まり)──────────────────────────
val = ws.cell(row=1, column=1).value
print(val)

# ── セルオブジェクトの属性 ───────────────────────────────
cell = ws["B2"]
print(cell.value)           # 値
print(cell.data_type)       # データ型コード ('n'=数値, 's'=文字列, 'd'=日付など)
print(cell.row)             # 行番号 (2)
print(cell.column)          # 列番号 (2)
print(cell.coordinate)      # 'B2'

# ── 数値・文字列・日付の例 ──────────────────────────────
ws["A1"] = 100              # 仮設定は不要、読み取りのみ

# 日付セルは datetime オブジェクトとして返る
from datetime import datetime
date_val = ws["C3"].value   # datetime(2026, 5, 26, 0, 0)
if isinstance(date_val, datetime):
    print(date_val.strftime("%Y/%m/%d"))

wb.close()
空セルの扱い: 値が入っていないセルの .valueNone を返します。文字列操作の前に if cell.value is not None: で確認しましょう。

5. 行・列を反復する

シート全体や特定範囲を行・列単位でループする方法を解説します。

python
import openpyxl

wb = openpyxl.load_workbook("sample.xlsx")
ws = wb.active

# ── 全行を反復 ────────────────────────────────────────────
# ws.rows は各行をタプルとして返すジェネレータ
for row in ws.rows:
    for cell in row:
        print(cell.coordinate, cell.value)

# ── 全列を反復 ────────────────────────────────────────────
for col in ws.columns:
    for cell in col:
        print(cell.coordinate, cell.value)

# ── values_only=True で値だけ取得(セルオブジェクト不要) ──
for row in ws.iter_rows(values_only=True):
    print(row)              # タプルで 1 行分の値が返る

# ── ヘッダー行を辞書のキーとして使う ───────────────────
rows = ws.iter_rows(values_only=True)
headers = next(rows)       # 先頭行をヘッダーとして取得
for row in rows:
    record = dict(zip(headers, row))
    print(record)           # {'名前': '田中', '年齢': 30, ...}

wb.close()
出力例(iter_rows + values_only)
('名前', '年齢', '部署') ('田中', 30, '営業') ('鈴木', 25, '開発') ('佐藤', 35, '人事')
read_only モードでの反復: 大きなファイルを全行スキャンする場合は read_only=True で開くと、メモリ消費を大幅に抑えられます。ただし ws.rows ではなく ws.iter_rows() を使う必要があります。

6. 範囲を指定して読み取る

iter_rows()iter_cols() は開始・終了の行列番号を引数で絞り込めます。

python
import openpyxl

wb = openpyxl.load_workbook("sample.xlsx")
ws = wb.active

# ── iter_rows:行範囲・列範囲を指定 ────────────────────
# 2〜5 行目、A〜C 列(column=1〜3)
for row in ws.iter_rows(min_row=2, max_row=5, min_col=1, max_col=3, values_only=True):
    print(row)

# ── iter_cols:列ごとに取得 ──────────────────────────
for col in ws.iter_cols(min_row=1, max_row=10, min_col=2, max_col=4, values_only=True):
    print(col)

# ── スライス記法 ─────────────────────────────────────
# A1:C5 の範囲を 2 次元タプルで取得
cell_range = ws["A1:C5"]
for row in cell_range:
    for cell in row:
        print(cell.coordinate, cell.value)

# ── シートの実データ範囲を調べる ──────────────────────
print(ws.dimensions)        # 'A1:E20' など
print(ws.max_row)           # 最終行番号
print(ws.max_column)        # 最終列番号

wb.close()

7. セルのデータ型と変換

openpyxl が返す値の型と、よくある型変換パターンをまとめます。

Excel の型 Python の型 data_type コード 備考
数値(整数) int n 小数点がなければ int
数値(小数) float n
文字列 str s
日付・時刻 datetime / time d strftime() で書式化
真偽値 bool b TRUE/FALSE
数式 str(数式文字列) f data_only=True で計算値
空セル None n
python
import openpyxl
from datetime import datetime

wb = openpyxl.load_workbook("sample.xlsx", data_only=True)
ws = wb.active

for row in ws.iter_rows(min_row=2, values_only=True):
    name, age, sales, date_val, active = row

    # None ガード
    if name is None:
        continue

    # 数値を文字列に変換
    age_str = str(age) if age is not None else "-"

    # 日付フォーマット
    date_str = date_val.strftime("%Y/%m/%d") if isinstance(date_val, datetime) else str(date_val)

    # bool → 日本語
    status = "有効" if active else "無効"

    print(f"{name} | {age_str}歳 | {sales:,}円 | {date_str} | {status}")

wb.close()

8. シート情報を取得する

シートやブック全体のメタ情報(プロパティ・シート一覧・非表示設定など)を取得する方法です。

python
import openpyxl

wb = openpyxl.load_workbook("sample.xlsx")

# ── シート一覧 ─────────────────────────────────────────
print(wb.sheetnames)        # ['Sheet1', '売上', '設定']

# ── 各シートの情報 ─────────────────────────────────────
for ws in wb.worksheets:
    print(f"シート名: {ws.title}")
    print(f"  最大行: {ws.max_row}, 最大列: {ws.max_column}")
    print(f"  範囲: {ws.dimensions}")
    print(f"  非表示: {ws.sheet_state}")   # 'visible' / 'hidden'

# ── 列の幅・行の高さ ───────────────────────────────────
ws = wb.active
print(ws.column_dimensions['A'].width)     # A 列の幅
print(ws.row_dimensions[1].height)         # 1 行目の高さ

# ── ブックのプロパティ ─────────────────────────────────
props = wb.properties
print(props.title)          # ブックタイトル
print(props.creator)        # 作成者
print(props.lastModifiedBy) # 最終更新者
print(props.modified)       # 最終更新日時

wb.close()

9. 名前付き範囲を読む

Excel で「名前の定義」をしたセル範囲を Python から取得する方法です。

python
import openpyxl

wb = openpyxl.load_workbook("sample.xlsx")

# ── 定義済みの名前付き範囲を一覧表示 ────────────────────
for name, defn in wb.defined_names.items():
    print(f"名前: {name}")
    for title, coord in defn.destinations:
        print(f"  シート: {title}, 範囲: {coord}")

# ── 名前付き範囲の値を取得 ──────────────────────────────
range_name = "売上データ"  # Excel で定義した名前
defn = wb.defined_names[range_name]

for title, coord in defn.destinations:
    ws = wb[title]
    for row in ws[coord]:
        for cell in row:
            print(cell.value)

wb.close()

10. pandas で読み取る

データ集計・分析が目的なら pandas.read_excel() が最も手軽です。DataFrame として取り込めるため、集計・フィルタ・グラフ化が簡単に行えます。

python
import pandas as pd

# ── 基本 ─────────────────────────────────────────────────
df = pd.read_excel("sample.xlsx")
print(df.head())

# ── 主要なオプション ──────────────────────────────────────
df = pd.read_excel(
    "sample.xlsx",
    sheet_name="売上データ",    # シート名(省略でアクティブ)
    header=0,                   # 何行目をヘッダーにするか(0-indexed)
    skiprows=2,                 # 先頭から何行スキップするか
    nrows=100,                  # 読み込む最大行数
    usecols="A:D",              # 読み込む列('A:D' または [0,1,2,3] または 列名リスト)
    dtype={"年齢": int, "売上": float},  # 列ごとの型指定
    na_values=["N/A", "-"],     # NaN として扱う文字列
    parse_dates=["日付"],        # 日付に変換する列
    index_col="ID",             # インデックスにする列
    engine="openpyxl",          # .xlsx は openpyxl(省略可)
)

# ── 複数シートを一括読み込み ─────────────────────────────
# sheet_name=None ですべてのシートを dict として取得
all_sheets = pd.read_excel("sample.xlsx", sheet_name=None)
for sheet_name, df in all_sheets.items():
    print(f"=== {sheet_name} ===")
    print(df.shape)

# ── 読み込み後の基本操作 ──────────────────────────────────
print(df.dtypes)            # 各列のデータ型
print(df.describe())        # 統計情報
print(df.isnull().sum())    # 欠損値のカウント
df_filtered = df[df["売上"] > 100000]  # 条件フィルタ
engine の指定: pandas 1.3 以降、.xlsx の読み取りには openpyxl エンジンが必要です。pip install openpyxl 済みであれば自動検出されますが、明示的に engine="openpyxl" を指定すると確実です。古い .xls は engine="xlrd" を指定してください。

11. 実践スクリプト

複数シートを横断して売上データを集計し、CSV に出力するスクリプトです。openpyxl と pandas を組み合わせた実践パターンです。

python
"""
Excel 読み取り実践スクリプト
- 複数シートの売上データを集計して CSV 出力
"""

import openpyxl
import pandas as pd
from pathlib import Path


def read_all_sheets(filepath: str) -> dict[str, pd.DataFrame]:
    """すべてのシートを DataFrame の辞書として返す"""
    return pd.read_excel(filepath, sheet_name=None, header=0, engine="openpyxl")


def summarize_sales(sheets: dict[str, pd.DataFrame]) -> pd.DataFrame:
    """各シートから売上列を抽出して月次集計する"""
    records = []
    for sheet_name, df in sheets.items():
        # 「売上」列が存在するシートのみ処理
        if "売上" not in df.columns:
            continue
        total = df["売上"].sum()
        count = df["売上"].count()
        records.append({"シート": sheet_name, "件数": count, "合計売上": total})
    return pd.DataFrame(records)


def get_cell_info(filepath: str, sheet_name: str, cell_addr: str) -> dict:
    """特定セルのメタ情報を openpyxl で取得"""
    wb = openpyxl.load_workbook(filepath, data_only=True)
    ws = wb[sheet_name]
    cell = ws[cell_addr]
    info = {
        "coordinate": cell.coordinate,
        "value": cell.value,
        "data_type": cell.data_type,
        "row": cell.row,
        "column": cell.column,
    }
    wb.close()
    return info


def main():
    filepath = "sales_report.xlsx"

    # シート一覧を openpyxl で確認
    wb = openpyxl.load_workbook(filepath)
    print("シート一覧:", wb.sheetnames)
    wb.close()

    # pandas で全シート読み込み
    sheets = read_all_sheets(filepath)
    print(f"\n読み込んだシート数: {len(sheets)}")
    for name, df in sheets.items():
        print(f"  {name}: {df.shape[0]}行 × {df.shape[1]}列")

    # 集計
    summary = summarize_sales(sheets)
    print("\n=== 集計結果 ===")
    print(summary.to_string(index=False))

    # CSV 出力
    out_path = Path("output_summary.csv")
    summary.to_csv(out_path, index=False, encoding="utf-8-sig")
    print(f"\nCSV を保存しました: {out_path}")

    # 特定セルのメタ情報
    info = get_cell_info(filepath, wb.sheetnames[0], "B2")
    print("\n=== セル情報 ===")
    for k, v in info.items():
        print(f"  {k}: {v}")


if __name__ == "__main__":
    main()
出力例
シート一覧: ['1月', '2月', '3月', '集計'] 読み込んだシート数: 4 1月: 31行 × 5列 2月: 28行 × 5列 3月: 31行 × 5列 集計: 3行 × 3列 === 集計結果 === シート 件数 合計売上 1月 31 4520000.0 2月 28 3890000.0 3月 31 5130000.0 CSV を保存しました: output_summary.csv === セル情報 === coordinate: B2 value: 田中太郎 data_type: s row: 2 column: 2
次のステップ: 読み取ったデータを加工して Excel ファイルに書き出すには PART 07 の「Excel 書き込み」を参照してください。openpyxl による書式設定や pandas の to_excel() を使った出力方法を詳しく解説します。