【自動化】PDF内の表をPythonで抜き出す

## PDFは扱いにくい

PDFファイルをPythonで扱うのは大変です。


表がPDFの中に埋め込まれているケースも割とあります。

例えば

[平成30年 全衛連ストレスチェックサービス実施結果報告書](http://www.zeneiren.or.jp/cgi-bin/pdfdata/20190925114437.pdf)の中にはたくさんの表データが埋め込まれています。

例えばファイルの40ページの【表14 業種別高ストレス者の割合】を抜き出したいと思ったとします。

この表を選択して、Excelにコピペしてみましょう。
![pdf_table_copy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634673/bba3b6a4-05f7-b6f1-8a1a-2b6721b4d118.png)

コピーして、Excelに貼り付けます。

![pdf_copy2excel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634673/dba3a21c-dac1-d29d-ec28-325e2da156fc.png)


おや？うまくいかないですね。
1つのセルの中に、全部のデータが羅列されてしまっています。

実はPythonを使ってこのPDF中の表を比較的簡単にcsvやExcelに変換することができます。

## PythonでPDFの表をcsvに

PythonでPDF内の表(テーブル)をcsvやexcelに変換する手順は2ステップです。

ステップ1. PDFから表をpandasのDataFrameとして抜き出す
ステップ2. DataFrameをcsvやexcelとして書き込む

順に見ていきましょう。

### ステップ1. PDFから表をpandasのDataFrameとして抜き出す

pdfの表をDataFrameとして抜き出すために、**tabula**というモジュールを使います。

tabulaはインストールされていない方も多いと思いますので
`pip install tabula-py`
でインストールします。

さらにこのtabulaはJavaで動きますので、Javaのインストールも必要です。

tabulaの準備ができたところで、pandasとtabulaをimportしておきます。

```python:python

import pandas as pd
import tabula
```

PDFから表を抜き出すには、
`tabula.read_pdf("xxx.pdf", lattice=True, pages='xxxx')`
という関数を使います。

※補足：`tabula.read_pdf("xxx.pdf", lattice=True, pages='xxxx')`でエラーになる場合もあるようです。その場合は、`tabula.io.read_pdf("xxx.pdf", lattice=True, pages='xxxx')`としてみてください。

- `"xxx.pdf"`には、読み込みたいPDFファイルのパスを書きます。
- `lattice=True`はテーブルの罫線でセルを判定するためのオプションです。
抜き出したい表が罫線で区切られているならlattice=Trueを指定しましょう。
- `pages`は読み込みたいページを指定します。
 - 40ページ目だけを読み込むなら`pages='40'`のように指定します。
 - 40～45ページを読み込むなら`pages='40-45'`のように指定します。
 - すべてのページを読み込むなら`pages='all'`でOKです。

- 関数の戻りとして`pandas.DataFrameのリスト`が返ります。複数の表があった場合には、このリストをfor文で順に取り出せばよいです。

では、先ほどの『平成30年 全衛連ストレスチェックサービス実施結果報告書』の40ページの表を読み込んでみましょう。

```python:python

# lattice=Trueでテーブルの軸線でセルを判定
dfs = tabula.read_pdf("平成30年 全衛連ストレスチェックサービス実施結果報告書.pdf", lattice=True, pages = '40')

for df in dfs:
    display(df)

```
![tabula_df.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634673/af24f27d-e0db-2f6b-a513-00f01a25a0d4.png)

列名がセル内で改行されていたために`\r`が入ってしまっていて変ですが、表の中身はうまく取り出せていますね。

一応、列名もきちんと直しておきましょう。
`df.rename(columns={'元の列名': '変更後の列名'})`で列名を変更できます。
複数の列名を変更するときは`'元の列名': '変更後の列名'`をコンマで区切ってつなげていけばOKです。


```python:python
df = df.rename(columns={'高ストレ\rス者数': '高ストレス者数', '高ストレス\r者の割合': '高ストレス者の割合'})
```

### ステップ2. DataFrameをcsvやexcelとして書き込む

pandasには元々DataFrameをcsvやExcelとして書き込む機能がついています。

csvとして保存：`df.to_csv("ファイル名.csv", index=None)`
Excelとして保存：`df.to_excel("ファイル名.xlsx", index=None)`

※`index=None`はDataFrameのindexを書き込まないようにするためのオプション

## まとめ

最後に今回のコードをまとめて記載しておきます。

```python:pyhon
import pandas as pd
import tabula
 
# lattice=Trueでテーブルの軸線でセルを判定
dfs = tabula.read_pdf("平成30年 全衛連ストレスチェックサービス実施結果報告書.pdf", lattice=True, pages = '40')

# PDFの表をちゃんと取得できているか確認
for df in dfs:
    display(df)

# csv/Excelとして保存(今回はdfs[0]のみ)
df = dfs[0].rename(columns={'高ストレ\rス者数': '高ストレス者数', '高ストレス\r者の割合': '高ストレス者の割合'})
df.to_csv("PDFの表.csv", index=None) # csv
df.to_excel("PDFの表.xlsx", index=None) # Excel
```

## 画像扱いのPDFファイルから表を抜き出すには
紙の文書や書籍をスキャンして電子化したPDFの場合、テキストがOCR化されておらず、PDFファイル内の表が画像扱いのままのものもあると思います。

その場合は、下記の記事で紹介した方法をお試しください。

[画像ファイルの表をOneDrive&Pythonで抜き出す](https://qiita.com/konitech913/items/10b5e1477df991055e0c)

## 参考
私の書いた他の自動化シリーズはこちらです。ご興味があればどうぞ！

【自動化】PythonでWordの文書を読み取る
https://qiita.com/konitech913/items/c30236bdf47775535e2f

【自動化】Pythonコードをexeファイル化する
https://qiita.com/konitech913/items/6259f13e057bc25ebc23

【自動化】PythonでOutlookメールを送信する
https://qiita.com/konitech913/items/51867dbe24a2a4272bb6

【自動化】PythonでOutlookのメールを読み込む
https://qiita.com/konitech913/items/8a285522b0c118d5f905

【自動化】Pythonでメール(msgファイル)を読み込む
https://qiita.com/konitech913/items/fa0cf66aad27d16258c0

【自動化】Pythonでクリップボードを操作してExcelに表を貼り付ける
https://qiita.com/konitech913/items/83975332e395a387eace