DocumentDrive

【GAS】PDFからテキスト抽出(OCR) メール添付の請求書PDFを保存してチャットに通知⑦

前回のおさらい

前回はチャットに通知するためのメッセージを作成しました。

メッセージを作成するために税抜請求額、税込請求額、請求書を発行した会社名、請求書のURLが必要でしたので、これらをGASを使って取り出していきました。

最後にテンプレートリテラルを使ってメッセージをつくりました。

会社名はメッセージオブジェクトからgetFromメソッドを使って取り出しました。

const fromName = message.getFrom()

請求書のURLはGoogleドライブのファイルオブジェクトからgetDownloadUrlメソッドを使って手に入れました。

const invoiceUrl = invoiceFile.getDownloadUrl()

そして最後にテンプレートリテラルを使ってメッセージを作成しました。

const chatMessage =
`${companyName}の請求書が届きました。\n${taxNotIncluded} ${taxIncluded}\n以下のURLからダウンロードしてください。\n${invoiceUrl}`

コード全体としてはこのようになっています。

const searchGmail = () => {
  const gmail = GmailApp
  const searchedMail = gmail.search('from:株式会社 インボイス送信元 subject: 【請求書】送付のご案内 is:unread')
  const messages = searchedMail.map(thread => {
    return thread.getMessages()
  })
  const message = messages[0][0]

  // 本文から税抜請求額と税込請求額を取得
  const messageBody = message.getPlainBody()
  const taxNotIncluded = messageBody.match(/税抜請求額.*$/m)[0]
  const taxIncluded = messageBody.match(/税込請求額.*$/m)[0]

  // 添付ファイルの取得とドライブへの保存
  const attachments = message.getAttachments()
  const drive = DriveApp
  const folder = drive.getFolderById('フォルダIDが入ります')
  const invoiceFile = folder.createFile(attachments[0])
  
  // チャット通知用のメッセージをつくる
  const fromName = message.getFrom()
  const companyName = fromName.match(/"([^"]*)"/)[1]
  const invoiceUrl = invoiceFile.getDownloadUrl()
  const chatMessage = `${companyName}の請求書が届きました。\n${taxNotIncluded} ${taxIncluded}\n以下のURLからダウンロードしてください。\n${invoiceUrl}`
  console.log(chatMessage)
}



今回はGoogleドライブに保存したPDFファイルからOCRでテキストを読み出します。

ついでにファイル名も「請求年月+会社名+請求書」としちゃいます。


レッツラゴー

DriveAPIサービスを使ってPDFファイルのテキストを読み取る

OCRをするにはDriveAPIサービスを使います。DriveAppではなく、DriveAPIサービスです。

DriveAPIサービスを追加する

DriveAPIサービスを使うには事前準備が必要です。

左のメニューの「サービス」を選択します。


DriveAPIサービスを選択して追加します。バージョンはv2にします。(デフォルトはv3)


このようにDriveAPIサービスが追加されていたら成功です。

Drive.files.copyメソッドを使う

DriveAPIにあらかじめ用意されているDrive.files.copyメソッドを利用します。

OCRで読み出したテキストはGoogleドキュメントとして保存されます。

OCRでPDFを読み取ってGoogleドキュメントとして保存

const document = Drive.Files.copy({ title: 'テスト' }, invoiceFile.getId(), { ocr: true })
console.log(document)


実行結果


さらにGoogleドライブの請求書フォルダ内はこのようになっています。


Drive.files.copyメソッドは第1引数にresource(ファイルのメタ情報等)、第2引数にファイルID、第3引数にオプションをとります。

ここでは第1引数にファイル名、第2引数にPDFファイルのファイルID、第3引数にOCRを有効にするオプションを設定しました。

ファイル名の指定

{ title: 'テスト' }, // オブジェクトの形式でタイトル(ファイル名)をわたす


PDFファイルのファイルID

invoiceFile.getId() // ファイルオブジェクトのgetIdメソッドでIDを取得


OCRの有効化

{ ocr: true } // オブジェクトの形式でocrオプションをわたす

作成されたGoogleドキュメントからテキストを取得する

OCRで読み出されたテキストは「テスト」というGoogleドキュメントに入ってます。

テキストを読み出すにはGoogleドキュメントのメソッドを使います。

一連の手順はこうなります。

  const documentApp = DocumentApp
  const documentFile = documentApp.openById(document.id)
  const documentBody = documentFile.getBody()
  const text = documentBody.getText()
  console.log(text)

★それぞれのクラス、メソッドの説明★

DocumentApp ー Googleドキュメントオブジェクトをつくる

openById ー ドキュメントのファイルIDからドキュメントファイルオブジェクトをつくる

getBody ー ドキュメントファイルオブジェクトから本文部分を取得する

getText ー 本文部分からテキストを取得する


実行結果

請求月(上の例では2024年3月分)のテキストを取得する

