GASとClaudeでGmailから複数のPDFを集めて1つのPDFにマージする

  • URLをコピーしました!

※小樽→札幌方面のJRの車窓から(海は日本海) – by Canon RP(RF35mm f 2.2 1/1100 ISO100)

こちらの意図しないところで、システムの仕様変更などがあると、今まで不便に感じていなかったことが、突然面倒になることがあります。

それを解消するのに、すべてをAIだけにお願いできないこともあります。
今回はひとつの例として、GASとAI(Claude)を組み合わた方法をまとめてみました。

※ただいまメルマガ読者を募集しています(ご登録はこちら)

目次

仕様変更で月1回→都度メール方式に

移動にはシェアサイクルをちょこちょこ使っています。Docomoが運営するポロクルです(地域によって名称は違うようですが)。

そのシェアサイクルの領収書はスマホのアプリから、「領収書発行」ボタンをタップすると、登録メールアドレス(わたしはGmailのアドレス)にメールが届き、リンク先のURLから領収書のPDFデータをダウンロードできます。

このダウンロード。
7月までは、1か月分の利用分をまとめた1つの領収書をダウンロードできました。

ただ、運営側のシステムの仕様変更?があったのかはわかりませんが、8月分からは、それができなくなっていたのです。

「領収書発行」ボタンをタップして、Gmailにメールが届く仕組みは変わりありませんが、8月分からは、1か月分をまとめた領収書ではなく、利用1回につき、1つのリンク(領収書も)が発行されるように…。

このように、一か月間で8回利用したとすると、領収書ダウンロードするリンクも8つ発行されるのです。

仮に1日2往復で15日間利用したとすると、合計30個のリンクがGmailに届くわけで、領収書が必要なら、リンクを30回クリックしなければなりません。

これはさすがに手間が…。

こういうときに、AIに「Gmailのリンクから領収書のPDFデータをダウンロードして」とか、「8個のPDFを1つのPDFにマージして」とお願いすることもできます。

今回は、GASとAI(Claude)で一連の流れをお願いしてみました。

GmailのダウンロードリンクはGASで取得

今回の事例でやりたいことは次の手順を自動化することです。

1.Gmailからダウンロードリンク(8個)を見つける
2.各ダウンロードリンクから領収書PDFを取得→ダウンロードする
3.取得した8個のPDFを1ファイルにマージ
4.マージしたPDFにわかりやすい名前を付ける
5.指定したフォルダに保存

ClaudeとGmailを連携すれば、1(該当のGmailを見つける)ところは、やってもらえます。

ただ、わたしがClaudeで試してみた場合だと、2(ダウンロードリンクから領収書PDFを取得→ダウンロード)の「ダウンロード」は、URLの記述が長くて、記号も紛らわしい(1とI、Oと0など)ので、1文字でも間違うとダウンロードできないという回答が…

なので、1と2は、別の方法でPDFをダウンロードしてから、3~5をClaudeでお願いすることに。

1.【GAS】Gmailからダウンロードリンク(8個)を見つける
2.【GAS】各ダウンロードリンクから領収書PDFを取得→ダウンロードする
3.【Claude】取得した8個のPDFを1ファイルにマージ
4.【Claude】マージしたPDFにわかりやすい名前を付ける
5.【Claude】指定したフォルダに保存

1と2は、Gmailと相性のいいGASにしました。 Googleドライブには、あらかじめダウンロードするPDFの保存先となるフォルダをつくっておきます。

GASのコードは、Claudeで書いてくれます。
(コードはこちらにコピーを載せておきます)

