Initial Site

Initial Site

Initial Site

【GAS】お手軽なOCRの自動化をスプレッドシートで扱いやすくする

  • ヨシモト2019/08/08 19:44
ai_computer_sousa_robot

開発部 ヨシモトです。
 
※7月度より開発部所属になりました、そのお話はまた後日。

 

以前書いた、【GAS】OCRを使ってスキャンしたい画像の文字取得を自動化するという記事について、並べ替えに関するコメントをいただきましたので、スプレッドシートやエクセル等でもう少し扱いやすいように変更いたしました。

 

概要

大まかには前回の記事と似たような流れです。

  1. 1. 文字を読み取りたい画像ファイルがGoogle ドライブにある。
  2. 2. Google ドライブ内の画像から画像ファイルとは別にOCR用のファイル(ドキュメントのファイル)を作る(読み取った文字列や数値がテキストとして、このOCRファイルに入っています)
  3. 3. OCRで文字を読み取る
  4. 4. 読み取った文字列と、ファイル名と、元の画像ファイルがドライブに追加された日時をスプレッドシートに入力する NEW

 

※読み取りたい画像がGmailにある場合は、以下の記事を参照してください。

【GAS】Gmailの添付ファイルを一括でGoogleドライブへ保存する

 

コード

function ocrSample() {
  var picFolderId = PropertiesService.getScriptProperties().getProperty('picFolderId');
  var folder = DriveApp.getFoldersByName('対象フォルダ名').next();
  var images = folder.getFilesByType('image/png');
  
  var sheet = SpreadsheetApp.getActiveSheet();
  
  var titleAndText = [];
  
  while(images.hasNext()){
    var image = images.next();
    var docName = image.getName().split("\.")[0];
    var createDateRaw = image.getDateCreated();
    var createDate = Utilities.formatDate(createDateRaw,"JST","YYYY/MM/dd HH:mm");
    
    var Request_body = {
      title: docName, 
      mimeType: 'image/jpeg'
    }
    Drive.Files.insert(Request_body, image, { ocr: true });
    
    var newFile = DriveApp.getFilesByName(docName).next();
    folder.addFile(newFile);
    DriveApp.getRootFolder().removeFile(newFile);
    
    var docs = folder.getFilesByType('application/vnd.google-apps.document');
    var file = docs.next();
    var docId = file.getId();
    var doc = DocumentApp.openById(docId);
    var text = doc.getBody().getText().split('\n')[2];
    
    titleAndText.push([createDate, docName, text]);
    DriveApp.getFolderById(picFolderId).removeFile(file);
  }
  
  sheet.getRange(1, 1, titleAndText.length, titleAndText[0].length).setValues(titleAndText);
  
  var range = sheet.getDataRange()
  range.sort({column: 1, ascending: false});
}

 

注意

基本的な所は前回の【GAS】OCRを使った画像の文字取得を自動化すると同じなので、先に必ずこちらをご覧ください

その他、前回から変更のあった点を補足します。

 

フォルダIDの指定

var picFolderId = PropertiesService.getScriptProperties().getProperty('picFolderId');

GoogleドライブフォルダのIDを指定する箇所があり、そこに直接IDを書き込んでもよいのですが、このようにコードから見えないようにする方法もあります。

これがフォルダのIDです。

folderID

スクリプトのエディタ画面のココをクリックすると

fileMenu

 

こんな画面になるので、このように入力します。

prop

ここに入れた値は PropertiesService.getScriptProperties().getProperty(‘プロパティ名’)で取得することができます。

コードを公開したいけどIDやトークン等、見られたくないものがある時に使いましょう。

 

ファイルがドライブに追加された日時を取得する

var createDateRaw = image.getDateCreated();
var createDate = Utilities.formatDate(createDateRaw,"JST","YYYY/MM/dd HH:mm");

これで追加された日時を取得することができます。あくまでもGoogleドライブに追加された日時の取得です。

Class File| Apps Script | Google Developers

 

配列に「日時」と「ファイル名」と「OCRで取得した文字」を格納する

var titleAndText = [];
~~省略~~
titleAndText.push([createDate, docName, text]);

予め空の配列を作っておき、そこに「ファイル追加日時」「ファイル名」「OCRで取得した文字」を配列として格納し、2次元配列にします。

 

配列をスプレッドシートに渡して並び替えをする

  sheet.getRange(1, 1, titleAndText.length, titleAndText[0].length).setValues(titleAndText);
  
  var range = sheet.getDataRange()
  range.sort({column: 1, ascending: false});

あとはシートに配列をセットして、並び替えをするだけです。

 

今回はファイル追加日の新しい順に並べてますが、適宜置き換えて使ってみてください。

 

今回読み取りに使った画像はこちらです。

ファックス

メール

会社名

電話

これを実行するとこのようになりました。

sheet

前回のものよりはもう少し実用的になったかと思います。