条件を指定してテキストの取得をするならmatchメソッドと正規表現です。

const invoiceDate = text.match(/(\d{4}年\d{1,2}月分)/)[1]
console.log(invoiceDate)


matchメソッドの戻り値は値の配列が戻り値となっておりましてマッチしたテキストは配列の2番目(インデックスは1)に入ってます。

そこでmatchメソッドが書かれた行の末尾を[1]としているんですね。


実行結果


はい、ちゃんととれてます。

忘れずにテンプレートリテラルも変更しておきます。

const chatMessage = `${companyName}の${invoiceDate}請求書が届きました。\n${taxNotIncluded} ${taxIncluded}\n以下のURLからダウンロードしてください。\n${invoiceUrl}`
  console.log(chatMessage)

実行結果



で、せっかく請求月をとりましたのでPDFファイルのファイル名を以下のようにしましょう。

2024年3月分 株式会社 インボイス送信元 請求書

PDFのファイル名を変更する

ファイル名を変更するのに必要な材料は請求月と会社名です。それぞれどの変数に格納されているか確認です。

請求月:invoiceDate

会社名:companyName


で、これをテンプレートリテラルを使いまして、うまいことファイル名になるように仕立て上げると、、、

invoiceFile.setName(`${invoiceDate} ${companyName} 請求書`)

setNameメソッド ー ファイルオブジェクトのファイル名を変更するメソッド

構文:ファイルオブジェクト.setName(‘ファイル名’)

戻り値:ファイルオブジェクト

参照)Google Apps Scriptのマニュアル ファイルクラス


実行してみて請求書フォルダにこのようなファイルがあれば成功です。


最後に不要なGoogleドキュメントファイルを削除

請求書フォルダを見ると「テスト」というGoogleドキュメントファイルがあります。

もう用済みなので、このファイルは消しちゃいましょう。

const removingFile = drive.getFileById(document.id)
removingFile.setTrashed(true)

setTrashedメソッド ー Googleドライブのファイルオブジェクトをゴミ箱に移動するメソッド

構文:ファイルオブジェクト.setName(boolean) ※trueはゴミ箱行き、falseはゴミ箱に行かない

戻り値:ファイルオブジェクト

参照)Google Apps Scriptのマニュアル ファイルクラス


実行すると請求書フォルダはこのようになりました。

必要なPDFファイルだけが保存された状態です。


あらためて全体のコードを見てみますとこのようになっています。

const searchGmail = () => {
  const gmail = GmailApp
  const searchedMail = gmail.search('from:株式会社 インボイス送信元 subject: 【請求書】送付のご案内 is:unread')
  const messages = searchedMail.map(thread => {
    return thread.getMessages()
  })
  const message = messages[0][0]

  // 本文から税抜請求額と税込請求額を取得
  const messageBody = message.getPlainBody()
  const taxNotIncluded = messageBody.match(/税抜請求額.*$/m)[0]
  const taxIncluded = messageBody.match(/税込請求額.*$/m)[0]

  // 添付ファイルの取得とドライブへの保存
  const attachments = message.getAttachments()
  const drive = DriveApp
  const folder = drive.getFolderById('フォルダIDが入ります')
  const invoiceFile = folder.createFile(attachments[0])
  
  // チャット通知用メッセージの材料を集める
  const fromName = message.getFrom()
  const companyName = fromName.match(/"([^"]*)"/)[1]
  const invoiceUrl = invoiceFile.getDownloadUrl()
  
  // PDFからOCRでテキストを取り出す
  const document = Drive.Files.copy({ title: 'テスト' }, invoiceFile.getId(), { ocr: true })
  const documentApp = DocumentApp
  const documentFile = documentApp.openById(document.id)
  const documentBody = documentFile.getBody()
  const text = documentBody.getText()
  const invoiceDate = text.match(/(\d{4}年\d{1,2}月分)/)[1]
  invoiceFile.setName(`${invoiceDate} ${companyName} 請求書`)

  // 通知用のメッセージをつくる ※位置を上から移動
  const chatMessage = `${companyName}の${invoiceDate}請求書が届きました。\n${taxNotIncluded} ${taxIncluded}\n以下のURLからダウンロードしてください。\n${invoiceUrl}`
  console.log(chatMessage)
  
  // 不要なGoogleドキュメントファイルを削除する
  const removingFile = drive.getFileById(document.id)
  removingFile.setTrashed(true)
}


ひゃー、いっぱい書いてありますね。なんだか難しそうです。

でもやっていることは単純です。ほしい情報を取り出すために順番にオブジェクトを取得していっているだけなんですよ。


次回はチャットツールに通知します。世の中、たくさんのチャットツールがありますが、いくつかの代表的なツールでの通知方法を紹介します。

とりあえずslackかなぁー。


ハスタラビスタベイビー

Copied title and URL