Excelファイルから文字列を取り出す

神エクセルから文字列だけを頂戴します。

Excelから文字列だけを取り出したい!という需要はあまりないと思いますが、画像を取り出すツール(こちら)がありますので、どうせならと作ってみました。

原理は画像取り出しツールと基本同じですが、文字列はXMLファイルに埋め込まれており単純にファイルをごそっと抜き取るだけでは使い物になりません。XMLパーサーで必要な部分だけを抜き出して、それをファイルに書き出すという処理が必要になります。

なお、取り出せるのは文字列だけで計算式の結果は対象外です。よって対神エクセル専用ツールとお考えください。

スクリプトはPythonでソースコードは次の通りです。

import xml.etree.ElementTree as et
import sys
import os
import zipfile

file = sys.argv[1]

with zipfile.ZipFile(file) as xlsx:
    ns = {
        'xlsx': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
        'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'
    }
    str_root = et.fromstring(xlsx.read('xl/sharedStrings.xml'))
    values = str_root.findall('xlsx:si/xlsx:t', ns) + str_root.findall('xlsx:si/xlsx:r/xlsx:t', ns)
    os.makedirs(os.path.join(os.path.dirname(__file__), 'xl'), exist_ok=True)

    for draw in xlsx.namelist():
        if 'xl/drawings' in draw:
            draw_root = et.fromstring(xlsx.read(draw))
            values += draw_root.findall('.//a:t', ns)

    with open(os.path.join('xl', 'strings.txt'), 'w') as result:
        for value in values:
            try:
                result.write(value.text + '\n')
            except UnicodeEncodeError:
                pass

解説

神エクセル撲滅協会理事(自称)である私のPC上には神エクセルの存在が許されていません。そこでサンプルとなるファイルを我らがさいたま市のWEBサイトで探してみたら、やっぱりありました。

別にさいたま市がダメなのではありません。仕事がら経済産業省とかの書式を使いますが、これと大差ないです。これが国家の中枢の仕事なのかと愕然となります。もはや国家ぐるみです。まぁ、使えるものをどう使おうが自由だと言われたら何も反論できないんですけどね。

サンプルデータはこちらのページの「省エネ対策詳細表」です。

excel-str-sample.png

列表示を見るだけで、ほとばしる神感を感じていただけるかと思います。

さて、画像ツールのページには書いてありますが、Excelファイルの実体はXMLと付帯データをZIP圧縮したものです。Excelシートの文字データはその中の【xl/sharedStrings.xml】に記述されています。ここに

<si><t>文字列</t></si>
または
<si><r><t>文字列</t></r></si>

という構造で文字列が格納されています。二つの違いはよくわかりません。rタグの中身を見た感じ、フォントを変更するなど、デフォルトと違うスタイルを文字に指定すると<r>配下になると思われます。

ExcelのXMLについては詳しい仕様書が公開されているのですが、5000ページ以上あるPDFで全部英語で読む気力も能力もありません。

サンプルファイルのXMLはこんな感じです。

excel-str-sample2.png

よって不確定要素が多く、あまりスマートではないですが、パーサーでこの2パターンを引っ張ってきます。XMLパーサーはPython標準のElementTreeを使用します。

nsはネームスペースとPrefixとの対応を定義した辞書で、パーサーに渡しておく必要があります。

ns = {
    'xlsx': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
    'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'
}
str_root = et.fromstring(xlsx.read('xl/sharedStrings.xml'))
values = str_root.findall('xlsx:si/xlsx:t', ns) + str_root.findall('xlsx:si/xlsx:r/xlsx:t', ns)

もう一つExcelシートに文字を表示する手法として、テキストボックスがあります。テキストボックスの文字列情報はsharedStrings.xmlには記述されません。

では、どこに記述されているかというと、サンプルファイルの場合【xl/drowings/】配下に【drawing1.xml】という名前でありました。このdrawing1.xmlというファイルがテキストボックスを増やすと2、3と増えていきそうな気がしたので、試しに1つテキストボックスを追加してみたのですが、drawing1.xmlにその情報が追記されただけでした。

しかし思わせぶりなファイル名が気になるので、どのタイミングで増えても、何個存在してもいいように、forループで総当たりでパースすることにします。

テキストボックスの文字データはXMLに
<a:t>文字列</a:t>
のように格納されています。

