Google Apps Script(GAS)でOCRを活用し、抽出結果をスプレッドシートに書き込む一連の仕組み

この記事の内容について、業務や開発でお困りの場合は個別に対応できます。

概要

  • Google Apps Script(GAS) を使い、Googleドライブ上のファイルをOCR(文字認識)してテキストを抽出する。
  • 抽出したテキストをスプレッドシートへ自動的に書き込むことで、手作業による転記や入力ミスを防ぎ、業務全体を効率化する。
  • さらに、抽出処理の成否やリトライ回数を スクリプトプロパティ に記録し、エラー発生時にも再実行できる仕組みを組み込むことで、継続的かつ安全に運用できる。

全体フローの抽象イメージ

  1. 対象ファイル検索
    • Googleドライブの指定フォルダを走査し、OCR対象となるファイル一覧を取得する。
    • 例:PDFや画像ファイル(JPEG, PNG)などを想定。
  2. OCR変換
    • ファイルごとにOCRを実行し、テキストを抽出する。
    • GAS上で [Advanced Drive Service] を利用するか、あるいは標準の DriveApp とAPI組み合わせで行うパターンが一般的。
  3. テキスト解析
    • 抽出したテキストから必要項目(例:注文番号、金額、日付など)を正規表現等で抜き出す。
    • 複数のパターン(分割納品、通常納品など)に対応するため、フォールバックロジックを組み込む場合もある。
  4. スプレッドシートへの書き込み
    • すでに登録済みかどうかをチェックし、重複しない場合だけ新たに行を追加する。
    • ファイル名をA列、ファイルIDをB列に格納するなど、抽象的なデータ構造を設けておく。
  5. エラー管理と再実行トリガー
    • OCR失敗や解析失敗が続くファイルについては、スクリプトプロパティにカウンターを保持する。
    • 失敗回数が一定回数を超えた場合は再試行を止める、または手動対応に切り替える。
    • 大量のファイルをいっぺんに処理するとタイムアウトの恐れがあるため、ファイル数を限定して実行し、残りがある場合は少し時間を空けて再実行するトリガーを設定するのが定石。

コード例(抽象化)

以下に、典型的なGASコードの断片とその解説を示す。実際には用途や業務に合わせて変更すること。

1. メインエントリーポイント

function runAllTools() {
  // OCR実行 + スプレッドシート書き込み
  extractOcrData();
  // ファイル名変更など、別の自動処理を呼び出すことも可能
  renameFilesIfNeeded();
}
  • runAllTools() 関数を カスタムメニュー時間ベースのトリガー から呼び出す想定。
  • 一度の呼び出しで複数の処理を連続的に実行する。

2. OCR実行と抽出結果の書き込み

function extractOcrData() {
  const folderId = "xxxxx_xxxxx"; // OCR対象フォルダのID
  const folder = DriveApp.getFolderById(folderId);
  const files = folder.getFiles();

  const props = PropertiesService.getScriptProperties();
  let errorMap = JSON.parse(props.getProperty("ERROR_MAP") || "{}");

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("抽象的シート名") || ss.insertSheet("抽象的シート名");

  let count = 0;
  const MAX_PER_RUN = 10;

  while (files.hasNext()) {
    if (count >= MAX_PER_RUN) {
      // 上限を超えたので一旦中断、後で再実行トリガーをセット
      setOneTimeTrigger("extractOcrData", 5); // 5分後など
      break;
    }

    const file = files.next();
    const fileId = file.getId();

    // 重複チェック
    if (isAlreadyRegistered(sheet, fileId)) {
      continue;
    }

    // 失敗回数が多いファイルはスキップ
    if (errorMap[fileId] && errorMap[fileId] >= 3) {
      continue;
    }

    // OCR + テキスト解析
    const success = processSingleFile(file, sheet, errorMap);
    if (!success) {
      errorMap[fileId] = (errorMap[fileId] || 0) + 1;
      continue;
    }

    count++;
  }

  // スクリプトプロパティに失敗回数を保存
  props.setProperty("ERROR_MAP", JSON.stringify(errorMap));
}
  • extractOcrData() 関数が本体。指定したフォルダを走査し、ファイルごとにOCRを実行して抽出結果をシートに書き込む。
  • タイムアウトに対処するため、一度に処理する件数を MAX_PER_RUN で制限し、残があれば再実行トリガーを設定する流れが典型的。
  • errorMap により失敗回数を蓄積し、3回以上失敗したファイルは除外している例を示している。

3. 個別ファイル処理関数

