この記事は制作途中です.
随時コードブロックなどを追加して見やすくしていきます.
概要
大学の奨学金一覧のPDFをスクレイピングで取り込んで,それを適切に処理して欲しいデータだけを抽出したいという思いでCLIアプリの制作を始めたが,色々詰まったので備忘録として残しておきます.
成果物(途中) -> https://github.com/Acu4git/pdfxtractor
当初の構想
- Go言語のみで実装したい(個人的に重要)
- 奨学金一覧のPDFが掲載されている場所は固定されており,PDFファイル名は決まったフォーマットに従っているため,スクレイピングライブラリと正規表現を用いることで取得できそう
- PDFからの表データの抽出は,PDFからテキストを抽出できるライブラリがあればいけそう
- ついでにCSV変換が出来れば嬉しい
- 後は構造体にマッピングして,処理を加えればいけそう
スクレイピングは問題なく成功し,GoのPDFライブラリによるCSV変換も無事できたため,幸先が良い...かのように思えた
突如PDFライブラリがエラーを吐く
使用していたのはunipdf (https://github.com/unidoc/unipdf) で,最初はCSV変換まで問題なくいけた.しかし,ある日から以下のようなエラーがでた.
Error: NewPdfReaderLazy failed. "sample.pdf" err=ciphertext too short
exit status 1
NewPdfReaderLazy関数でエラーが出てるようだが,どうも様子がおかしい.Chat-GPTにて質問を投げかけたところ以下のような解答が得られた.
- PDFファイルが壊れている
- PDFファイルが暗号化されている
- ライブラリのバグや制限
- ファイルパスが間違っている
1に関しては問題なくPDFが読めるし,2に関してはそもそも暗号化を施していない.4に関しても勿論問題ない.また,回数制限には達していない.そのため,3のライブラリ側のバグが原因の可能性がある.unipdfは一応有償のライブラリなのだが,回数制限付きで無償利用ができる.そのため,このライブラリに拘らなくても他に解決策があればそちらを使う方が利用面でも経済面においても安心できるのではないかと思い,一先ず手放すことにした.
代替ライブラリの限界
Go言語には他にもPDF用のライブラリがあるが,テキスト抽出が可能なライブラリの数に限りがあり,1つ1つ神頼みしながら利用しなければならない.(つよつよエンジニアならPDFのフォーマットを解読して自作ライブラリを作ってしまうのかもしれないが)
代替案として挙げられたのが,pdfcpu (https://github.com/pdfcpu/pdfcpu) やledongthuc (https://github.com/ledongthuc/pdf) である.
pdfcpuはGoのPDF用ライブラリではそこそこ有名らしく機能も充実してそうだった.しかし,テキストの抽出の仕方が分からなず断念した.(海外のユーザーも同じことに詰まっていたが未解決のままだった)
ledongthucはテキストの抽出は問題なくできたが,テキストの間に余分な空白があったり,区切り位置がバラバラであったためパースをするのが限りなく困難に近くて挫折.
OCRでの試み
私は大事なことを忘れていた.
「PDFからの抽出が困難なら,画像にしてOCRを通して抽出すればええやんけ!」
すかさず行動に移し,gosseractによるOCRによる抽出を試みた!
失敗した.
日本語のPDFとの相性が悪かったのか,余白と途中改行の嵐でとてもパースできたものではなかった.
悩んだ末
Go言語は比較的新しい言語であるため,PythonやJavascriptなどの言語に比べると情報やライブラリが少ない.そこで,PDFからの抽出部分は他の言語でやってみることにした.ライブラリによって抽出の精度が変わるらしく,それが解決できるかもしれないと思った.
Pythonによる抽出
「ライブラリの宝石箱や~(by 某摩呂)」と言わんばかりにライブラリに恵まれたPythonを使うことにした.ライブラリもそれなりに候補が見つかり,pdfplumberを使用した.
すると普通に成功した.今までの血の滲む努力により達成できなかったものが,ぽっと出のキャラに翻弄されるが如く解決できてしまった.
ほぼ完成へ
その後のCSVからのマッピングはGo言語で問題なく行うことができ,無事形にはなった.ここから色々機能を追加していくつもり.
課題
もともとはGo言語のみで実装する予定であったが,Pythonも使用することになった.そのため,このCLIアプリの起動にはGoとPythonの2つの実行環境が必要になってしまい,利用者のハードルが少し上がる.これを解決するために,Pythonで統一するか,Web上で公開することが候補にある.
今回はGo言語でのアプリ制作の練習も踏まえての実装であったため,途中までGoに拘っていたが,技術選定はもっと柔軟に行うべきだなぁと実感した.