for draw in xlsx.namelist():
    if 'xl/drawings' in draw:
        draw_root = et.fromstring(xlsx.read(draw))
        values += draw_root.findall('.//a:t', ns)

最後にパーサーが収集した文字列をまとめてテキストファイルへ書き出します。画像ツールにならって【xl/strings.txt】という構成で出力します。エラーハンドラはPythonが処理できない特殊文字があった場合に処理が中断されてしまうのを防いでいます。処理できない文字を含むデータは書き出されません。

使用方法

拡張子xlsのファイルは処理できません。xlsxに保存しなおすか、あきらめてください。

1.アプリを入手して適当なフォルダへ配置してください。

excel-str-ex1.png


2.アプリへ対象のExcelファイルをドラッグ&ドロップします。コマンドプロンプトの黒い画面が一瞬見えると思いますが、こいつの仕業です。ウイルスではありません。ご安心ください。

excel-str-ex2.png


3.Excelファイルがあるフォルダへ【xl】というフォルダができます。

excel-str-ex3.png


4.【xl】フォルダの中の strings.txtファイルに文字データあります。
Excelでの見た目通りの順序で記録されません(元になるXMLがおそらく入力した順に記録されているためです)。

excel-str-ex4.png

サンプルファイルの実行結果は正確に検証していませんが、テキストデータの8割くらいは抽出されている感じです。しかし今回のサンプルで一番重要と思われる省エネ対策に対する助成金一覧表がまさかの画像データだったので取れませんでした。全体の情報量からすると半分程度になってますね。

神エクセル侮りがたし。

本気でやるなら手軽さはガクンと落ちますが、素直にExcel-VBAでセルデータを書き出す処理を作った方がいい気がします。気が向いたらやってみたいと思います。

アプリを入手する

アプリで使用しているモジュールElementTreeは悪意を持って作成されたデータに対して安全ではありません。信頼できないデータをパースする場合はご注意ください。詳しくはPythonリファレンスページをご確認ください。

利用上のご注意
  • ダウンロードしたファイルを利用したことにより生じた結果については、利用者ご自身に責任を負っていただきます。
  • ご利用前に使用方法をご確認ください。
  • 当方は成果物の正確性について最善を尽くしますが保証はいたしません。
  • Windows10-64bit Excel2016-32bit環境でのみ動作確認済み。

excel_string_extraction.exe

DOWN LOADボタンが押下された時点で注意事項に同意したものとみなします。

ソースコードから実行する

得体の知れないサイトで拾った実行ファイルなんて使えねーよというかたは、ソースコードから実行できます。ダウンロードボタンからソースコード(.pyファイル)を入手してください。

対象のExcelブックをコマンドラインから引数でわたすか.pyファイルにドラッグ&ドロップすると実行されます。詳細は次の記事を参考にしてください。

ソースコードをダウンロード

excel_string_extraction.py

DOWN LOADボタンが押下された時点で注意事項に同意したものとみなします。

参考サイト

ElementTreeの使い方はこちらのサイトで勉強しました。

おわり。

related pages
Pythonにドラッグ&ドロップでファイルをわたす超簡単な方法
ファイルをドラッグ&ドロップで処理させる一番簡単なやり方。

PythonとExcelをハイブリッドに駆使するという当サイトのコンセプト上、ExcelブックをPythonスクリプトにわたさなければならない機会が多々あります。順当にやるならパスを引数にしてわたす方法ですが、もっと超絶簡単にできるんです。

Read More ...
Excelファイルから画像を取り出す
神エクセルから画像だけを頂戴します。

Excelファイルは拡張子をむりやり変更してZIPファイルとして展開し、画像が保存されているフォルダを取り出すことで画像だけを手に入れられます。しかし!もっとスマートかつスタイリッシュに取り出したい!ということで、ドラッグ&ドロップするだけで画像を取り出すアプリを完成させました。

Read More ...
NCMBにPythonでファイルをアップする
NCMBのREST-APIをPythonから利用します。

NCMBはmBaaSです。スマホアプリのバックエンドとしての機能は当然そろっていますが、REST-APIが用意されており、スマホからに限らずHTTPでアクセスできればデータを出し入れできます。すなわちPythonからだろうとVBAからだろうと利用できます。

Read More ...
この記事の
作成日

2019-10-19

更新日

2020-07-12

ページ内検索
目次
WEB MASTER
さいた
神エクセル撲滅協会理事(自称)
さいたま市民 埼玉こそ地上の楽園