GASのコード
/**
 * 【概要】
 * Gmailに届く「バイクシェアサービス(ポロクル/docomo-cycle)」の
 * 領収書発行通知メールを検索し、本文中のダウンロードURLからPDFを取得して
 * 指定のGoogle Driveフォルダに保存するスクリプトです。
 *
 * 【事前準備】
 * 1. Google Drive「ポロクル領収書」フォルダのID(下記 FOLDER_ID)は
 *    設定済みです。変更したい場合はここを書き換えてください。
 * 2. Gmail側でこのラベルを1つ作成しておいてください(初回実行時に
 *    自動作成されるので、事前作成は不要です)。
 *      ラベル名: ポロクル領収書取込済み
 *
 * 【使い方】
 * 1. Google Apps Script(script.google.com)で新規プロジェクトを作成
 * 2. このコードを貼り付けて保存
 * 3. 関数 saveBikeShareReceipts を選択して「実行」
 * 4. 初回はGmail/Driveへのアクセス許可を求められるので許可する
 * 5. 以後は「トリガー」機能で定期実行(例: 毎日1回)に設定すると自動化できます
 */

// ↓ Google Driveの保存先フォルダID(「ポロクル領収書」フォルダ)
var FOLDER_ID = '1qaTpXc6mvAoVZjc5ibQmfvCLTPRsb7U2';

// 処理済みメールに付けるGmailラベル名(重複ダウンロード防止用)
var PROCESSED_LABEL_NAME = 'ポロクル領収書取込済み';

// 領収書ダウンロードURLの検出パターン
// 例: https://csapi.docomo-cycle.jp/invoice/receipt/PRC/202608/PRC20260800000519490.pdf?Expires=...&Signature=...&Key-Pair-Id=...
var URL_PATTERN = /https:\/\/csapi\.docomo-cycle\.jp\/invoice\/receipt\/[A-Za-z0-9]+\/\d+\/[A-Za-z0-9]+\.pdf\?[^\s]+/g;

function saveBikeShareReceipts() {
  var label = getOrCreateLabel_(PROCESSED_LABEL_NAME);
  var folder = DriveApp.getFolderById(FOLDER_ID);

  // 「バイクシェアサービス」の領収書発行通知メールのうち、未処理のものを検索
  var query = 'from:cs_system_notification@docomo-cycle.jp subject:領収書 -label:"' + PROCESSED_LABEL_NAME + '"';
  var threads = GmailApp.search(query);

  if (threads.length === 0) {
    Logger.log('未処理の領収書メールはありませんでした。');
    return;
  }

  var totalSaved = 0;

  threads.forEach(function (thread) {
    var messages = thread.getMessages();

    messages.forEach(function (message) {
      var body = message.getPlainBody();
      var urls = body.match(URL_PATTERN);

      if (!urls || urls.length === 0) {
        return;
      }

      urls.forEach(function (url) {
        try {
          var response = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
          if (response.getResponseCode() !== 200) {
            Logger.log('ダウンロード失敗(HTTP ' + response.getResponseCode() + '): ' + url);
            return;
          }

          var blob = response.getBlob();
          var filename = extractFilenameFromUrl_(url);
          blob.setName(filename);

          // 同名ファイルが既にある場合は重複保存しない
          if (folder.getFilesByName(filename).hasNext()) {
            Logger.log('既に保存済みのためスキップ: ' + filename);
            return;
          }

          folder.createFile(blob);
          totalSaved++;
          Logger.log('保存しました: ' + filename);
        } catch (e) {
          Logger.log('エラー: ' + url + ' / ' + e);
        }
      });
    });

    // 処理済みラベルを付与(次回以降このメールは検索対象から除外される)
    thread.addLabel(label);
  });

  Logger.log('完了。' + totalSaved + '件のPDFを保存しました。');
}

// URLからファイル名(例: PRC20260800000519490.pdf)を抽出
function extractFilenameFromUrl_(url) {
  var match = url.match(/([A-Za-z0-9]+\.pdf)/);
  if (match) {
    return match[1];
  }
  return 'receipt_' + Utilities.getUuid() + '.pdf';
}

// ラベルが無ければ作成して返す
function getOrCreateLabel_(labelName) {
  var label = GmailApp.getUserLabelByName(labelName);
  if (!label) {
    label = GmailApp.createLabel(labelName);
  }
  return label;
}

