Gemini note

【Adobe Scan活用術】Adobe ScanとGoogle Driveでレシート管理

こちらの記事は2025年4月4日noteに投稿した内容です。

皆さんは領収書やレシートの管理に悩んだことはありませんか?財布の中に溜まっていく紙のレシート、確定申告や経費精算の時期になると探し出すのに苦労する経験は多くの方が持っているのではないでしょうか。

本記事では、Adobe ScanとGoogle Driveを連携させた効率的なレシート管理システムをご紹介します。スマートフォン一つで撮影からデータ化、整理までの一連の流れを自動化することで、レシート管理の手間を大幅に削減できます。個人事業主の方や会社での経費精算が多い方はもちろん、家計管理に活用したい方にもおすすめの方法です。

0. 準備

まずは必要なアカウントを用意しましょう。このシステムを利用するには、AdobeとGoogleの両方のアカウントが必要です。

  • Adobeアカウントの取得:まだ持っていない場合は、Adobe公式サイトから無料で作成できます。Adobe IDがあれば、Adobe Scanを含む様々なAdobe製品の基本機能を利用できます。
  • Googleアカウント取得:すでにお持ちの方も多いと思いますが、Gmail、Google Drive、Google Spreadsheetなどのサービスを利用するために必要です。こちらも無料で作成可能です。

1. Adobe Scanについて

Adobe Scanとは

Adobe Scanは、Adobeが提供する高性能なモバイルスキャンアプリです。スマートフォンのカメラを使って、書類やレシートなどを簡単にデジタル化できます。単なる写真ではなく、PDFとして保存され、OCR機能によってテキスト検索も可能になります。

Adobe Scanは以下からダウンロードできます。

Google Play
App Store

Adobe Scanの優れた点

  1. 自動認識と切り取り機能: Adobe Scanはレシートの境界を自動的に検出し、適切に切り取ってくれるため、手動で調整する手間が省けます。これにより、レシートの形状が歪んでいてもきれいにスキャンできます。
  2. 高品質な画像処理: 照明や影を補正し、テキストを鮮明にする機能が優れているため、レシート上の細かい文字や数字が読みやすくなります。
  3. OCR(文字認識)機能: スキャンしたレシートからテキストを自動的に抽出できるため、金額や店名などの情報をデジタル化して管理しやすくなります。
  4. Google Driveとの統合: スキャンしたレシートをPDF形式で直接Google Driveに保存できるため、クラウド上で簡単に整理・共有が可能です。
  5. 複数ページのスキャン対応: 複数のレシートを連続で撮影しても、一つのPDFファイルにまとめて保存できるので、効率的に管理できます。
  6. 使いやすいインターフェース: シンプルで直感的な操作性が特徴で、レシートを素早くスキャンして保存するのに時間をかけません。
  7. 無料で基本機能が利用可能: 基本的なスキャン機能は無料で利用できるため、コストをかけずにレシート管理が始められます。

これらの点から、Adobe Scanはレシートのデジタル化とGoogle Driveでの保存に非常に適したツールと言えます。

2. Adobe Scanの設定

初期ファイル名の設定

効率的なレシート管理のために、ファイル名の設定は重要です。Adobe Scanでは、保存するファイルの命名規則を設定できます。

レシート管理に最適なファイル名の形式は「日付(YYYY-MM-DD)_取引先_金額」です。この命名規則を使うことで、ファイル名だけで重要な情報が一目で分かるようになります。

例えば、「2025-04-04_コンビニA_580」というファイル名があれば、2025年4月4日にコンビニAで580円の支払いをしたことが瞬時に理解できます。

3. Google Driveの準備

レシートの管理をスムーズに行うために、Google Drive内に専用のフォルダを作成しましょう。

  1. Google Driveにログインします。
  2. 「新規」ボタンをクリックし、「フォルダ」を選択します。
  3. フォルダ名を「レシート管理」など分かりやすい名前にして作成します。

このフォルダにAdobe Scanでスキャンしたレシートのデータを保存していきます。一箇所にまとめることで、後々の管理や検索が簡単になります。

4. Google Spreadsheetの準備

レシートの情報を一覧で管理するため、Google Spreadsheetを作成します。

  1. 先ほど作成した「レシート管理」フォルダ内で「新規」ボタンをクリックし、「Google スプレッドシート」を選択します。
  2. ファイル名を「レシート管理表」など分かりやすい名前に変更します。
  3. ここでは1行目に以下のようにタイトルを入力します:
    • A列: No
    • B列: Date
    • C列: Company
    • D列: Amount
    • E列: Filename

