Tabulaを使ってPDFからテーブルを抽出する

目次

  1. 背景
  2. Tabulaとは?
  3. GUIでの実行
    1. Tabulaのダウンロード
    2. Tabulaの利用法
    3. Templateの作成
  4. コマンドラインからの実行(tabula-java)
  5. Javaライブラリ(tabula-java)の利用
    1. Gradle
    2. 実装
  6. まとめ
  7. 関連記事
  8. おすすめ書籍

背景

こんにちは。 かりんとうマニア(@karintozuki)です。

皆様、業務自動化してますか。(唐突
ありがちな業務としてPDFの読み取りがあるかと思います。
今日はPDFからテーブルの値を抽出できるTabulaというツールを紹介します。

Tabulaとは?

オープンソースのPDFからテーブルの値を抽出するソフトです。
値を抽出するといってもOCR(画像の読み取り)ではなく、
あくまでもテキストとして認識できるデータを対象としています。

このツールの良いところは、
色々な方法で実行が可能で、要件にそった利用方法を選ぶことができます。

Tabulaの実行方法には以下の三つの方法があります。

  • GUI
  • コマンドライン
  • Java、Pythonなど各種言語のAPI

サクッと一、二枚を抽出するならGUI、
大量のPDFを自動で読み取る際にはコマンドラインからの実行か
Javaなどのプログラミング言語から呼び出して使用できます。

この記事では三つの使用方法をサクッと紹介します。

GUIでの実行

GUIではブラウザから直感的にテーブルを読み取ることができます。

また、このGUIで作成したテンプレートを、
他の方法でも利用するので、とりあえずこのステップはできるようにしておいてください。

Tabulaのダウンロード

Tabulaのダウンロード方法です。

Windowsでの方法を書いてますが、
Macでも大差ないかと思います。

以下のリンクからZipをダウンロードします。
https://tabula.technology/

こちらを任意のフォルダに解凍するだけ
利用可能になります。

簡単ですね。

Tabulaの利用法

それでは先ほどダウンロードしたTabulaを実行します。

解凍したフォルダにあるtabula.exeを起動します。

コマンドプロンプトが立ち上がり、
しばらくするとブラウザが立ち上がります。

BrowseボタンからローカルにあるPDFファイルを指定します。

今回はテストとして以下のPDFを使ってみます。
https://github.com/tabulapdf/tabula-java/blob/master/src/test/resources/technology/tabula/20.pdf

importボタン押下でPDFを読み込みます。

読み込みが完了したらテーブルの範囲を指定します。

Preview & Export Extracted Dataボタン押下で抽出を実行します。

読み込めたみたいですね。
この状態からCSVやJSONに出力が可能です。

Templateの作成

これ以降の操作の下準備として、
今回取得したテーブルの範囲をテンプレートとして保存しておきます。
My Templateタブからダウンロードします。

こんな感じのJSONになっています。
これらのx1,x2,y1,y2をこの後の自動化のステップで使用していきます。

20.tabula-template.json
1
2
3
4
5
6
7
8
9
10
11
12
[
{
"page": 1,
"extraction_method": "guess",
"x1": 96.97123842315747,
"x2": 506.9289932449348,
"y1": 156.61725479125977,
"y2": 508.5410624694824,
"width": 409.9577548217773,
"height": 351.92380767822266
}
]

コマンドラインからの実行(tabula-java)

Tabulaはコマンドで実行することも可能です。

コマンドライン用のツールがあるので、
以下からjarファイルをダウンロードします。
https://github.com/tabulapdf/tabula-java/releases

適当な場所に配置して以下のコマンドを叩きます。
今回は簡単のためjarとPDFを同じ場所に配置しています。
また、ここで先ほど取得したjsonの座標情報を使用します。

1
2
3
java -jar ./jarのパス/tabula-0.9.0-jar-with-dependencies.jar -p all -a $y1,$x1,$y2,$x2 -o {アウトプットのファイルパス} {対象PDFのパス}
// コマンド例
java -jar tabula-1.0.4-jar-with-dependencies.jar -p all -a 156,96,508,506 -o output.csv 20.pdf

CSVが出力されます。

Javaライブラリ(tabula-java)の利用

tabulaはJavaのプログラムからも使用できます。
今回はGradleなどを使ったプロジェクトからライブラリを呼び出す場合を紹介します。

Gradle

repositoryにmavenCentralを追加します。

1
2
3
4
repositories {
jcenter()
mavenCentral()
}

dependenciesにtabulaを追加します。

1
2
3
4
5
6
7
8
9
dependencies {
// This dependency is used by the application.
implementation 'com.google.guava:guava:29.0-jre'

implementation 'technology.tabula:tabula:1.0.4'

// Use JUnit test framework
testImplementation 'junit:junit:4.13'
}

実装

以下の関数でpdfを抽出してCSVに出力できます。

App.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public void extractPdf(){
// PDFのパス
String path = "src\\main\\resources\\20.pdf";
// 出力先CSVのパス
String outputPath = "src\\main\\resources\\output.csv";

// PDF内のテーブルの座標
float top = 156f; // y1
float left = 96f; // x1
float bottom = 508f; // y2
float right = 506; // x2

try{
// PDFの取得
Page page = Utils.getAreaFromFirstPage(path, top, left, bottom, right);

// 読み込み用のクラス
BasicExtractionAlgorithm sea = new BasicExtractionAlgorithm();

// テーブルの抽出
List<Table> tables = (List<Table>) sea.extract(page);

StringBuilder sb = new StringBuilder();
(new CSVWriter()).write(sb, tables);

// CSVの書き込み
PrintWriter pw = new PrintWriter(new File(outputPath));
pw.write(sb.toString());
pw.close();

System.out.println(sb.toString());

}catch(IOException e ){
e.printStackTrace();
}

}

PDFを読み込むアルゴリズムには、
BasicExtractionAlgorithmと
SpreadsheetExtractionAlgorithmがあります。

BasicExtractionAlgorithmは余白をみる、
SpreadsheetExtractionAlgorithmは罫線をみることで

テーブルを認識しているそうです。

GUI版では以下の箇所に対応しているので、どちらのメソッドが良いかは
GUIで試してみると良いと思います。

この例ではCSVに出力したいので、CSVWriterクラスを利用していますが、
他にもJSONでの出力用にJSONWriterクラスなども用意されています。

また、PDFのテーブル範囲を指定する処理をUtilとして
別クラスに切り出しています。

こちらは本家のテスト用Utilクラスを参考にしました。
https://github.com/tabulapdf/tabula-java/blob/master/src/test/java/technology/tabula/UtilsForTesting.java

Utils.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package tablajava;

import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;

import technology.tabula.ObjectExtractor;
import technology.tabula.Page;

public class Utils {
public static Page getAreaFromFirstPage(String path, float top, float left, float bottom, float right) throws IOException {
return getAreaFromPage(path, 1, top, left, bottom, right);
}

public static Page getAreaFromPage(String path, int page, float top, float left, float bottom, float right) throws IOException {
return getPage(path, page).getArea(top, left, bottom, right);
}

public static Page getPage(String path, int pageNumber) throws IOException {
ObjectExtractor oe = null;
try {
PDDocument document = PDDocument
.load(new File(path));
oe = new ObjectExtractor(document);
Page page = oe.extract(pageNumber);
return page;
} finally {
if (oe != null)
oe.close();
}
}

}

実際に動かしてみたい人は以下のレポジトリに
ソースを格納したので、使ってみてください。
https://github.com/karintomania/JavaTabulaDemo

まとめ

今回はTabulaの使い方を紹介しました。

PDFを自動で読み取りたい要件があったときには
使ってみてください。

それじゃ今日はこの辺で。

関連記事

こちらの記事もおすすめです。

現役エンジニアが業務を自動化してきた手法7つ+αを紹介【Windows編】

おすすめ書籍