このコードをGASの画面にコピペして保存(上部の関数選択欄が 「saveBikeShareReceipts」になっていることを確認)して、実行をクリック。

すると、8個のリンク先からでも一瞬でダウンロードして保存できます。

ここまでが
1.【GAS】Gmailからダウンロードリンク(8個)を見つける
2.【GAS】各ダウンロードリンクから領収書PDFを取得→ダウンロードする

までの流れです。

次(3~5まで)の工程は、Claudeにお任せします。

3.取得した8個のPDFを1ファイルにマージする
4.マージしたPDFにわかりやすい名前を付ける
5.指定したフォルダに保存

5まで完了したら、指定したフォルダに、保存してくれます。 このように、1/8ページ目があるので、8つのPDFを1つにマージしてくれています。

ただ、ここまできて言うのも非常に何なのですが、正直、3(取得した8個のPDFを1ファイルにマージする)は、Adobeを有料プランで使っているなら、Adobe Acrobatでマージしたほうが早いかと(今回のClaudeだと50分くらいかかりました。わたしのやり方の問題もあるかもしれませんけど…)。

こういうのを「AI時間泥棒」と言うらしいのですが、その間に違う仕事を進められる限りは、そんなこともないのかなぁと。

といっても、AIにどこまでをお任せするかの判断は大事です。

AIを絶対使わないといけないわけではないですし、自分(人間)が時間をかけたいことに時間を使えるようになることが大前提ですから。

AIとアプリと組み合わせたほうが自分の時間をつくりやすいなら、それはそれでいいのではないかと。

相手都合で仕組みが変わることはある、そのために変わらず勉強する

AIに何かとお願いできる時代。
お願いすれば、すぐに答えてくれますし、資料づくりもチェックも一瞬でやってくれます。

今回の事例でも、領収書を発行する単位が、1カ月単位→都度単位に変わったことがきっかけで、AIに解決策をお願いしました。

ただ、その際のAIとのやりとりの中で感じたことは、お願いできることが増えたとはいえ、基本的な知識・スキルが前提にあるのと、ないのとでは、時間のかかり具合も変わってくるということです。

・コードを書けるようになる ⇄ 書いたことがない
・コードを多少は読めるようになる ⇄ まったく読めない
・IT用語に触れても平気 ⇄ 触れたら蕁麻疹がでる(苦手)
・データを整理する ⇄ 紙を整理する
・文章を書く ⇄ 書けない
・写真を撮る ⇄ 写真をつくってもらう

どこまでをAIにお願いしたいか?は人それぞれ。

わたしは、仮にAIがやってくれることだとしても、ITの知識・スキルは今も勉強しています。

AIにお願いしても、たまに余計なことを書くことはありますし、いざ動かしてみるとエラーになることもあります。
AIにエラーの原因を調べてもらったところ、単純なタイプミスに気づいたこともあります。

そうしたやりとりが勉強になっていることもざらにあるわけで。

ITスキルを磨きたいという気持ちでいられ続けているのは、これまでも、ブログやHPを自分でつくったり、Excelを手を動かしながら勉強してきたことが大きいです。

AIに頼るにしても、頼りすぎず、自分で判断できるスキルも磨いておきたいなと。

こういう時代だからこそ、足元を見て勉強する。
錆びつかせないほうがいいのかなと、と。

ちなみに、資格をとることを口実にして、勉強するのもおすすめです(先日、とある資格試験の受験を申し込みしました)。

参考になればうれしいです。


■編集後記
昨日は朝タスクと家事、
朝から外出して会計士業を
移動はJR。朝なので混んでましたがなんとか

■昨日の1日1新
・えきねっと(再登録)
・おたる番屋

■息子(12歳)
学校の給食も完食
いつも美味しいメニューのようで(親のほうでも1度食べてみたいなぁと)
(きのうの給食 688kcal:ごはん、じゃがべーじる、ちくぜんに、マヨぽんあえ)


この記事が気に入ったら
フォローしてね!

  • URLをコピーしました!
目次