0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

書類の電子化とスプレッドシートを用いた台帳テンプレート・GAS

Posted at

書類の電子化とスプレッドシートを使った台帳テンプレート・GAS・Python

スプレッドシートのテンプレート(GASつき)

Google Apps Script(GAS)サンプルコード
/**
 * ===============================================================
 *  logFolderToSheet  —— 必須 5 列だけ確保して台帳へ書込(省略なし版)
 * --------------------------------------------------------------
 *  必須列 : ['ファイル名','URL','fileId','作成日時','folderId']
 *  1) headerIndex で現在の列マップを取得
 *  2) 無い列だけ sheet.appendRow() で右端に追加(既存列は上書きしない)
 *  3) Drive 内ファイルを BATCH_SIZE (=50) 行ごとにバッチ書込
 *  4) 重複 fileId は Set 判定でスキップ
 *  5) onEdit/onOpen トリガーは禁止。時間主導や手動トリガーで実行
 * ---------------------------------------------------------------
 *  フォルダ ID  : 設定用!A2  または ScriptProperty 'folderId'
 *  MIME/拡張子 : 設定用!B2(".pdf" や "image/" 等)※空欄なら全ファイル
 * ===============================================================
 */
function logFolderToSheet() {

  /* ---------- 設定 ---------- */
  const REQUIRED   = ['ファイル名','URL','fileId','作成日時','folderId'];
  const SHEET_NAME = 'スキャン台帳';
  const BATCH_SIZE = 50;

  /* ---------- シート取得 & 必須列確保 ---------- */
  const ss    = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(SHEET_NAME) || ss.insertSheet(SHEET_NAME);

  // 必須列チェック後は必ず最新ヘッダを取得
  let colMap = headerIndex(SHEET_NAME);
  const missing = REQUIRED.filter(c => colMap[c] === undefined);
  if (missing.length) {
    sheet.appendRow(missing);
  }
  // ここで強制再取得して確実に最新列順へ
  colMap = headerIndex(SHEET_NAME, undefined, { forceRefresh: true });

  /* ---------- フォルダ ID / フィルタ取得 ---------- */
  const folderId = getFolderId();
  if (!folderId) {
    SpreadsheetApp.getUi().alert('folderId が未設定です(設定用!A2 または ScriptProperty)。');
    return;
  }
  const filterStr = getFilterStr();                         // 拡張子 / MIME 部分文字列

  /* ---------- Drive 走査 ---------- */
  const folder = DriveApp.getFolderById(folderId);
  const files  = folder.getFiles();

  // 既存FileIdセット(重複排除)
  const lastRow = sheet.getLastRow();
  const idSet   = new Set(
      lastRow > 1
        ? sheet.getRange(2, colMap['fileId'] + 1, lastRow - 1).getValues().flat()
        : []
  );

  /* ---------- バッチ書込 ---------- */
  const buffer = [];
  while (files.hasNext()) {
    const f = files.next();
    if (idSet.has(f.getId())) continue;                      // 重複スキップ

    // フィルタ(拡張子 or MIME 部分一致)
    if (filterStr) {
      if (filterStr.startsWith('.')) {
        if (!f.getName().toLowerCase().endsWith(filterStr.toLowerCase())) continue;
      } else {
        if (!f.getMimeType().includes(filterStr)) continue;
      }
    }

    const row = new Array(Object.keys(colMap).length).fill('');
    row[colMap['ファイル名']] = f.getName();
    row[colMap['URL']]      = f.getUrl();
    row[colMap['fileId']]   = f.getId();
    row[colMap['作成日時']]   = Utilities.formatDate(
        f.getDateCreated(), Session.getScriptTimeZone(), 'yyyy-MM-dd HH:mm:ss');
    row[colMap['folderId']] = folderId;
    buffer.push(row);

    if (buffer.length >= BATCH_SIZE) {
      sheet.getRange(sheet.getLastRow() + 1, 1, buffer.length, row.length)
           .setValues(buffer);
      buffer.length = 0; // バッファクリア
    }
  }
  if (buffer.length) {
    sheet.getRange(sheet.getLastRow() + 1, 1, buffer.length, buffer[0].length)
         .setValues(buffer);
  }
}