function processSingleFile(file, sheet, errorMap) {
  // OCR変換
  const docId = convertToDoc(file);
  if (!docId) return false;

  // ドキュメント本文のテキスト取得
  const text = getOcrText(docId);

  // 必要項目を抽出(例:注文番号・金額など)
  const orderNumber = extractOrderNumber(text);
  const amount = extractAmount(text);

  // スプレッドシートに書き込み
  writeRow(sheet, file, orderNumber, amount);

  // 後処理(Googleドキュメントを削除 or ゴミ箱へ移動など)
  DriveApp.getFileById(docId).setTrashed(true);

  return true;
}
  • processSingleFile() は1ファイルあたりの実処理。
  • OCR後のドキュメントID docId を取り出し、本体テキストを読み込む。抽出ロジックは別途 extractOrderNumber()extractAmount() などの関数にまとめると可読性が上がる。
  • 最終的にはシートに1行追加し、true(成功)か false(失敗)を返す。

4. OCRコンバートとテキスト取得

function convertToDoc(file) {
  try {
    // Advanced Drive Service または Drive API を利用
    const resource = {
      title: file.getName().replace(/\.pdf$/i, ""),
      mimeType: MimeType.GOOGLE_DOCS
    };
    const docFile = Drive.Files.create(resource, file.getBlob(), {
      ocr: true,
      ocrLanguage: "ja",
      supportsAllDrives: true
    });
    return docFile.id;
  } catch (e) {
    Logger.log("OCR変換失敗: " + e.message);
    return null;
  }
}

function getOcrText(docId) {
  try {
    const doc = DocumentApp.openById(docId);
    return doc.getBody().getText();
  } catch (e) {
    Logger.log("ドキュメント取得失敗: " + e.message);
    return "";
  }
}
  • PDFや画像をGoogleドキュメントに変換することで、OCR処理が実行される(Advanced Drive Service あるいは Drive API を有効化しておく必要あり)。
  • 変換後のDocIDを元に DocumentApp で本文を取得する。

5. スプレッドシートへの書き込み

function writeRow(sheet, file, orderNumber, amount) {
  const fileName = file.getName();
  const fileId = file.getId();

  const link = SpreadsheetApp.newRichTextValue()
    .setText(fileName)
    .setLinkUrl(file.getUrl())
    .build();

  // 例: A列=ファイル名(リンクつき)、B列=ファイルID、C列=金額、D列=注文番号
  sheet.appendRow(["", "", "", ""]);
  const lastRow = sheet.getLastRow();
  sheet.getRange(lastRow, 1).setRichTextValue(link);
  sheet.getRange(lastRow, 2).setValue(fileId);
  sheet.getRange(lastRow, 3).setValue(amount);
  sheet.getRange(lastRow, 4).setValue(orderNumber);
}
  • appendRow() で空行を追加し、そこに各情報を書き込む例。
  • リンク付き文字列としてスプレッドシートに表示するために、RichTextValue の機能を使っている。

6. 再実行トリガーの設定

function setOneTimeTrigger(funcName, minutesLater) {
  ScriptApp.newTrigger(funcName)
    .timeBased()
    .after(minutesLater * 60 * 1000) // ミリ秒換算
    .create();
}
  • 5分後や10分後など、短時間後に再実行したい場合に呼び出す関数。
  • タイムアウトや大量ファイル処理時の対策として重要。

まとめ

本記事では、GASでOCRを実行してスプレッドシートに書き込む仕組みの一連の流れを抽象化して示した。ポイントは以下のとおりである。

  • コード分割:OCR変換、テキスト抽出、スプレッドシート書き込み、再実行トリガーなどを関数ごとに分割し、可読性と保守性を高める。
  • スクリプトプロパティ:失敗回数や一時的な状態を保持し、エラーが繰り返されても無限ループに陥らないよう制御する。
  • 再実行トリガー:大量のファイルを処理するとタイムアウトになりやすいので、一定件数処理したら再度トリガーを発行して続きの処理を行う。
  • 抽出ロジック:複数のパターンやフォーマットに対応するために正規表現やフォールバック処理を用意し、抽出精度を高める。

このような実装を行うことで、紙や画像の情報を自動でデジタル化し、スプレッドシートに集約できる。その結果、手動の入力ミスや作業時間を大幅に削減し、業務全体の生産性向上につながる。

以上が、GASコードを抽象化したOCR連携スクリプトの典型例である。実際の運用では、これをベースにエラー通知(メール送信)やフォルダ分けによる権限管理、ファイル名の自動変更など、さまざまな拡張を施して柔軟に対応していくことができる。

ZIDOOKA!

この記事の内容について、対応できます

この記事に関連する技術トラブルや開発上の問題について個別対応を行っています。

個別対応は3,000円〜 内容・工数により事前にお見積りします
最後までお読みいただきありがとうございました

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

AI活用に関するポリシー

当サイトでは、記事の執筆補助にAIを活用する場合がありますが、全面的な委任は行いません。