サーバーレスではじめる大学生活(時間割管理)
大学の時間割がPDFしかなくてカレンダー入れるのが一々手間だったので自動化したノウハウ
前提
公開されている時間割ではないので、どういうPDFなのかぼかして記載しています。
そのためパッとしない説明が多いですがご了承ください。
アーキテクチャ
システムは
- Pre processor
- PDFからテキスト情報とカラー情報を抽出し、JSONにしてR2にupload
- API
- URLから対象のJSONを特定し、GETパラメーターを元に特定のコマをicsに変換し返す
の2つに分かれています。
困ったこと
PDFのテキストデータが構造化されていない
今回対応したPDFにはExcelのような表があり、その中に「x日のn時限目はyy教科」というような情報が含まれている。
これを抽出したいわけだが、
Portable Document Formatは、デジタルデバイス上でアプリケーションやOS、ハードウェアに依存せず文章や図版を表示するために開発され、ISO 32000で国際標準化された電子文書ファイル形式である。 by Wikipedia
であることから、当然RDBのように構造化されているわけではない。
ではどうするかというと
- 隣接しているテキスト同士を結合 / セル情報に変換する
- 座標からセル情報に変換 / テキスト統合
の二択であるが、前者は上手くいかない。
見出しなどで文字同士が離れていたり、逆に隣接しすぎて別の文字列だと判断出来なかったりと、色々面倒事が多いからである。[1]
そのため今回は(2)を採用した。[2]
具体的には「座標aから座標b間にあるテキストは一つのテキスト(=セル)としてみなす」という実装になっている。
学年毎に色分けされている
セルの背景色で学年識別できるようになっている
pdfjs-distというライブラリを使用してPDFデータを読み取っているが、色情報を取得する方法が分からなかった。
(恐らく図形の背景色みたいな扱いになっていると思われる)
そこで今回はPDFを一旦canvasに描画して、特定のピクセル情報を取得する方針にした。
幸いにもpdfjs
にcanvasに描画する関数が用意されているので、それを利用し色情報を取得することが出来た。
コマごとに抽出
icsに変換後R2にアップロードして終わり!と思っていたが...
本システムを使いたい人によって取っているコマが違うだろう。
そのため一度Cloud Runを挟み、欲しいコマのみ抽出できるようにした。
GETパラメーターとArray.filter
使ってるだけなので割愛。コード見てください。
お金周り
自分だけならまだしも、他人も使えるようにしてしまったせいでアクセス数が読めない。
そのため無料枠が多いCloudFlare R2とCloud Runを採用した。
実はCloud Function Gen 2も使っていましたが、Artifact Registry周り(特にCloud Storage)で料金が発生してしまったため、Docker Hub経由のCloud Runに変更しました。
また、Cloud Runだけだとコールドスタートでレスポンス遅いので、間にCloudFlare CDN挟んで高速化しました。
どちらかといえば無駄にCloud Run実行されるのを防ぐという意味合いが強いけど。
おわりに
PDF扱う人の何かの参考になれば幸いです。
余談ですがPDFの保存先にGoogle Driveを選んだ理由は、大学行ってるのが彼女なので使い勝手の面でGoogle Driveになりました。
リポジトリ
Discussion