この表に、スキャンしたレシートの情報が自動的に記録されるようにしていきます。

5. Google Apps Scriptの作成

レシートの情報を自動的にスプレッドシートに記録するため、Google Apps Scriptを作成します。

  1. 作成したスプレッドシートで、上部メニューの「拡張機能」→「Apps Script」をクリックします。
  2. 以下のようなスクリプトを入力します(実際の使用時には、フォルダIDなどの設定変数を自分の環境に合わせて修正してください):

フォルダIDは、Google DriveのフォルダURLのfolders/以降です。
https://drive.google.com/drive/folders/この部分がフォルダID

シートIDは、Spread Sheet URLのd/から/edit?の間の部分です。
https://docs.google.com/spreadsheets/d/この部分がシートID/edit?gid=0#gid=0

/**
 * 領収書PDFファイルからファイル名を解析して情報を抽出し、スプレッドシートに記録するスクリプト
 * 
 * 使用方法:
 * 1. FOLDER_ID にGoogleドライブの監視したいフォルダIDを設定
 * 2. SPREADSHEET_ID に情報を記録するスプレッドシートのIDを設定
 * 3. トリガーを設定して一定間隔で実行(例: 1時間ごと)
 * 
 * ファイル名の形式: YYYY-MM-DD_会社名_金額.pdf
 */

// 設定変数
const FOLDER_ID = 'Google Drive フォルダID'; // 領収書PDFが保存されるフォルダID
const SPREADSHEET_ID = 'Google Spread Sheet シートID'; // 情報を記録するスプレッドシートID
const SHEET_NAME = 'Spread Sheet シート名'; // シート名
const ADMIN_EMAIL = 'yourname@example.com'; // エラー通知先メールアドレス

/**
 * メイン実行関数 - 新しいPDFファイルを処理
 */
function processNewReceiptPDFs() {
  try {
    // スプレッドシートを取得
    const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
    const sheet = ss.getSheetByName(SHEET_NAME) || ss.insertSheet(SHEET_NAME);
    
    // シートのヘッダーが存在しない場合は作成
    ensureSheetHeaders(sheet);
    
    // 既存の記録を取得(ファイル名をキーとして)
    const existingRecords = getExistingRecords(sheet);
    
    // フォルダ内のPDFファイルを取得
    const folder = DriveApp.getFolderById(FOLDER_ID);
    const files = folder.getFilesByType(MimeType.PDF);
    
    let newEntriesCount = 0;
    let errorFiles = [];
    
    // 各PDFに対して処理
    while (files.hasNext()) {
      const file = files.next();
      const fileName = file.getName();
      
      // 既に処理済みのファイルはスキップ
      if (existingRecords.has(fileName)) {
        continue;
      }
      
      // ファイル名から情報を抽出
      const receiptData = extractInfoFromFileName(fileName);
      
      if (receiptData) {
        // 最後の行番号を取得
        const lastRow = sheet.getLastRow();
        
        // 現在の年月日を取得(YYYYMMDD形式)
        const today = new Date();
        const yyyymmdd = Utilities.formatDate(today, 'JST', 'yyyyMMdd');
        
        // 通し番号を作成(当日分をカウント)
        const todaysEntries = countTodaysEntries(sheet, yyyymmdd);
        const sequentialNum = (todaysEntries + 1).toString().padStart(3, '0');
        
        // No(YYYYMMDD+3桁通番)を作成
        const entryNo = yyyymmdd + sequentialNum;
        
        // スプレッドシートに記録
        sheet.appendRow([
          entryNo,
          receiptData.date,
          receiptData.company,
          receiptData.amount,
          fileName
        ]);
        
        newEntriesCount++;
      } else {
        errorFiles.push(fileName);
      }
    }
    
    // データを日付順に並べ替え
    if (sheet.getLastRow() > 1) {
      sortSheetByDate(sheet);
    }
    
    // ログに記録
    if (newEntriesCount > 0) {
      console.log(`${newEntriesCount}件の新しい領収書を処理しました。`);
    } else {
      console.log('新しい領収書はありませんでした。');
    }
    
    // エラーファイルがある場合はメール通知
    if (errorFiles.length > 0) {
      const errorMessage = `以下の領収書ファイルの処理に失敗しました:\n${errorFiles.join('\n')}`;
      sendErrorEmail('領収書処理エラー', errorMessage);
    }
    
  } catch (error) {
    console.error('エラーが発生しました:', error);
    sendErrorEmail('領収書トラッカー実行エラー', `エラー内容: ${error.toString()}`);
  }
}

