落ちたからアプリ作る②:OCRで過去問PDFをテキスト化する

システム開発

はじめに

※本記事の一部コンテンツ(文章・画像)はAIの支援を受けて作成しています。

情報処理安全確保支援士試験に落ちたのをきっかけに、「だったら自分で対策アプリ作っちゃえ!」というモチベーションで始めたこのシリーズ。今回はその第2回です。

前回のおさらい

前回は、受験に失敗した反省から「過去問を効率的に学習できるアプリを作りたい」と思い立ち、ChatGPTと連携して解説も自動生成できたらいいな〜というところまで考えました。AI開発×python×情報処理安全確保支援士を並行して進めています。

作りたいのは下記2点でした。

  • 過去問をアプリケーションから活用できるように問題文を抽出してDB化するツール
  • DB化された問題文からランダムに出題、回答後にChatGPTが解説してくれるアプリケーション

今回の目的とやりたいこと

アプリで使う過去問データを手作業で入力するのは現実的ではないので、できる限り自動で取り込める仕組みを検討中です。問題点が3点ありました。

  1. 過去問のページが実施回ごとに分かれていてすべてダウンロードするには結構な操作が必要
    →手動でやったら大変そう。スクレイピングするツールを作る?
  2. 過去問のPDFが公開されている量が多い(2009年度のものからある)
    →16年分。年2回で各30問、約900問。重複も多いと思われるが、手動でデータ化するのは厳しそう。
     重複データは集約する?しない?
  3. PDFに掲載されている過去問はテキストデータではなく、実際の試験に使われた冊子をPDF化したものらしくすべて画像データ
    →アプリケーション上は画像で表示する?テキストデータの方がデータ量もすくなく軽くて済むのだが・・・

問題点1についてはさほど難しそうではなく、スクレイピングするツールなどいくらでもありそうなので後回し。
それよりも、まずはツールが作れるかどうかの大きな問題である問題点3の技術検証をすることにしました。

ChatGPTに聞くとこういった処理はOCRといい、tesseract(テッセラクト)というGoogleが開発したオープンソースのプロダクトが使えるそう。pythonから使うにはpytesseractというライブラリを利用すると良いとサンプルソースまで生成してくれました。

今回はただの検証なので、適当な実施回のPDFを読み込ませ「PDF形式の過去問をOCR(光学文字認識)でテキスト化する」処理をGoogle Colabで試してみました。Google Colabとはブラウザ上でpythonが記述・実行できるサイトです。ちょっとした検証や学習にはとても便利です。

OCR実験の流れ

PDFから画像への変換

IPAが配布している過去問PDFは、ぱっと見はテキストっぽいのに実は全部画像で構成されています
画像→テキストはOCRの役目なのですが、pytessearctではPDFを読み込めないので、まずはPDFをページごとに画像に変換する必要がありました。

下記は検証用に作成したコードです(記事の最後にGoogle Colabのノートブックへのリンクを掲載しています)

!apt-get install -y poppler-utils
!pip install pdf2image
from pdf2image import convert_from_path
from google.colab import files
import os

# === 画像出力フォルダの設定 ===
output_folder = "output_images"

# === PDFの読み込み(ローカルファイルを指定してアップロード)===
uploaded = files.upload()
for fn in uploaded.keys():
  print('User uploaded file "{name}" with length {length} bytes'.format(
      name=fn, length=len(uploaded[fn])))
pdf_path = os.path.join("/content", list(uploaded.keys())[0])

# === フォルダ作成(既に存在していてもOK)===
os.makedirs(output_folder, exist_ok=True)

# === PDFをページごとの画像に変換 ===
images = convert_from_path(pdf_path, dpi=300)

# === 各ページをPNGで保存 ===
for i, page in enumerate(images):
    filename = f"page_{i+1}.png"
    filepath = os.path.join(output_folder, filename)
    page.save(filepath, "PNG")
    print(f"{filepath} に保存しました")

print("すべてのページを画像に変換・保存しました!")

ここでは pdf2image というPythonライブラリを使っています。Colab環境なら apt で必要な依存も含めてインストール可能です。

OCRでテキスト抽出