おもしろい使い方がありましたらコメント等で教えてください。

 

その他、スプレッドシートやGASに関する記事はこちらからどうぞ。

Google Apps Script はじめました

GASを使ってGmailから本文の一部を抜き出す

スプレッドシート独自の便利な関数

QUERY関数の便利な使い方

スプレッドシートを使って簡単なスクレイピングをしてみよう

【GAS】正規表現を使ってGmailの本文から文章を抜き出す

【簡単】GASでスプレッドシートの送信リストからメールを送る

【GAS】正規表現を使って複数行の文章をGmailから抜き出す

【GAS】Gmailの受信トレイにあるメールの添付ファイルを自動でGoogleドライブへ保存する

【難しくない】GASでwebスクレイピングして正規表現でデータを集める

【GAS】OCRを使った画像の文字取得を自動化する

【GAS】お手軽なOCRの自動化をスプレッドシートで扱いやすくする

ReactとFirebase(Cloud Firestore)を使って独り言WEBアプリをつくる

 

それでは!


この記事の作者

アバター
ヨシモト


総記事本数:17

この記事へのコメント

    • 札幌のななっしー さん
      2020年1月25日 6:22 PM
    • 返信

    こんにちは。
    プログラムなどなにも分からず、
    たどり着いたこのページで、私がやりたいと思っていたことを実現されておられ、
    感動に打ち震えています。

    早速実装させていただいたのですが、
    > 無効な引数: id(行 33、ファイル「コード」)
    と表示され、スクリプトが止まります。
    > DriveApp.getFolderById(picFolderId).removeFile(file);
    の部分です。
    documentがfolderで指定されたフォルダに一個作られて止まります。

    お暇がございましたら、不明点ご教示いただければ幸いです。
    スクリプトはマイドライブに置き、サブディレクトリの写真を読みに行っています。
    よろしくお願いいたします。

      • 揚げたてエビフライ さん
        2020年1月25日 10:05 PM

      自分はちゃんと動いたんですが、内容を見て
      「picFolderId」をちゃんと設定してないのかな?と思ったので、
      試してみたところ、同じ現象が発生したので解説のお手伝いを。

      このページのヨシモト様の説明で「フォルダIDの指定」の仕方が書かれてますが
      こちらの設定がされていないか、設定した文字が間違っているかだと
      思います。

      本当に素晴らしいものを惜しみなく公開してくださっているので、
      是非動いて結果が得られた時の喜びを早く感じてほしいと思ってしまい、
      出しゃばってしまいました。

      • ヨシモト さん
        2020年1月27日 4:05 PM

      札幌のななっしー さん

      コメントありがとうございます。
      手軽にこういうことができるのですごい世の中ですよね。

      さて、
      ————–
      早速実装させていただいたのですが、
      > 無効な引数: id(行 33、ファイル「コード」)
      >と表示され、スクリプトが止まります。
      > DriveApp.getFolderById(picFolderId).removeFile(file);
      の部分です。
      ————–
      こちらについてですが、
      DriveApp.getFolderById(picFolderId).removeFile(file);
      の中で引数がidとして認識されるのは
      getFolderById(picFolderId) の部分で、
      揚げたてエビフライ さんの仰るように、
      picFolderId がうまく設定されていないと思われます。

      本コードでpicFolderIdを設定しているのが
      var picFolderId = PropertiesService.getScriptProperties().getProperty(‘picFolderId’);
      にあたり、解説にもあるように、コード外でフォルダのIDを設定しております。
      これはコード内に直接「ID」や「パスワード」などを書いて、「うっかりIDやパスワードを外部に晒してしまう」ことを防ぐために行っているものですが、
      var picFolderId = ‘フォルダのID’;
      または
      DriveApp.getFolderById(‘フォルダのID’).removeFile(file);
      と直接書いても同じ動作をするのでこのように置き換えて実行してみてください。
      ※コードを公開してID等が漏れなければ問題ありません。

    • 揚げたてエビフライ さん
      2020年1月25日 10:06 PM
    • 返信

    理想的なコードを公開して下さり、本当にありがとうございます。
    色々と勉強になります。
    最初にDoc化の自動化だけ拝見して「これがスプレッドシートに
    出せればSQL関数もあるし、色々できるのに!!」と思っていたところ…
    作られていて、本当に驚きました。

    プライベートでの利用予定でしたが、
    仕事でも色々と使えそうなので、書類化したり
    色々作りこめそうです!

    また、記事の配分、説明、画像の入れ方などが適度で
    とても見やすくて、助かりました。

    本当に素晴らしいものをありがとうございました!

    今後とも応援しております。

      • ヨシモト さん
        2020年1月27日 4:23 PM

      揚げたてエビフライ さん

      コメントありがとうございます。

      業務でレシートの内容をスプレッドシートで管理する必要が出そうだったのと、
      GoogleDriveでOCRの変換ができるという記事を思い出して、
      それならGASで出来るかも、と思ったことがきっかけでした。
      おっしゃる通りこれは作り込めば応用も広く効くので色々試したいですね。

      また、こういった解説は性質上の読みづらさもあったりするので、
      なるべく読みやすくなるようには心がけております。

      これからもおもしろそうなことをご紹介できたらと思います。
      ありがとうございました。

    • 札幌のななっしー さん
      2020年1月28日 1:06 PM
    • 返信

    ヨシモト様
    揚げたてエビフライ様

    わざわざコメントありがとうございます。
    フォルダIDを入れていないのではというご指摘、
    ソースの中に記載させていただいて、かようなエラーが出ています。
    IDを隠す場合のも行いましたが、sheet.getRangeの部分でエラーを吐いて止まります。

    ご参考にされた
    https://qiita.com/ttake/items/77f25a9c357ff2327868 は動きました。
    http://www.initialsite.com/w01/14488 は動きませんでした。
    スプレッドシートが入るとダメっぽいです。

    私のリテラシーが低い所以ですので諦めます。
    わざわざお時間を割いていただきありがとうございました。

      • ヨシモト さん
        2020年1月28日 5:32 PM

      札幌のななっしー さん

      蒸し返すようで申し訳ありませんが、
      >>IDを隠す場合のも行いましたが、sheet.getRangeの部分でエラーを吐いて止まります。
      こちらを拝見するにもともと原因は複数あって、
      ひとつはフォルダID。
      ソースに記載して上記のエラーが出たということは、最初におっしゃっていたエラーはクリアしています。
      そして
      sheet.getRange(1, 1, titleAndText.length, titleAndText[0].length).setValues(titleAndText);
      で止まるということは、
      ID以外にもエラーがあったということですので、
      デバッグボタン(虫のマーク)で実行し、各変数に何が入っているか(入っていないのか)を確認しましょう。
      エラーメッセージに書かれた部分を見るのが一番良いです。
      スプレッドシートの処理がなければ問題ないのでしたら、スプレッドシートの処理を一つずつ見直しましょう。
      「○○を△△すれば動きますよ」と全てお答えできたら良いのでしょうけど、
      スプレッドシートやスクリプト、対象の画像など、全部見てみないと全ては解決できませんし、さすがにそういうわけにもいかないので、、、。
      エラーメッセージってわかりにくいように思えるかもしれませんが、
      何がうまくいっていないのかピンポイントで教えてくれているのでそこを直せば次に進みます。

      正直な所、このスクリプトは実行環境や対象物によっては書き換える必要もあるでしょうから、
      適宜ご自身の環境に適合するようにどんどん書き換えてみてください。

      明確な回答でなくて申し訳ありませんが、
      一カ所ずつ検証するつもりで臨めば動きますのでなんとかしてみましょう。
      良いご報告お待ちしております。

    • にゃお さん
      2020年1月28日 3:27 PM
    • 返信

    お世話になります。
    この素晴らしいコードを使用したく、コピペさせていただき実行したのですが
    「TypeError: undefined からプロパティ「length」を読み取れません。」となってしまいます。
    どういった可能性が考えられますでしょうか。
    宜しくお願いします。

    • にゃお さん
      2020年1月28日 3:49 PM
    • 返信

    自己レスです
    「var images = folder.getFilesByType(‘image/jpeg’);」
    に書き換えましたらうまく動きました。
    当方の不注意で申し訳ありません。
    ありがとうございました。

      • ヨシモト さん
        2020年1月28日 5:39 PM

      にゃお さん

      コメントありがとうございます。
      動いたようで良かったです。
      私が扱ったファイルがpngだったのでこのようにしていますが、拡張子によって変える必要がありますね。
      この記事は応用編ですが、ひとつ手前段階の記事の方がこちらよりも多少解説がありますのでよろしければご覧ください。
      http://www.initialsite.com/w01/14488

    • 札幌のななっしー さん
      2020年1月30日 2:51 PM
    • 返信

    ヨシモト様

    私が至らないばかりに、お手間を取らせて大変申し訳ないです。
    もう大丈夫です。動かないものは動かないので。。

      • むっく さん
        2020年5月7日 5:24 PM

      札幌のななっしー さん
      同じところでひっかかったものです
      スプレッドシート上で実施しないと同じ事になりました。
      過去の記事を振り返ったらできました!

コメントをどうぞ

おすすめ記事

  1. 2af1a7d9bbe73319a6c346c407cdefbf_m
    リモートワークに移行します
  2. ウィルス画像
    横浜のブラック企業 Initial Site(イニシャルサイト)からコロナウイルスで考えたこと。B…
  3. E5DxwzVgVHYHr411581668296_1581668370
    わたしは公家ではありませんでした(多分)
  4. 1b8493ba94ff68762824c3c7274b3128-e1499313795652
    イオンの保存容器はジップロック超えた!?※主観的視点