プログラミング / 言語 / 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)をインストールします。
# 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 オブジェクトを取得します。シートは名前またはインデックスで指定します。
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 通りがあります。どちらも同じセルを指します。
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()
空セルの扱い: 値が入っていないセルの
.value は None を返します。文字列操作の前に if cell.value is not None: で確認しましょう。
5. 行・列を反復する
シート全体や特定範囲を行・列単位でループする方法を解説します。
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() は開始・終了の行列番号を引数で絞り込めます。
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 | — |
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. シート情報を取得する
シートやブック全体のメタ情報(プロパティ・シート一覧・非表示設定など)を取得する方法です。
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 から取得する方法です。
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 として取り込めるため、集計・フィルタ・グラフ化が簡単に行えます。
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 を組み合わせた実践パターンです。
"""
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() を使った出力方法を詳しく解説します。