/**
 * ファイル名から領収書情報を抽出
 * 想定フォーマット: YYYY-MM-DD_CompanyName_Amount.pdf
 */
function extractInfoFromFileName(fileName) {
  try {
    const fileNamePattern = /(\d{4}-\d{2}-\d{2})_([^_]+)_(\d+)/;
    const fileNameMatch = fileName.match(fileNamePattern);
    
    if (fileNameMatch && fileNameMatch.length >= 4) {
      const date = fileNameMatch[1];
      const company = fileNameMatch[2];
      const totalAmount = parseInt(fileNameMatch[3], 10);
      
      return {
        date: date,
        company: company,
        amount: totalAmount
      };
    } else {
      console.error('ファイル名から情報を抽出できませんでした:', fileName);
      return null;
    }
  } catch (error) {
    console.error('ファイル名解析エラー:', error);
    return null;
  }
}

/**
 * シートのヘッダーを確認し、必要に応じて作成
 */
function ensureSheetHeaders(sheet) {
  if (sheet.getLastRow() === 0) {
    // ヘッダー行を設定
    sheet.appendRow(['No', 'Date', 'Company', 'Amount', 'FileName']);
    
    // ヘッダーの書式設定
    sheet.getRange('A1:E1').setBackground('#f3f3f3').setFontWeight('bold');
    
    // 列幅の調整
    sheet.setColumnWidth(1, 120);  // No
    sheet.setColumnWidth(2, 100);  // Date
    sheet.setColumnWidth(3, 200);  // Company
    sheet.setColumnWidth(4, 100);  // Amount
    sheet.setColumnWidth(5, 300);  // FileName
  }
}

/**
 * 既存の記録を取得(ファイル名をキーとして)
 */
function getExistingRecords(sheet) {
  const records = new Set();
  
  if (sheet.getLastRow() <= 1) {
    return records; // ヘッダーのみの場合は空のセットを返す
  }
  
  // ファイル名の列(E列)からすべての値を取得
  const fileNames = sheet.getRange(2, 5, sheet.getLastRow() - 1, 1).getValues();
  
  // セットに追加
  fileNames.forEach(row => {
    if (row[0]) {
      records.add(row[0]);
    }
  });
  
  return records;
}

/**
 * 当日のエントリ数をカウント
 */
function countTodaysEntries(sheet, yyyymmdd) {
  if (sheet.getLastRow() <= 1) {
    return 0; // ヘッダーのみの場合は0を返す
  }
  
  // No列(A列)からすべての値を取得
  const noValues = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1).getValues();
  
  // 当日のエントリをカウント
  let count = 0;
  noValues.forEach(row => {
    const entryNo = row[0].toString();
    if (entryNo.startsWith(yyyymmdd)) {
      count++;
    }
  });
  
  return count;
}

/**
 * スプレッドシートをDate列で日付順に並べ替え
 */
function sortSheetByDate(sheet) {
  // データが2行未満(ヘッダーのみ)の場合は並べ替えをスキップ
  if (sheet.getLastRow() <= 1) {
    return;
  }
  
  try {
    // データ範囲を取得(ヘッダー行を除く)
    const dataRange = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
    
    // Date列(B列 = 2)で昇順に並べ替え
    dataRange.sort({column: 2, ascending: true});
    
    console.log('スプレッドシートを日付順に並べ替えました');
  } catch (error) {
    console.error('スプレッドシート並べ替えエラー:', error);
    sendErrorEmail('並べ替えエラー', `シートの並べ替え中にエラーが発生しました: ${error}`);
  }
}

/**
 * エラーメールを送信
 */
function sendErrorEmail(subject, message) {
  try {
    MailApp.sendEmail({
      to: ADMIN_EMAIL,
      subject: `[領収書トラッカー] ${subject}`,
      body: `領収書トラッカーで問題が発生しました。\n\n${message}\n\nタイムスタンプ: ${new Date().toLocaleString('ja-JP')}`
    });
    console.log('エラーメールを送信しました');
  } catch (error) {
    console.error('メール送信エラー:', error);
  }
}

/**
 * スプレッドシートの操作性を向上させるため、カスタムメニューを追加
 */
function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('領収書トラッカー')
    .addItem('新規領収書を処理', 'processNewReceiptPDFs')
    .addSeparator()
    .addItem('トリガー設定(自動実行)', 'showTriggerDialog')
    .addToUi();
}

