引き継いだ進捗表や見積書には、前任者がセルに残したメモがそのまま入っていることがよくあります。「この日付は契約待ちで動く」「この数値は見込み」といった補足は、表の数字だけでは分からない前提を教えてくれます。ただしコメントは吹き出しの中に隠れていて、読むにはセルを 1 つずつ開く必要がありますし、まとめてコピーするのも一苦労です。 本記事では、Spire.XLS for Python を使って、Excel のコメントから本文・投稿者・セル位置を取り出して一覧にする方法と、画像が貼られたコメントから画像ファイルだけを取り出す方法を紹介します。抽出したテキストはそのままレビュー資料や引き継ぎメモの下書きに使えます。 クイックナビゲーション コメントから取り出せる 4 つの情報 どのセルにどんなメモがあるかを一覧にする 一覧をテキストファイルに残す 画像付きコメントから画像を取り出す 抽出したデータの使い方 まとめ よくある質問 コメントから取り出せる 4 つの情報 セルに付いたコメントは CellRange.Comment から取得でき、次の 4 つを取り出せます。 取り出せるもの プロパティ 取り出し例 本文 Comment.Text 「外部ベンダーの契約待ちで1週間後ろにずれた。」 投稿者 Comment.Author 「PMO」 セル位置 Comment.Row / Comment.Column → Range[行, 列].RangeAddressLocal 「C4」 埋め込まれた画像 Comment.Fill.Picture PNG などの画像データ 動作確認は Spire.XLS for Python 16.8.2(plum-dispatch v1.7.4)で行っています。次のコマンドでインストールできます。 pip install Spire.XLS スクリプトの先頭では、Spire.XLS のモジュールを読み込みます。 from spire.xls import * from spire.xls.common import * サンプルは、新製品プロジェクトの進捗を 1 シートにまとめた Comments.xlsx です。A1:E1 が見出し、A2:E6 に 5 つのタスクが並び、4 つのセルに補足メモが付いています。B3 には担当交代の連絡、C4 には日程の変更理由、D5 にはテスト工程の前提、E6 には進捗値の見込みが入っています。 どのセルにどんなメモがあるかを一覧にする まずは、シート内のコメントを順番に読み出して、セル位置と投稿者を添えて表示してみます。Worksheet.Comments はシートごとのコメントをまとめたコレクションで、for 文でそのまま反復できます。 from spire.xls import * from spire.xls.common import * # ブックを読み込み、最初のワークシートを取得する workbook = Workbook() workbook.LoadFromFile("Comments.xlsx") worksheet = workbook.Worksheets[0] # コメントを 1 件ずつ読み出す for comment in worksheet.Comments: address = worksheet.Range[comment.Row, comment.Column].RangeAddressLocal print(f"{address}({comment.Author})") print(comment.Text) print() workbook.Dispose() 実行すると、コメントのあるセルと内容が順に表示されます。 Comment.Row と Comment.Column は 1 始まりの行番号・列番号です。Range[行, 列].RangeAddressLocal を通すと「C4」のような A1 形式のセル名になるので、表のどこを指しているメモなのかが分かりやすくなります。件数だけを確認したいときは Worksheet.Comments.Count を使います。 一覧をテキストファイルに残す 画面に出すだけでは後から見返しにくいので、同じ内容をテキストファイルに書き出します。抽出した文字列をリストにためて、最後にまとめて保存する形にすると、出力の体裁も整えやすくなります。 from spire.xls import * from spire.xls.common import * # ブックとワークシートを用意する workbook = Workbook() workbook.LoadFromFile("Comments.xlsx") worksheet = workbook.Worksheets[0] # 出力する行を組み立てる lines = [] for comment in worksheet.Comments: address = worksheet.Range[comment.Row, comment.Column].RangeAddressLocal text = comment.Text.strip() if not text: continue lines.append(f"{address}({comment.Author})") lines.append(text) lines.append("") # テキストファイルに保存する with open("comments.txt", "w", encoding="utf-8") as file: file.write("n".join(lines)) workbook.Dispose() 実行すると、comments.txt に同じ内容が保存されます。1 件につき「セル番地(投稿者)」「本文」「空行」の 3 行で並びます。 Comment.Text は改行をそのまま含むため、複数行のメモも元の形で残ります。画像だけが貼られたコメントは本文が空になるので、strip() で除外しておくと、テキストの一覧が空行だらけになりません。encoding="utf-8" を指定して保存すれば、日本語もそのまま開けます。 図の上段が元のシート、下段が書き出したテキストです。セル番地と投稿者が、吹き出しの位置とそのまま対応しているのが分かります。 コメントを新しく付ける手順は、Python:Excelファイルにコメントを追加する方法 で解説しています。 画像付きコメントから画像を取り出す コメントには、文字ではなく画像が貼られていることもあります。図やグラフの写しをメモ代わりにしているケースです。画像は Comment.Fill.Picture から取り出せます。 サンプルは、月次売上の表にグラフ画像を貼ったコメントを持つ ImageComment.xlsx です。B2 のコメントに 1〜3 月の売上推移の画像、B4 のコメントにテキストのメモが入っています。 コメントに画像が入っているかどうかは、Comment.Fill.FillType で判定できます。ShapeFillType.Picture なら画像が入っているので、Comment.Fill.Picture を取り出して Save() でファイルに保存します。 from spire.xls import * from spire.xls.common import * # ブックとワークシートを用意する workbook = Workbook() workbook.LoadFromFile("ImageComment.xlsx") worksheet = workbook.Worksheets[0] # 画像が入ったコメントを探して保存する for comment in worksheet.Comments: if comment.Fill.FillType == ShapeFillType.Picture: picture = comment.Fill.Picture picture.Save("CommentImage/Comment.png") workbook.Dispose() 図の上段が B2 のコメント、下段が保存した CommentImage/Comment.png です。コメントの中で縮小表示されていたグラフが、元の大きさの画像として取り出せています。 保存先のフォルダは、スクリプトを実行する前に用意しておきます。ファイル名の拡張子は、コメントに貼られている画像の形式に合わせてください。PNG の画像なら .png、JPEG なら .jpg です。画像が複数あるときは、ループのたびに Comment1.png、Comment2.png のように連番を付けると取り違えません。 saved = 0 for comment in worksheet.Comments: if comment.Fill.FillType == ShapeFillType.Picture: saved += 1 comment.Fill.Picture.Save(f"CommentImage/Comment{saved}.png") 抽出したデータの使い方 取り出したテキストと画像は、そのまま作業に回せます。 場面 使い方 引き継ぎ セルごとのメモを 1 枚のテキストにまとめ、申し送り事項の抜け漏れを確認する レビュー 数値の前提や例外がコメントに書かれているブックで、根拠を本文と並べて読む 資料化 グラフ画像のコメントを取り出し、報告資料の素材として再利用する コメントは「表の外側にある注記」なので、抽出しておくと差分の確認もしやすくなります。更新前後で 2 回抽出して見比べれば、メモの書き換えや削除に気づけます。 まとめ コメントの抽出は、4 つのプロパティを押さえれば足ります。本文は Comment.Text、投稿者は Comment.Author、位置は Comment.Row と Comment.Column から A1 形式に変換、画像は Comment.Fill.Picture です。テキストはリストにためて utf-8 で書き出し、画像は FillType で見分けて Save() する、という流れでまとめて処理できます。 セルに残されたメモを一度テキストにしておくと、引き継ぎやレビューのたびに Excel を開いて吹き出しを 1 つずつ確認する必要がなくなります。定期的に抽出するスクリプトにしておけば、ブックの棚卸しも同じ手順で回せます。 Spire.XLS for Python の全機能を評価したい場合は、30 日間の無料ライセンスを申請できます。なお無償の試用版では、保存したファイルに評価用の警告シートが追加されます。ライセンスを適用するとこれも出力されなくなります。 よくある質問 シートが複数あるブックからまとめて抽出できますか? Workbook.Worksheets を繰り返し、シートごとに Comments を読み出します。シート名を添えておくと、どのシートのメモかが分かりやすくなります。 for sheet in workbook.Worksheets: for comment in sheet.Comments: address = sheet.Range[comment.Row, comment.Column].RangeAddressLocal print(f"{sheet.Name}!{address}", comment.Text) メモの改行はそのまま残りますか? 残ります。Comment.Text はセル内の改行を n として返すため、テキストファイルに書き出しても複数行のまま読めます。 画像だけのコメントはテキスト抽出でどうなりますか? 本文が空なので、strip() で除外する形にしておくと一覧が読みやすくなります。画像自体は Comment.Fill.Picture から取り出せます。 取り出した画像の形式は変わりますか? コメントに貼られた画像がそのまま保存されます。PNG の画像なら PNG のままなので、保存するファイル名の拡張子を元の形式に合わせてください。 セル位置を「Sheet1!C4」の形で出せますか? RangeAddressLocal はシート名を含まない「C4」を返します。シート名も付けたいときは、上の複数シートの例のように sheet.Name と組み合わせて文字列を作ります。