PythonでPDFの表からデータを取得する（PyMuPDF） 


# PDFの表からデータを取得したい

PDFの表からデータを取得したかったので、PyMuPDFを使ってデータを取得してみました。


### ドキュメント

https://pymupdf.readthedocs.io/en/latest/the-basics.html#extracting-tables-from-a-page


### pip install
```python
pip install PyMuPDF
```

### コード

ドキュメントのコードです。
ChatGPTにコメントを日本語にしてもらいました。

```python
import fitz
from pprint import pprint

# ドキュメントを開く
doc = fitz.open("test.pdf")

# ページを取得する
page = doc[0]

# ページ上にあるテーブルを検出する
tabs = page.find_tables()

# 検出されたテーブルの数を表示する
print(f"{len(tabs.tables)}個のテーブルが{page}上に見つかりました")

# 少なくとも1つのテーブルが見つかった場合
if tabs.tables:
    # 最初のテーブルの内容を表示する
    pprint(tabs[0].extract())
```


# 表からデータを取得する

### 1ページのPDFに1つの表があるとき
このようなPDFがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953149/491e5dc8-38e3-1d47-c2f3-cdacb2135d7f.png)

表（テーブル）のデータを取得します。
PDFのファイルは同一ディレクトリに保存します。

```python
from pprint import pprint

import fitz

# ドキュメントを開く
doc = fitz.open("recipe.pdf")

# ページを取得する
page = doc[0]

# ページ上にあるテーブルを検出する
tabs = page.find_tables()

# 検出されたテーブルの数を表示する
print(f"{len(tabs.tables)}個のテーブルが{page}上に見つかりました")

# 少なくとも1つのテーブルが見つかった場合
if tabs.tables:
    # 最初のテーブルの内容を表示する
    pprint(tabs[0].extract())
```

【出力結果】
リストとして出力されます。
```
1個のテーブルがpage 0 of recipe.pdf上に見つかりました
[['材料', '数量'],
 ['アボカド', '１個'],
 ['トマト', '適当（アボカドにあうくらい）'],
 ['大豆水煮缶', '１缶'],
 ['豆腐', '適当'],
 ['しらす', '適当'],
 ['ごま', '適当']]
```

### 1ページのPDFに複数の表があるとき

このPDFには、1ページのPDFに2つの表があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953149/9290051f-ab30-6f24-35a5-56b4206a69fe.png)

for文で複数の表のデータを取得します。

```python
from pprint import pprint

import fitz

# ドキュメントを開く
doc = fitz.open("recipe.pdf")

# ページを取得する
page = doc[0]

# ページ上にあるテーブルを検出する
tabs = page.find_tables()

# 検出されたテーブルの数を表示する
print(f"{len(tabs.tables)}個のテーブルが{page}上に見つかりました")

# 少なくとも1つのテーブルが見つかった場合
if tabs.tables:
    # すべてのテーブルを抽出する
    for table in tabs:
        # テーブルのデータを抽出する
        pprint(table.extract())
        print()
```

【出力結果】
リストが2つ出力されました。
```
2個のテーブルがpage 0 of recipe.pdf上に見つかりました
[['材料', '数量'],
 ['アボカド', '１個'],
 ['トマト', '適当（アボカドにあうくらい）'],
 ['大豆水煮缶', '１缶'],
 ['豆腐', '適当'],
 ['しらす', '適当'],
 ['ごま', '適当']]

[['順番', '内容'],
 ['1', 'アボカドとトマトを切る'],
 ['2', '１と大豆の水煮缶をまぜて、ビタミン C を入れる'],
 ['3', 'お皿に豆腐を入れて２をのせる'],
 ['4', '３にしらす・ごま・亜麻仁油をかける']]
```


### PDFが複数ページあるとき

PDFが複数ページあるときは`page = doc[0]`でページ番号を指定します。
`page = doc[0]`は1ページ目です。

財務省の貿易統計から「令和5年7月分貿易統計（速報）の概要」をダウンロードしました。

https://www.customs.go.jp/toukei/shinbun/trade-st/gaiyo2023_07.pdf


1ページ目の最初の表を取得します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953149/b8c2b302-7f69-7ed7-ef81-767525010ded.png)


1ページ目の1つ目の表のデータを取得します。
`page = doc[0]`は1ページ目、`tabs[0]`は1つ目の表です。

```python
from pprint import pprint

import fitz

doc = fitz.open("gaiyo2023_07.pdf")
page = doc[0]
tabs = page.find_tables()
if tabs.tables:
    pprint(tabs[0].extract())

```

【出力結果】

```
[['輸 出', '金 額', '８兆 ７，２５０億円', '▲ ０．３％', '２９ヵ月ぶりの減少'],
 [None, '数量指数', '１００．３', '▲ ３．２％', '１０ヵ月連続の減少'],
 ['輸 入', '金 額', '８兆 ８，０３７億円', '▲１３．５％', '４ヵ月連続の減少'],
 [None, '数量指数', '９６．９', '▲ ４．３％', '９ヵ月連続の減少'],
 ['差 引', '金 額', '▲７８７億円', '▲９４．５％', '２ヵ月ぶりの赤字']]
```

1ページ目の2つ目の表のデータを取得します。
`page = doc[0]`は1ページ目、`tabs[1]`は2つ目の表です。


```python
from pprint import pprint

import fitz

doc = fitz.open("gaiyo2023_07.pdf")
page = doc[0]
tabs = page.find_tables()
if tabs.tables:
    pprint(tabs[1].extract())

```

【出力結果】
```
[['輸 出', '１兆 ７，９１２億円', '＋１３．５％', '２２ヵ月連続の増加'],
 ['輸 入', '９，４５３億円', '▲１１．２％', '２ヵ月連続の減少'],
 ['差 引', '８，４５９億円', '＋６５．０％', '６ヵ月連続の増加']]
```

# PDFの表をExcelに出力する

pandasのデータフレームを作成して、Excelに出力します。

こちらの表を出力してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953149/f18528a1-e255-92c3-509d-16180de22fea.png)



```python
pip install pandas
pip install openpyxl
```
pandasのデータフレームを作成してExcelに出力します。

```python
import fitz
import pandas as pd

doc = fitz.open("gaiyo2023_07.pdf")
page = doc[3]
tabs = page.find_tables()
if tabs.tables:
    table_data = tabs[0].extract()

    # 列名を取得
    columns = table_data[0]

    # データ行を取得
    data_rows = table_data[1:]

    # Pandasデータフレームを作成
    df = pd.DataFrame(data_rows, columns=columns)

    # データフレームをExcelファイルに保存
    df.to_excel("output.xlsx", index=False)  # index=Falseを設定して行番号を含めない

    print("Excelファイルに保存しました: output.excel")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953149/90862079-856e-30ab-b54d-5700354b0620.png)


# おまけ
ちょっと遊んでみました🎊


Python日記vol.20🐍PDFの表からデータを取得して叙勲受章者の表を作りたい

https://note.com/alice37308108/n/ndce515aa8667