読者です 読者をやめる 読者になる 読者になる

HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

Apache TikaのPDFファイルテキスト抽出で遊んでみる

ということで、サイトのParser APIを追いかけてコードを組み立ててみたメモ。

環境は、CentOS 7(VM)上のOpenJDK 1.8.0_111。

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

以下のようなPDFファイルを使う。

f:id:hhelibex:20170227225332p:plain

PDFファイルからのテキスト抽出にはorg.apache.tika.parser.pdf.PDFParserクラスを使う。

最低限のコードは以下のような感じ。

import java.io.*;
import java.util.*;

import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

public class ParserSample {
    public static void main(String[] args) {
        Parser parser = new PDFParser();

        for (String arg : args) {
            ContentHandler handler = new BodyContentHandler();
            try (InputStream in = new FileInputStream(arg)) {
                Metadata metadata = new Metadata();
                ParseContext context = new ParseContext();
                try {
                    parser.parse(in, handler, metadata, context);
                } catch (TikaException | IOException | SAXException e) {
                    e.printStackTrace();
                }

                List<String> list = new ArrayList<>(Arrays.asList(handler.toString().trim().split("\\s")));
                List<String> names = new ArrayList<>(Arrays.asList(metadata.names()));
                Collections.sort(names);
                for (String name : names) {
                    System.out.printf("%-48s = %s%n", name, metadata.get(name));
                }
                System.out.println();
                System.out.println(list);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

これを実行すると、出力として以下のようなものが得られる。

Author                                           = hhelibex
Content-Type                                     = application/pdf
Creation-Date                                    = 2017-02-27T11:04:23Z
Last-Modified                                    = 2017-02-27T11:04:23Z
Last-Save-Date                                   = 2017-02-27T11:04:23Z
access_permission:assemble_document              = true
access_permission:can_modify                     = true
access_permission:can_print                      = true
access_permission:can_print_degraded             = true
access_permission:extract_content                = true
access_permission:extract_for_accessibility      = true
access_permission:fill_in_form                   = true
access_permission:modify_annotations             = true
created                                          = Mon Feb 27 20:04:23 JST 2017
creator                                          = hhelibex
date                                             = 2017-02-27T11:04:23Z
dc:creator                                       = hhelibex
dc:format                                        = application/pdf; version=1.4
dc:title                                         = Apache Tikaのテスト用
dcterms:created                                  = 2017-02-27T11:04:23Z
dcterms:modified                                 = 2017-02-27T11:04:23Z
meta:author                                      = hhelibex
meta:creation-date                               = 2017-02-27T11:04:23Z
meta:save-date                                   = 2017-02-27T11:04:23Z
modified                                         = 2017-02-27T11:04:23Z
pdf:PDFVersion                                   = 1.4
pdf:docinfo:created                              = 2017-02-27T11:04:23Z
pdf:docinfo:creator                              = hhelibex
pdf:docinfo:creator_tool                         = MicrosoftR Office ExcelR 2007
pdf:docinfo:modified                             = 2017-02-27T11:04:23Z
pdf:docinfo:producer                             = MicrosoftR Office ExcelR 2007
pdf:docinfo:title                                = Apache Tikaのテスト用
pdf:encrypted                                    = false
pdfa:PDFVersion                                  = A-1b
pdfaid:conformance                               = B
pdfaid:part                                      = 1
producer                                         = MicrosoftR Office ExcelR 2007
title                                            = Apache Tikaのテスト用
xmp:CreatorTool                                  = MicrosoftR Office ExcelR 2007
xmpMM:DocumentID                                 = uuid:72AB1A36-B534-4714-90E1-7640E90E7083
xmpTPg:NPages                                    = 1

[ヘッダ1, ヘッダ2, あ, ア, 阿, い, イ, 伊, う, ウ, 宇, え, エ, 江, お, オ, 尾]

PDFファイルだと「pdf:」で始まる名前を使ってMetadataから情報を取ればよい感じか。

コンテンツの方は、handler.toString()で得られる文字列が抽出結果になっているので、あとは煮るなり焼くなりすればいい。

汎用的にしてみる

実は、上記のことはorg.apache.tika.parser.AutoDetectParserを使っても実現できる。

ファイルタイプの検出に少し時間が掛かるのだが、PDFファイルだけではなくほかのファイルのテキストも同じコードで抽出したいという場合には有用だろう。

コードはほぼ同じになるが、以下のような感じ。

import java.io.*;
import java.util.*;

import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
//import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

public class ParserSample {
    public static void main(String[] args) {
//      Parser parser = new PDFParser();
        Parser parser = new AutoDetectParser();

        for (String arg : args) {
            ContentHandler handler = new BodyContentHandler();
            try (InputStream in = new FileInputStream(arg)) {
                Metadata metadata = new Metadata();
                ParseContext context = new ParseContext();
                try {
                    parser.parse(in, handler, metadata, context);
                } catch (TikaException | IOException | SAXException e) {
                    e.printStackTrace();
                }

                List<String> list = new ArrayList<>(Arrays.asList(handler.toString().trim().split("\\s")));
                List<String> names = new ArrayList<>(Arrays.asList(metadata.names()));
                Collections.sort(names);
                for (String name : names) {
                    System.out.printf("%-48s = %s%n", name, metadata.get(name));
                }
                System.out.println();
                System.out.println(list);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

試しに、先に使ったPDFファイルの元であるExcelファイルを食わせてみる。

Application-Name                                 = Microsoft Excel
Author                                           = hhelibex
Company                                          = 
Content-Type                                     = application/vnd.ms-excel
Creation-Date                                    = 2017-02-27T10:23:34Z
Last-Author                                      = hhelibex
Last-Modified                                    = 2017-02-27T10:31:13Z
Last-Save-Date                                   = 2017-02-27T10:31:13Z
X-Parsed-By                                      = org.apache.tika.parser.DefaultParser
creator                                          = hhelibex
date                                             = 2017-02-27T10:31:13Z
dc:creator                                       = hhelibex
dc:title                                         = Apache Tikaのテスト用
dcterms:created                                  = 2017-02-27T10:23:34Z
dcterms:modified                                 = 2017-02-27T10:31:13Z
extended-properties:Application                  = Microsoft Excel
extended-properties:Company                      = 
meta:author                                      = hhelibex
meta:creation-date                               = 2017-02-27T10:23:34Z
meta:last-author                                 = hhelibex
meta:save-date                                   = 2017-02-27T10:31:13Z
modified                                         = 2017-02-27T10:31:13Z
title                                            = Apache Tikaのテスト用

[Sheet1, , , ヘッダ1, ヘッダ2, , あ, ア, 阿, , い, イ, 伊, , う, ウ, 宇, , え, エ, 江, , お, オ, 尾, , , Sheet2, , , , , Sheet3]

PDFファイルの場合も同様だが、AutoDetectParserを使うと「X-Parsed-By」がMetadataに追加されている。