PyMuPDF4LLMを試す
ここで知った
公式
PyMuPDF4LLM は、Python 向けの最速の PDF 抽出ツールである PyMuPDF に基づいています。
機能
- マルチカラムページのサポート
- 画像およびベクターグラフィックスの抽出をサポート(MDテキストに参照を含めることもできる)
- ページチャンキング出力のサポート
- LlamaIndex Documentsとしての出力を直接サポート。
サポートしているドキュメント
PyMuPDF4LLMは、テキスト抽出用に以下のファイルタイプをサポートしている:
- DOCX
- XLSX
- PPTX
- HWPX
- XPS
- EPUB
- MOBI
- FB2
- CBZ
- 本パッケージは PyMuPDF を用いてファイルのページを Markdown 形式のテキストに変換する。
- 標準のテキストやテーブルが検出され、適切な読み取り順序で取り込まれ、その後一緒に GitHub 互換の Markdown テキストに変換されます。
- ヘッダー行はフォントサイズで識別され、適切に1つまたは複数の#タグで接頭語が付けられます。
- 太字、斜体、等幅テキスト、およびコードブロックが検出され、それに応じて書式が付けられます。順序付けられたリストと順不同リストにも同様のことが適用されます。
- デフォルトでは、すべての文書ページが処理されます。必要に応じて、0 から始まるページ番号のリストを指定してサブセットのページを指定できます。
Colaboratoryでためしてみる。
インストール
!pip install pymupdf4llm
読み込ませるPDFは、 神戸市が公開している観光に関する統計・調査資料のうち、「令和4年度 神戸市観光動向調査結果について」を使う。縦書きの文書で、文字がメイン、残りは表とグラフとなっている。
PDF直
ダウンロード
!wget https://www.city.kobe.lg.jp/documents/15123/r4_doukou.pdf -O kobe_kanko.pdf
まるっと読み込んでMarkdownに出力する。神戸の観光情報PDFから。
import pymupdf4llm
md_text = pymupdf4llm.to_markdown("kobe_kanko.pdf")
print(md_text)
長いので先頭部分だけ抜粋。
# 令和4年度 神戸市観光動向調査結果について
本調査は,来神観光客の特質と神戸市内の観光動向を把握し,今後の観光行政の参考とす
調査目的
ることを目的に実施。
調査方法 調査員が対面にてアンケート項目を聞き取りする形で実施。
① 令和4年5月21 日(土)
② 令和4年9月24 日(土)
③ 令和4年12 月17 日(土)・24 日(土)※
④ 令和5年3月4日(土)
※雨天により、一部の調査地点については延期して実施。
調査日
調査地点
|地区|NO|調査地点|サンプル数|
|---|---|---|---|
|北野|1|北野町広場|201|
||2|北野工房のまち|201|
|市街地|3|南京町広場|241|
||4|総合インフォメーションセンター|211|
||5|旧居留地|215|
||6|神戸布引ロープウェイハーブ園山麓駅|217|
||7|白鶴酒造資料館内|201|
||8|王子動物園内|224|
||9|県立美術館前|201|
||10|さんちか夢広場|245|
||11|神戸空港屋上階展望ロビー|222|
||12|IKEA神戸|204|
||13|能福寺(兵庫大仏)|131|
||14|兵庫津ミュージアム|171|
|神戸港|15|神戸海洋博物館前及び周辺|210|
||16|中突堤中央ターミナル周辺|215|
||17|umie モザイク|244|
||18|ハーバーランド総合インフォメーション前|211|
|六甲・摩耶|19|六甲天覧台|212|
||20|摩耶山掬星台広場|208|
||21|六甲山牧場|208|
||22|六甲ガーデンテラス内|212|
|有馬|23|有馬温泉観光総合案内所前|201|
||24|金の湯前|207|
||25|六甲有馬ロープウェイ有馬温泉駅|200|
|須磨・舞子|26|須磨海浜水族園入口付近|222|
||27|マリンピア神戸 さかなの学校おさかな広場周辺|207|
||28|須磨離宮公園|218|
||29|舞子公園(舞子海上プロムナード)|210|
|西北神|30|神戸ワイナリー(農業公園)|220|
||31|神戸フルーツ・フラワーパーク大沢園内|209|
||32|神戸三田プレミアム・アウトレット|216|
合計
市街地
神戸港
六甲・摩耶
有馬
須磨・舞子
西北神
-----
(snip)
デフォルトだと全ページ読み込まれて、ページごとに-----
で区切られる様子。
ページを指定する場合
md_text = pymupdf4llm.to_markdown("kobe_kanko.pdf", pages=range(0,2))
print(md_text)
# 令和4年度 神戸市観光動向調査結果について
本調査は,来神観光客の特質と神戸市内の観光動向を把握し,今後の観光行政の参考とす
調査目的
ることを目的に実施。
調査方法 調査員が対面にてアンケート項目を聞き取りする形で実施。
① 令和4年5月21 日(土)
② 令和4年9月24 日(土)
③ 令和4年12 月17 日(土)・24 日(土)※
④ 令和5年3月4日(土)
※雨天により、一部の調査地点については延期して実施。
調査日
調査地点
|地区|NO|調査地点|サンプル数|
|---|---|---|---|
|北野|1|北野町広場|201|
||2|北野工房のまち|201|
|市街地|3|南京町広場|241|
||4|総合インフォメーションセンター|211|
||5|旧居留地|215|
||6|神戸布引ロープウェイハーブ園山麓駅|217|
||7|白鶴酒造資料館内|201|
||8|王子動物園内|224|
||9|県立美術館前|201|
||10|さんちか夢広場|245|
||11|神戸空港屋上階展望ロビー|222|
||12|IKEA神戸|204|
||13|能福寺(兵庫大仏)|131|
||14|兵庫津ミュージアム|171|
|神戸港|15|神戸海洋博物館前及び周辺|210|
||16|中突堤中央ターミナル周辺|215|
||17|umie モザイク|244|
||18|ハーバーランド総合インフォメーション前|211|
|六甲・摩耶|19|六甲天覧台|212|
||20|摩耶山掬星台広場|208|
||21|六甲山牧場|208|
||22|六甲ガーデンテラス内|212|
|有馬|23|有馬温泉観光総合案内所前|201|
||24|金の湯前|207|
||25|六甲有馬ロープウェイ有馬温泉駅|200|
|須磨・舞子|26|須磨海浜水族園入口付近|222|
||27|マリンピア神戸 さかなの学校おさかな広場周辺|207|
||28|須磨離宮公園|218|
||29|舞子公園(舞子海上プロムナード)|210|
|西北神|30|神戸ワイナリー(農業公園)|220|
||31|神戸フルーツ・フラワーパーク大沢園内|209|
||32|神戸三田プレミアム・アウトレット|216|
合計
市街地
神戸港
六甲・摩耶
有馬
須磨・舞子
西北神
-----
分析の概要
Ⅰ.来神客の属性
性別構成としては、全市では男性より女性のほうが多くなっている。地区別にみても、いず
れの地区も女性の占める割合のほうが高くなっている。
年齢構成としては、全市では60歳以上が最も高く、次いで40歳代、50歳代、30歳代の順に高
く、全市では40歳以上が6割を超える。地区別にみると、『六甲・摩耶』で20歳代が2割強で、
他の地区と比較して高くなっている。
居住地としては、全市では近畿が8割を占め、遠距離(近畿以外)からは2割程度であるが、
地区別にみると、『北野』では遠距離(近畿以外)からが約4割となっている。
<(1)(2)(3)参照>
Ⅱ.利用交通機関
神戸までの主な利用交通手段としては、全市では「車、バイク」が約4割、鉄道(新幹線、
JR、阪急、阪神、山陽)利用者が4割を超えている。地区別にみると、新幹線利用者は『北
野』が約2割と他の地区より高い。一方、車利用者(バイク含む)は『西北神』で8割を超え、
飛びぬけて高くなっている。
また、神戸市内での主な利用交通手段としては、全市では車利用の割合が3割を超えて最も
高い。地区別にみると、「市内観光用のループバス」は『北野』において1割以上で他地区より
高い。「車、バイク」は『西北神』で8割超、『六甲・摩耶』『有馬』『須磨・舞子』では4割を
超えている。
<(4)参照>
Ⅲ.来神動機・情報収集
神戸観光の動機(きっかけ)としては、全市では「前に来てよかった」が最も高く、次いで
「家族・友人・知人の話」でそれぞれ2割を超えている。地区別にみると、『北野』『六甲・摩
耶』『有馬』の各地区は「家族・友人・知人の話」が最も高く、『西北神』はインターネットが
約2割で最も高い。
神戸観光にあたっての情報収集の方法としては、全市では旅行決定前・後ともに「インター
ネット」が約4割と最も高くなっている。また、すべての地区において、「家族・友人・知人の
話」は旅行決定前が旅行決定後より高くなっている。
<(5)(6)参照>
Ⅳ.旅行同行者・旅行形態
今回の旅行の同行者として、全市では「家族(子連れ)」が最も高く、次いで「友人知人」、
「家族(夫婦・パートナーのみ)」で、いずれも2割超となっている。地区別にみると、『須磨・
舞子』では「家族(子連れ)」が4割を超え、高くなっている。「友人知人」は『北野』『六甲・
摩耶』『有馬』で約3割と高くなっている。
旅行形態としては、全市で交通機関や宿泊施設などを予約していない割合が約8割となって
いる。地区別でみても、『有馬』を除くすべての地区で予約していない割合が過半数を占める。
個人で予約した割合は『有馬』では5割と高くなっている。
<(7)(8)参照>
-----
別のPDFでもためしてみる。
農林水産省公式サイト内で公開されている畜産・競馬に関する各種PDFの中から 「馬産地をめぐる情勢(令和6年6月)」 を使う。図・グラフ・表などが盛り込まれたスライドとなっている。
PDF直
ダウンロード
!wget https://www.maff.go.jp/j/chikusan/keiba/lin/attach/pdf/index-24.pdf -O basanchi.pdf
import pymupdf4llm
# marginsを指定するとその範囲内のみを抽出する。単位は不明
# marginsの指定
# - margins=(left, top, right, bottom)。デフォルトは`(0, 50, 0, 50)`で上下が少しカットされる。
# - margins=(top, bottom)。`(0, top, 0, bottom)`と同義
# - margins=f。`(f, f, f, f)`と同義。マージンを全て取り払うならば、margins=0とする
md_text = pymupdf4llm.to_markdown(
"basanchi.pdf",
pages=[8],
margins=0
)
print(md_text
### 7<規模別>軽種馬生産農家戸数・繁殖雌馬飼養頭数(令和5年)
##### 飼養規模10頭以下の生産者戸数は463戸で、全体の約61%。
飼養規模10頭以下の生産者における繁殖雌馬飼養頭数は2,261頭で全体の約21%。
飼養規模21頭以上の生産者における繁殖雌馬飼養頭数は5,883頭で全体の約55%。
ただし、21頭以上は繁殖雌馬合計頭数から推計。
1~10頭
```
21%
```
```
21頭以上
55%
```
全国
```
10,653頭
```
```
11~15頭
15%
```
```
16~20頭
9%
```
|1)繁殖雌馬飼養頭数別軽種馬生産者戸数|Col2|Col3|Col4|Col5|Col6|Col7|Col8|Col9|Col10|
|---|---|---|---|---|---|---|---|---|---|
|飼養規模 項目||1~10頭 1~5頭 6~10頭|||11~15頭|16~20頭|21頭以|上|合計|
||||1~5頭|6~10頭||||||
|全 国||463|276|187|121|55||122|761|
|||61%|36%|25%|16%|7%||16%|100%|
|北 海 道|日 高|366|196|170|110|53||113|642|
|||57%|31%|26%|17%|8%||18%|100%|
||胆 振|20|14|6|4|1||8|33|
|||61%|42%|18%|12%|3%||24%|100%|
|||||||||||
|2)飼養頭数規模別繁殖雌馬飼養頭数||||||||||
|飼養規模 項目||1~10頭 1~5頭 6~10頭|||11~15頭|16~20頭|21頭以|上|合計|
||||1~5頭|6~10頭||||||
|全 国||2,261|771|1,490|1,537|972|5|,883|10,653|
|||21%|7%|14%|14%|9%||55%|100%|
|北 海 道|日 高|1,943|589|1,354|1,398|936|4|,087|8,364|
|||23%|7%|16%|17%|11%||49%|100%|
||胆 振|80|28|52|52|16|1|,838|1,986|
|||4%|1%|3%|3%|1%||93%|100%|
|資料:(公財)ジャパン・スタッドブック・インターナショナル、(公社)日本軽種馬協会「2023軽種馬統計」(令和5年12 「(2)飼養頭数別繁殖雌馬飼養頭数」は(1)により頭数×戸数で算出。||||||||||
-----
画像を別に保存することもできる。
md_text = pymupdf4llm.to_markdown(
"basanchi.pdf",
pages=[8],
margins=0,
write_images=True, # 画像ファイルが別ファイルとして保存される
)
print(md_text)
### 7<規模別>軽種馬生産農家戸数・繁殖雌馬飼養頭数(令和5年)
##### 飼養規模10頭以下の生産者戸数は463戸で、全体の約61%。
飼養規模10頭以下の生産者における繁殖雌馬飼養頭数は2,261頭で全体の約21%。
飼養規模21頭以上の生産者における繁殖雌馬飼養頭数は5,883頭で全体の約55%。
![basanchi.pdf-8-0.png](basanchi.pdf-8-0.png)
1~10頭
```
21%
```
`21頭以上` 全国
```
11~15頭
55%
16~20頭
```
ただし、21頭以上は繁殖雌馬合計頭数から推計。
|1)繁殖雌馬飼養頭数別軽種馬生産者戸数|Col2|Col3|Col4|Col5|Col6|Col7|Col8|Col9|Col10|
|---|---|---|---|---|---|---|---|---|---|
|飼養規模 項目||1~10頭 1~5頭 6~10頭|||11~15頭|16~20頭|21頭以|上|合計|
||||1~5頭|6~10頭||||||
|全 国||463|276|187|121|55||122|761|
|||61%|36%|25%|16%|7%||16%|100%|
|北 海 道|日 高|366|196|170|110|53||113|642|
|||57%|31%|26%|17%|8%||18%|100%|
||胆 振|20|14|6|4|1||8|33|
|||61%|42%|18%|12%|3%||24%|100%|
|||||||||||
|2)飼養頭数規模別繁殖雌馬飼養頭数||||||||||
|飼養規模 項目||1~10頭 1~5頭 6~10頭|||11~15頭|16~20頭|21頭以|上|合計|
||||1~5頭|6~10頭||||||
|全 国||2,261|771|1,490|1,537|972|5|,883|10,653|
|||21%|7%|14%|14%|9%||55%|100%|
|北 海 道|日 高|1,943|589|1,354|1,398|936|4|,087|8,364|
|||23%|7%|16%|17%|11%||49%|100%|
||胆 振|80|28|52|52|16|1|,838|1,986|
|||4%|1%|3%|3%|1%||93%|100%|
|資料:(公財)ジャパン・スタッドブック・インターナショナル、(公社)日本軽種馬協会「2023軽種馬統計」(令和5年12 「(2)飼養頭数別繁殖雌馬飼養頭数」は(1)により頭数×戸数で算出。||||||||||
-----
画像はbasanchi.pdf-8-0.png
と言った形でページ番号とインデックス(おそらく複数画像が含まれる場合を踏まえて連番)が付与されてファイルが出力される。
実際にこんな感じで出力されていた。
ちょっと切れてしまっているし、グラフはもう一つあったけど1つしか画像としては生成されていなかったので、このあたりはやってみないとわからないところになりそう。
その他のオプションは以下。
LlamaIndexを使っている場合はPyMuPDF4LLMをDocumentLoaderとしてそのまま使える。
LlamaIndexとPyMuPDF4LLMをインストール
!pip install llama-index pymupdf4llm
!pip freeze | egrep -i "llama-|pymudf"
llama-cloud==0.0.9
llama-index==0.10.56
llama-index-agent-openai==0.2.9
llama-index-cli==0.1.12
llama-index-core==0.10.56
llama-index-embeddings-openai==0.1.11
llama-index-indices-managed-llama-cloud==0.2.5
llama-index-legacy==0.9.48
llama-index-llms-openai==0.1.26
llama-index-multi-modal-llms-openai==0.1.8
llama-index-program-openai==0.1.6
llama-index-question-gen-openai==0.1.3
llama-index-readers-file==0.1.30
llama-index-readers-llama-parse==0.1.6
llama-parse==0.4.9
神戸の観光PDFを使って、読み込み・インデックス作成を行う。
import os
from google.colab import userdata
import pymupdf4llm
from llama_index.core import VectorStoreIndex
# OpenAI APIキー読み込み
os.environ["OPENAI_API_KEY"] = userdata.get('OPENAI_API_KEY')
# PyMuPDF4LLMでPDFを読み込んでLlamaIndexのドキュメントオブジェクトを作成
llama_reader = pymupdf4llm.LlamaMarkdownReader()
documents = llama_reader.load_data("kobe_kanko.pdf")
# ドキュメントからインデックスを作成
index = VectorStoreIndex.from_documents(documents)
# インデックスを使うQuery Engineを作成
query_engine = index.as_query_engine()
ではクエリを投げてみる。
response = query_engine.query("神戸までの主な利用交通機関の内訳を教えて。回答は日本語で。")
print(response)
車、バイクが40.9%、鉄道利用者が46.9%で、鉄道利用者の内訳は新幹線、JR、阪急、阪神、山陽の計で構成されています。
なお、ドキュメントはページごとに分割されて読み込まれていた。
for idx, p in enumerate(documents, start=1):
print(idx, ":", p.id_, "\n ", p.get_content().split("\n")[0], "\n")
1 : acc22860-58b1-44a5-9afd-31181dfd81c6
# 令和4年度 神戸市観光動向調査結果について
2 : a74be0cf-019e-4fb6-8cf8-406462166955
分析の概要
3 : ca73869f-bbd0-43f2-8ade-25ebb207e72f
Ⅴ.旅行の日程および宿泊地
4 : 09571c87-7928-4e89-bb2f-50df90d76245
分析の詳細
5 : 3c8d6ec6-82ec-40a5-b257-adf8426e1559
(3)居住地
6 : d78e8ba6-f41f-48bb-b93e-b80769a46bcb
(4)交通機関利用状況
7 : a2ffe37c-cc68-4ce6-af05-3c756d463785
②神戸市内での主な交通手段
8 : d639f7d8-c5d8-4203-b948-cc61ccc232b9
(5)神戸観光の動機
9 : cdb0329a-a704-4ac5-aea9-74d4e0b8878e
(6)情報収集の方法
10 : cb6bbd0b-bbcd-4d4f-90f5-e8a90b1702cd
(7)旅行同行者
11 : 5c9f1719-be06-4155-9958-e2870b28f3dd
(8)旅行形態
12 : 4cfa6978-a38f-4ca7-9778-51b2b186bceb
(9)旅行の日程および宿泊地
13 : d234f2d3-588a-46b1-9b39-c82884155b80
【※参考】令和2年度・令和3年度調査結果
14 : 0eac9150-96ed-406f-b3f5-112ee888722e
(10)神戸市内での消費額
15 : 57f816c3-3b0e-4bae-b6f4-d3bc8f89a7d0
【※参考】令和2年度・令和3年度調査結果(全市)
16 : b88ae914-e181-4c7e-9036-3b1ead4c5ea9
(11)割引制度の利用
17 : 211fb678-8f62-4a87-818a-0a3d5d3f4e84
(12)立ち寄り先
18 : 957b9680-af0b-4fc3-8065-24ea770c9ca7
②神戸市内の立ち寄り先
19 : 3e848db5-4c72-4ea8-ba97-831a0b6dbf6f
(13)来神回数
20 : 81bab5e7-4765-48fe-a67d-6e49acf13558
(15)満足度
21 : cb2fe90d-c52e-4070-ad27-17d04efcd20e
(16)神戸市観光に期待すること
DocumentSummaryIndexとか使ってページごとのサマリを生成させてもいいかもしれないね。
- テーブルは結構ちゃんとパースできている気がする。複雑すぎるものは厳しいかもだけど、セル結合されているようなものもある程度いい感じにmarkdownのテーブルになってるように思える
- 画像部分の抽出はまあしょうがない。多少表などがあるような文書にはお手軽で良さそう。いかにもなスライドとかはマルチモーダルLLMでやるほうが良さそう。
- LlamaIndexで使えるのは便利なんだけど、結局パースして前処理でクリーニングしたほうがいいような気がするので、直接読み込むのはどうかなという感。
あんまり期待してなかったのだけど、思いの外良かったのと、シンプルに使うなら全然いいんじゃないかという気がした