/**
 * トリガー設定のダイアログを表示
 */
function showTriggerDialog() {
  const html = HtmlService.createHtmlOutput(`
    <h2>トリガー設定</h2>
    <p>以下のボタンをクリックして、1時間ごとの自動実行を設定します。</p>
    <button onclick="createTrigger()">トリガーを設定</button>
    <script>
      function createTrigger() {
        google.script.run
          .withSuccessHandler(function() {
            alert('トリガーを設定しました。1時間ごとに新規領収書が確認されます。');
            google.script.host.close();
          })
          .withFailureHandler(function(error) {
            alert('エラー: ' + error);
          })
          .createHourlyTrigger();
      }
    </script>
  `)
  .setWidth(400)
  .setHeight(200);
  
  SpreadsheetApp.getUi().showModalDialog(html, 'トリガー設定');
}

/**
 * 1時間ごとのトリガーを作成
 */
function createHourlyTrigger() {
  // 既存のトリガーを削除
  const triggers = ScriptApp.getProjectTriggers();
  for (let i = 0; i < triggers.length; i++) {
    if (triggers[i].getHandlerFunction() === 'processNewReceiptPDFs') {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }
  
  // 新しいトリガーを作成
  ScriptApp.newTrigger('processNewReceiptPDFs')
    .timeBased()
    .everyHours(1)
    .create();
  
  return '設定完了';
}

修正が完了後に「保存」ボタンをクリックして、スクリプトを保存します。スクリプトを保存すると「領収書トラッカー」メニューが作成されます。

トリガー設定(自動実行)

スクリプトを定期的に自動実行させるためのトリガーを設定します。

  1. スプレッドシートのメニューバーから「領収書トラッカー」→「トリガー設定(自動実行)」を選択する方法
  2. もしくは、Apps Scriptエディタの「トリガー」→「トリガーを追加」から以下のように設定:
    • イベントのソースを選択: 時間主導型
    • 時間ベースのトリガーのタイプを選択: 時間ベースのタイマー
    • 時間の間隔を選択(時間): 1時間おき

これで1時間ごとに自動的にレシート情報が更新されるようになります。

6. Adobe Scanでレシートを撮影して保存

実際にレシートを管理していきましょう。

  1. Adobe Scanアプリを開き、レシートを撮影します。
  2. 撮影したレシートのファイル名を「日付(YYYY-MM-DD)_取引先_金額」の形式に変更します。例: 「2025-04-04_コンビニA_580」
  3. 保存先として先ほど作成したGoogle Driveの「レシート管理」フォルダを選択します。
  4. 「保存」ボタンをタップして、レシートデータをGoogle Driveに保存します。

7. Apps Scriptの実行

スプレッドシートにレシート情報を記録するために、作成したApps Scriptを実行します。

  1. スプレッドシートのメニューバーから「領収書トラッカー」→「レシート情報を更新」をクリックします。
  2. 初回実行時には権限の確認が求められるので、許可します。
  3. スクリプトが実行され、Google Driveフォルダ内のレシートファイル情報がスプレッドシートに記録されます。

8. 記録の確認

スプレッドシートを確認して、レシート情報が正しく記録されているか確認します。

  • 各列にファイル名より取得された「No(自動設定)」「レシート日付」「取引先」「金額」「ファイル名」のデータが入力されているはずです。
  • トリガーを設定していれば、今後は1時間ごとに自動的に新しいレシートの情報が追加されます。

9. まとめ

Adobe ScanとGoogle Driveを組み合わせたレシート管理システムは、次のような利点があります:

  • スマートフォン一つでレシートのデジタル化から保存、管理までが完結
  • 紙のレシートの紛失や劣化を防ぎ、長期保存が可能
  • ファイル名のルール化により、基本情報を一目で把握可能
  • Google Spreadsheetとの連携で、レシート情報を一覧表示し管理しやすい
  • Apps Scriptによる自動化で、手間なく情報が更新される
  • クラウド上での管理により、どこからでもアクセス可能
  • 経費精算や確定申告の際のデータ整理が容易

この方法を活用すれば、従来のレシート管理の煩わしさから解放され、効率的に経費を管理できるようになります。特に個人事業主や経費精算が頻繁に必要な方にとって、大きな時間の節約になるでしょう。

日々のちょっとした工夫が、長期的には大きな効率化につながります。ぜひこのシステムを試してみてください。

Copyright © 2025 DFL inc. All Rights Reserved.