エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

PowerPointファイルからのテキスト抽出

こんにちは!エンジニアリンググループの鹿山です。今年の4月から新卒で入社し、AI・機械学習チームでレコメンドシステムの開発・運用を行なっています。

もっぱら西場さんが日々改良を加えている luigi をラップしたモジュールを用いて開発をしているのですが、処理フローがわかりやすくなるため 結果の共有や互いのコードのレビューがしやすくなり、日々の業務が効率化されています。

(luigi についての記事はこちら)

最近、社内での業務プロセス改善の一環で、pptx形式のPowerPointファイルからテキスト抽出を自動化し解析を行いました。 そこで今回は pptxファイルからテキストを抽出する方法について共有させていただきます。

目次

例えば下記のようなスライドを持つ pptx ファイルからテキストを抽出することを考えます。

f:id:kayamin:20181106203959p:plain

1. pptx ファイルから xml ファイルを抽出

pptx ファイルは スライドのコンテンツを格納した OpenXML 形式の xml ファイルを圧縮したものになっています。 ファイルの拡張子を .pptx から .zip に変更し、 解凍することで xmlファイルの中身を見ることができます。

解凍した pptx ファイルの中身

pptx_file
├── [Content_Types].xml
├── _rels
├── customXml
├── docProps
└── ppt

この内、ppt ディレクトリにスライドのコンテンツが格納されています.

pptx_file
├── [Content_Types].xml
├── _rels
├── customXml
├── docProps
└── ppt
    ├── _rels
    ├── commentAuthors.xml
    ├── handoutMasters
    ├── media
    ├── notesMasters
    ├── notesSlides
    ├── presProps.xml
    ├── presentation.xml
    ├── slideLayouts
    ├── slideMasters
    ├── slides
    ├── tableStyles.xml
    ├── theme
    └── viewProps.xml

ppt ディレクトリ以下には、各スライドやそれらに含まれる画像、スライドマスタ等が存在します。

今回抽出する各スライドのテキストは、slidesslideMastersslide_Layouts 以下の xml ファイルに記載されています。

また _rels以下の ~.xml.relsファイルは ~.xmlファイル に紐づけられている他の xmlファイル、画像ファイルのパス等が記載されています。(例えば各スライドに適用されているレイアウト xml ファイルのパス)

slides
├── _rels
│   └── slide1.xml.rels
└── slide1.xml

slideMasters
├── _rels
│   └── slideMaster1.xml.rels
└── slideMaster1.xml

slideLayouts
├── _rels
│   ├── slideLayout1.xml.rels
│   └── slideLayout2.xml.rels
├── slideLayout1.xml
└── slideLayout2.xml

2. スライドの xml ファイルからテキストを抽出

slides 以下の xml ファイルには pptxファイルの各スライドで定義されたオブジェクトの情報が保存されています。 スライドに含まれるテキストボックス・表・図形・画像等様々なオブジェクトはいくつかのタグに分類され、ツリー構造で管理されています.

この内、テキストボックスを定義する spタグと表を定義するgraphicFrameタグを検索し、テキストを抽出します.

テキストボックスはsp タグで定義され、spタグ以下の tタグにテキストが格納されています。

slide1.xml でのテキストボックス記述例

<p:sp>
    ~
    <p:txBody>
    ~
                <a:t>サンプルスライド</a:t>
    ~       
    </p:txBody>
</p:sp>

表はgraphicFrame タグで定義されます。graphicFrame タグ以下では表の各セルはtr(行)、 tc(列) タグで区切られており、各セル内のt タグにテキストが格納されています。

slide1.xml での表記述例

<p:graphicFrame>
    ~
    <a:graphic>
        <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/table">
            <a:tbl>
                <a:tr h="1772084">
                    <a:tc>
                        <a:txBody>
                            ~
                                    <a:t>左上</a:t>
                            ~
                        </a:txBody>
                    </a:tc>
                    <a:tc>
                        <a:txBody>
                            ~
                                    <a:t>右上</a:t>
                            ~
                        </a:txBody>
                    </a:tc>
                </a:tr>
                <a:tr h="1772084">
                    <a:tc>
                        <a:txBody>
                            ~
                                    <a:t>左下</a:t>
                            ~
                        </a:txBody>
                        <a:tcPr anchor="ctr"/>
                    </a:tc>
                    <a:tc>
                        <a:txBody>
                            ~
                                    <a:t>右下</a:t>
                            ~
                        </a:txBody>
                        <a:tcPr anchor="ctr"/>
                    </a:tc>
                </a:tr>
            </a:tbl>
        </a:graphicData>
    </a:graphic>
</p:graphicFrame>

このようにして、テキストボックス、表 それぞれに対応するtタグからテキストを取得することで、スライド内のテキストを抽出することができます。

3. スライドマスタの xml ファイルからテキストを抽出

スライド内にテキストが存在するのに、対応する slide.xml に該当テキストが含まれていない場合があります。サンプルの場合、左下の「M3 Tech Blog」 がそれに当たります。 そういったテキストは、スライドに適用されているレイアウト、スライドマスタ側で定義されています。 適用されているレイアウト、スライドマスタの xml ファイルは xml.rels ファイルを辿ることで確認できます。

例えば、 slides/slide1.xml に適用されているレイアウトは slides/_rels/slide1.xml.relsに下記のように記されており、slideLayouts/slideLayout2.xmlが適用されていることがわかります。

slides/_rels/slide1.xml.rels

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide" Target="../notesSlides/notesSlide1.xml"/>
    <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/slideLayout2.xml"/>
</Relationships>

レイアウトに適用されているスライドマスタも同様にして確認することができます。

レイアウト、スライドマスタのxml は各スライドの xml 同様の構造をしています。

ユーザーが追加したテキストボックスの場合spタグ以下に userDraw属性をもつタグ<p:nvPr userDrawn="1"/>が存在します。このタグが存在するオブジェクトからのみテキストを抽出することで、スライドマスタ側には存在するが、実際のスライドには表示されないテキスト(マスターテキストの書式設定等)を除くことができます。

slideMaster1.xml 内のユーザー追加箇所例

<p:sp>
    <p:nvSpPr>
        <p:cNvPr id="1" name="テキスト ボックス 1"/>
        <p:cNvSpPr txBox="1"/>
        <p:nvPr userDrawn="1"/>
    </p:nvSpPr>
    ~
    <p:txBody>
    ~
                <a:t>M3 Tech Blog</a:t>
    ~       
    </p:txBody>
</p:sp>

まとめ

多くのビジネスシーンで使われているPowerPointのスライドからテキストを抽出する方法についてご紹介させていただきました。 テキストを抽出するだけではなくxmlファイル内のオブジェクトのサイズ・配置情報を書き換える、配置変更等の定型作業を自動化することも可能です。

また、一からのスライド作成をスクリプトで定義し自動化するための python-pptx というパッケージも開発されています。 日々の定型作業をハックすることで、やりたい仕事に時間を充てていきましょう!

We are hiring !

自身の業務はもちろん、医師・製薬企業の方々の業務を効率化し、不必要な医療コストを1円でも減らしたい! そんな思いを持って一緒に働いてくれるエンジニアを募集しています。

M3 Tech Blog を読まれて興味を持った方はぜひ下記リンクよりご応募ください!また、Tech Talkの参加、登壇もお待ちしていますのでお気軽にご連絡ください!

jobs.m3.com