/* ====================================================================
 *  サポート関数
 * ==================================================================== */

/**
 * headerIndex  —— ヘッダー ⇔ 列番号ユーティリティ(キャッシュ付)
 *   - 引数・振る舞いは README コメントを参照
 */
function headerIndex(sheetName, key, opts) {
  opts = Object.assign({ headerRow: 1, indexBase: 0, forceRefresh: false }, opts || {});
  const cacheKey = `hdr:${sheetName}:${opts.headerRow}`;

  // 1) 実行中メモリキャッシュ
  headerIndex._mem = headerIndex._mem || {};
  if (!opts.forceRefresh && headerIndex._mem[cacheKey]) {
    return _dispatch(headerIndex._mem[cacheKey], key, opts.indexBase);
  }

  // 2) ScriptCache(TTL 6h)
  const sc = CacheService.getScriptCache();
  let headers = null;
  if (!opts.forceRefresh) {
    const cached = sc.get(cacheKey);
    if (cached) headers = JSON.parse(cached);
  }

  // 3) シートから読み込み
  if (!headers) {
    const ss    = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = ss.getSheetByName(sheetName);
    if (!sheet) throw new Error(`Sheet '${sheetName}' not found`);
    headers = sheet.getRange(opts.headerRow, 1, 1, sheet.getLastColumn()).getValues()[0];
    headerIndex._mem[cacheKey] = headers;
    sc.put(cacheKey, JSON.stringify(headers), 21600); // 6h
  }

  return _dispatch(headers, key, opts.indexBase);

  /* --- 内部ヘルパ --- */
  function _dispatch(arr, k, base) {
    const off = base === 1 ? 1 : 0;
    if (k === undefined) return arr.reduce((o, h, i) => (o[h] = i + off, o), {});
    if (typeof k === 'number') return arr[k - 1] ?? null;
    if (Array.isArray(k)) return k.reduce((o, h) => (o[h] = arr.indexOf(h) + off || null, o), {});
    if (typeof k === 'string') {
      const idx = arr.indexOf(k);
      return idx === -1 ? null : idx + off;
    }
    throw new Error('key must be undefined/string/number/string[]');
  }
}

/* ---------- フォルダ ID 取得 ---------- */
function getFolderId() {
  const ss   = SpreadsheetApp.getActiveSpreadsheet();
  const s2   = ss.getSheetByName('設定用');
  const idIn = s2 ? String(s2.getRange('A2').getValue()).trim() : '';
  return idIn || PropertiesService.getScriptProperties().getProperty('folderId') || '';
}

/* ---------- フィルタ文字列取得(拡張子 or MIME 部分) ---------- */
function getFilterStr() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const s2 = ss.getSheetByName('設定用');
  return s2 ? String(s2.getRange('B2').getValue()).trim() : '';
}
}

概要

大量の紙書類を電子化し、Googleスプレッドシートを用いた台帳管理からはじめたい方向け

対象: 業務でGoogle Workspace環境を使っており、現場の書類管理を効率化したい方。

制約

  • 雇用契約書等の機密情報が対象

筆者の環境

  • クラウド: Google Workspace(Google Drive, Google Spreadsheet, Google Apps Script)
  • スキャナー: ScanSnap (流し込みスキャンができること)
  • Adobe Acrobat Pro (ページの分割に使用)

書類電子化の流れ

  1. 紙書類のスキャン

    • ホチキスやクリップの除去、付箋の剥離、A3書類はA4変換等
    • スキャナーでPDF化
  2. Google Driveにアップロード

    • フォルダ構成(例:年度・部署・個人フォルダごとなど)
  3. スプレッドシート台帳作成

    • Driveのファイル情報を一覧管理

    • カラム例:

      ファイル名 URL fileId 作成日時 folderId
  4. 自動化(GAS)

    • 指定したGoogle Drive内のフォルダからファイルリストを取得し、自動でスプレッドシートに書き出す
    • カラムの順序が変わっても動くスクリプト
    • 重複回避
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?