画像に変換した各ページを pytesseract(Google製OCRエンジンTesseractのPythonラッパー)を使って日本語テキストに変換しました。

!apt install -y tesseract-ocr tesseract-ocr-jpn
!pip install pytesseract pillow

from PIL import Image
import pytesseract
from google.colab import files

# === 環境設定 ===
txt_output_folder = "ocr_pages"
os.makedirs(txt_output_folder, exist_ok=True)

# -- 抽出したイメージすべてに対して処理する --
for i, page in enumerate(images):
  image_path = os.path.join(output_folder, f"page_{i+1}.png")
  text_path = os.path.join(txt_output_folder, f"page_{i+1}_text.txt")
  # --- 画像を開く ---
  img = Image.open(image_path)

  # --- OCR処理(日本語) ---
  text = pytesseract.image_to_string(img, lang='jpn')

  # -- ファイル出力 --
  with open(text_path, "w", encoding="utf-8") as f:
          f.write(text)

実行してみた結果と課題

実行してみた結果、ほぼ正確にテキスト化できている模様で一瞬喜びましたが・・・そんなに甘くは無いみたい。

PDF(画像)
出典:令和5年度 秋期試験 情報処理安全確保支援士 午前Ⅰ 問1~2
OCRで抽出したテキスト
間1 逆ポーランド表記法 (後置記法) で表現されている式 ABCD一X十において,
A三16, Bー8, C=ニ4, Dニ2 のときの演算結果はどれか。逆ポーランド表記法による式
AB十は, 中言記法による式A十B と同一である。

問2 図のように 16 ビットのデータを 4X4 の正方形状に並べ, 行と列にパリティビット
を付加することによって何ビットまでの誤りを訂正できるか。ここで, 図の網掛け部
分はパリティビットを表す。





トo

てりう
H
-ト
  • 問1
    • =や×、+といった数学記号の変換が怪しい
    • 選択肢が変換できてない
  • 問2
    • 図が変換できてない(テキスト化だから当たりまえか・・・)
    • やっぱり×の変換が怪しいけど、これはまだ読めるから良いか・・・

成功した部分

  • 解像度をDPI 300〜400に設定すれば、日本語テキストの大部分は9割以上の精度で正しく抽出できました。
  • OCRがうまく動いたページはそのままテキスト化でき、正規表現などで構造を取れそうな手応えもありました。

困った・気づいたこと

  • 数式(分数や√)や記号(±など)は正しく認識されないケースが多かった
  • 一部のページでは「0(ゼロ)」が「9」と認識されるなどの誤認識もあり
  • 問題文中に画像が含まれているパターンもあることに、OCR後の結果を見て初めて気づく

つまり、「PDFだからといって全部文字とは限らない」「OCRに過信は禁物」というのが今回の教訓です。

実際の開発作業や見積もり作業だと大失敗するようなパターンですね。多分自動化できるのでツール作成2日+実行1日とかで!と見積もった結果、実は手作業が大量に発生した、というのはよくあるケースです。必死でスケジュール守るか、ごめんなさい想定外です、もっとスケジュールください、とか言わないとダメなやつです。

ChatGPTに打開案を相談してみたところ、いくつか対方法はあるようで、次回はこの問題の解消するべく検証続けていきます!(試験勉強できない・・・)

今後の方針

  • このままだとかなり手作業を入れないとデータ化できないので、数式や画像を含むページについては、OCRの前処理(画像加工や領域抽出など)を別ノートで検証予定です。
    今後は以下のアプローチを通じて、OCRの認識精度をさらに高めていく予定です。
    • OpenCVによる画像前処理
    • 文字種の指定
    • Tesseractの設定調整
  • 図や数式の領域を切り分けるレイアウト解析の導入も検討しています。問題文の図のみ抽出したり、数式の箇所だけ特殊な処理を入れたりできないかと思いました。
  • 抽出したテキストの構造化(問題文/選択肢の分離)についても、今後扱っていきます。

おまけ:Colabノートブック公開

今回のOCR処理をColabノートブックにまとめました。
実行・再利用できるように公開しているので、よろしければ試してみてください👇

🔗 Colabノートを開く

タイトルとURLをコピーしました