SECTION 17

実践: 名刺管理OCRアプリ

Gemini Vision API × Google Apps Script で名刺情報をスプレッドシートに自動登録する

calendar_today 2026 LCREATOR.Inc Google AI 研修プログラム

SECTION 17 — プロジェクト概要

名刺管理OCRアプリとは

OVERVIEW

解決する課題

名刺はもらったその場では整理できず、後でまとめて入力する作業が発生。手動入力はミスが多く、時間もかかる。

1

スマホで名刺を撮影

Googleフォームの画像アップロード機能を利用

2

Gemini Vision APIで解析

GASが自動的に画像をGeminiに送信しテキスト抽出

3

スプレッドシートに自動登録

構造化されたデータが即座にシートへ書き込まれる

名刺管理OCRアプリ完成イメージ
平均5分
従来の手動入力時間(1枚あたり)
約20秒
このシステム導入後の処理時間
check_circle
ノーコード・ローコードで構築可能。GASの基本が理解できていれば実装できる。

SECTION 17 — アーキテクチャ

システム構成図

ARCHITECTURE
smartphone スマホ撮影 ユーザー
arrow_forward
assignment Googleフォーム 送信
arrow_forward
code GAS 処理
arrow_forward
psychology Gemini API OCR
arrow_forward
table_chart スプレッドシート 保存

フォーム送信

画像ファイルはGoogleドライブに自動保存される。GASはファイルIDを取得して処理開始。

GASの役割

onFormSubmitトリガーで自動起動。画像をBase64エンコードしてGemini APIへ送信する。

データ保存

Geminiから返ってきたJSONを解析し、指定シートの末尾行に追記する。

SECTION 17 — フォーム設計

Googleフォームの設計

STEP 01

画像アップロードフォームの作成手順

1

Googleフォームを新規作成

forms.google.com から空白のフォームを作成する

2

氏名フィールドを追加

「短文テキスト」形式で送信者を識別するフィールドを追加

3

ファイルアップロードを追加

質問タイプ「ファイルのアップロード」を選択。許可するファイル形式を「画像」に限定する

4

スプレッドシートと連携

「回答」タブ > スプレッドシートアイコンから連携先を設定

フォーム設計のポイント

  • 「会社名」「撮影日」など補足情報も追加しておくと後でフィルタリングしやすい
  • ファイルサイズは最大10MBに設定(スマホ撮影は平均3〜5MB)
  • 複数枚アップロード可能に設定すると一度に複数名刺を処理できる
warning
注意: ファイルアップロード機能はGoogleアカウントへのログインが必要。社外の方向けのフォームには使えない場合がある。

SECTION 17 — GAS実装

GASでフォーム送信を受け取る

STEP 02

onFormSubmitトリガーの設定とイベントオブジェクトの扱い方

GAS // フォーム送信時に自動実行される関数 function onFormSubmit(e) { // フォームの回答を取得 const response = e.response; const itemResponses = response.getItemResponses(); // ファイルアップロードの回答を取得 let fileUrl = ''; itemResponses.forEach(item => { if (item.getItem().getTitle() === '名刺画像') { fileUrl = item.getResponse(); } }); // DriveのファイルIDを抽出 const fileId = extractFileId(fileUrl); // OCR処理を実行 processBusinessCard(fileId); }

トリガーの設定方法

1

GASエディタの「トリガー」アイコンをクリック

2

「トリガーを追加」> イベントの種類:「フォーム送信時」

3

実行する関数: onFormSubmit を選択して保存

info
GASはフォームに紐付いたスプレッドシートのスクリプトエディタから開く。スプレッドシートの「拡張機能」メニューから「Apps Script」を選択する。

SECTION 17 — API連携

Gemini Vision APIで画像解析

STEP 03

名刺画像をBase64に変換してGeminiへ送信するコード

GAS function analyzeBusinessCard(fileId) { const file = DriveApp.getFileById(fileId); const blob = file.getBlob(); // Base64エンコード const base64 = Utilities.base64Encode( blob.getBytes() ); // Vertex AI 経由で Gemini API を呼び出し const projectId = 'YOUR_GCP_PROJECT_ID'; const location = 'us-central1'; const model = 'gemini-2.5-flash'; const token = ScriptApp.getOAuthToken(); const url = `https://${location}-aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/publishers/google/models/${model}:generateContent`; const payload = { contents: [{ parts: [ { text: BUSINESS_CARD_PROMPT }, { inlineData: { mimeType: 'image/jpeg', data: base64 }} ] }] }; const res = UrlFetchApp.fetch(url, { method: 'post', contentType: 'application/json', headers: { 'Authorization': `Bearer ${token}` }, payload: JSON.stringify(payload) }); return JSON.parse(res.getContentText()); }

Vertex AI認証(GCPプロジェクト経由)

Vertex AI 経由ではScriptApp.getOAuthToken()で実行ユーザーのOAuthトークンを取得。そのユーザーにGCPプロジェクトの「Vertex AI ユーザー」IAMロールが付与されていれば認証が通る。

// GASの appsscript.json に以下のスコープを追加 "oauthScopes": [ "https://www.googleapis.com/auth/cloud-platform" ]
cloud
Vertex AI: GCPプロジェクトの「Vertex AI API」を有効化し、GASを実行するGoogleアカウントにIAMロール「Vertex AI ユーザー」を付与する。

SECTION 17 — プロンプト設計

名刺OCR用プロンプトの設計

STEP 04

JSON出力を強制する構造化プロンプト

const BUSINESS_CARD_PROMPT = ` この名刺画像から情報を抽出してください。 以下のJSON形式のみで回答してください。 余分なテキストや説明は不要です。 { "company": "会社名(なければ空文字)", "name": "氏名", "title": "役職・部署(なければ空文字)", "phone": "電話番号(なければ空文字)", "mobile": "携帯番号(なければ空文字)", "email": "メールアドレス(なければ空文字)", "address": "住所(なければ空文字)", "website": "WebサイトURL(なければ空文字)", "notes": "その他特記事項(なければ空文字)" } 情報が読み取れない項目は空文字にしてください。 JSONのみを返してください。 `;

効果的なプロンプト設計の原則

  • JSON形式を明示: 「JSONのみで回答」と指示することで余分な説明文を排除
  • フィールド定義を明記: 期待するキー名と値の型を示す
  • 空値の扱いを指定: 読み取れない場合の処理を明示
  • 言語を統一: 日本語の名刺なら日本語で出力するよう指示する
tips_and_updates
Gemini 2.0 Flash はJSONモードに対応。`responseMimeType: "application/json"` を指定すると、より確実にJSON形式で返答が得られる。

データ処理

抽出データの構造化・保存・重複管理

SECTION 17 — データ処理

抽出データの構造化

DATA 01

GeminiのレスポンスをJSONとしてパースし、配列に変換する

GAS function parseCardData(apiResponse) { // レスポンスからテキスト部分を取得 const text = apiResponse.candidates[0] .content.parts[0].text; // JSONとしてパース(前後の```json```を除去) const jsonStr = text .replace(/```json\n?/g, '') .replace(/```\n?/g, '') .trim(); const data = JSON.parse(jsonStr); // スプレッドシートの列順に配列化 return [ new Date(), // 登録日時 data.company, data.name, data.title, data.phone, data.mobile, data.email, data.address, data.website, data.notes ]; }

スプレッドシートの列構成

項目説明
A登録日時処理実行日時
B会社名company
C氏名name
D役職title
E電話phone
Fメールemail
G住所address
lightbulb
try-catchでJSONパースエラーをキャッチし、エラー時は生テキストをnotesに保存しておくと後から確認できる。

SECTION 17 — データ保存

スプレッドシートへの書き込み

DATA 02

構造化データをシートの末尾行に追記するコード

GAS function writeToSheet(rowData) { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName('名刺データ'); // シートが存在しない場合は作成 if (!sheet) { const newSheet = ss.insertSheet('名刺データ'); newSheet.appendRow([ '登録日時', '会社名', '氏名', '役職', '電話', '携帯', 'メール', '住所', 'Web', '備考' ]); } // データを末尾に追記 sheet.appendRow(rowData); // 最終行を強調表示(任意) const lastRow = sheet.getLastRow(); sheet.getRange(lastRow, 1, 1, rowData.length) .setBackground('#e8f0fe'); }

appendRow の利点

  • 常に末尾に追加するため、既存データを上書きする心配がない
  • 複数のフォーム送信が同時に来ても順序が保たれる
  • 行番号の管理が不要でコードがシンプルになる
check_circle
書き込み後に最終行をハイライトしておくと、新規追加データが一目でわかる。翌日のレビュー時に確認漏れを防げる。

SECTION 17 — データ品質

重複チェック: 既存データとの照合

DATA 03

メールアドレスをキーにした重複判定ロジック

GAS function isDuplicate(email) { if (!email) return false; const sheet = SpreadsheetApp .getActiveSpreadsheet() .getSheetByName('名刺データ'); if (!sheet) return false; // メール列(F列=6列目)の全データを取得 const lastRow = sheet.getLastRow(); if (lastRow < 2) return false; const emails = sheet .getRange(2, 7, lastRow - 1, 1) .getValues() .flat(); return emails.includes(email.toLowerCase()); } // 使用例 if (isDuplicate(data.email)) { // 重複時の処理(上書き or スキップ) updateExistingRecord(data); } else { writeToSheet(rowData); }

重複時の対応パターン

パターン1 スキップ
既存データを優先し、新しいデータを無視する

パターン2 上書き
最新の情報を優先し、既存行を更新する

パターン3 別シートに移動
重複を「要確認」シートに移して手動判断させる

info
メールアドレスがない名刺の場合は会社名+氏名の組み合わせでも重複チェックできる。完全一致に加えて類似度チェックも検討する。

SECTION 17 — 堅牢性

エラーハンドリング

DATA 04

発生しやすいエラーと対処法

image_not_supported

画像が不鮮明・読み取り不可

Geminiが空のJSONや不完全なデータを返す。全フィールドが空の場合、エラーシートに記録してフォーム送信者にメール通知する。

data_object

JSONパースエラー

Geminiが想定外のフォーマットで返した場合。try-catchでキャッチし、生テキストを保存してログに記録する。

cloud_off

API呼び出し失敗

タイムアウトやレート制限。Utilities.sleep()を使って指数バックオフで最大3回リトライする。

GAS function processWithErrorHandling(fileId) { try { const result = analyzeBusinessCard(fileId); const data = parseCardData(result); // データ品質チェック if (!data[2]) { // 氏名が空 logError('OCR失敗: 氏名取得不可', fileId); notifyError(fileId); return; } writeToSheet(data); } catch(e) { // エラーログをシートに記録 const errSheet = SpreadsheetApp .getActiveSpreadsheet() .getSheetByName('エラーログ'); errSheet.appendRow([ new Date(), fileId, e.message ]); } }

応用機能

CRM連携・バッチ処理によるさらなる活用

SECTION 17 — 応用

CRM連携: 取得データの活用

ADVANCED 01
email

フォローアップメール

名刺取得直後に自動でお礼メールを送信。Geminiで文面を個人化する。

GmailApp.sendEmail( data.email, '先日はありがとうございました', generateBody(data) );
calendar_today

Googleカレンダー連携

名刺登録後1週間でフォローアップのリマインダーをカレンダーに自動追加する。

CalendarApp .getDefaultCalendar() .createEvent( `${data.name}さんフォロー`, followUpDate, endDate );
chat

Chatwork/Slack通知

新しい名刺が登録されたらチームのチャットに通知。即座に営業担当者へ共有できる。

UrlFetchApp.fetch( WEBHOOK_URL, { method: 'post', payload: JSON.stringify({ text: `新規名刺: ${data.name}` }) } );

SECTION 17 — 応用

バッチ処理: 複数名刺の一括処理

ADVANCED 02

バッチ処理が有効な場面

  • 展示会後に100枚以上の名刺をまとめて処理したい
  • 既存の名刺フォルダをまとめてデジタル化したい
  • GASの実行時間制限(無料6分/Workspace30分)を超えないよう分割処理が必要
timer
GASの制限: 1回の実行は無料アカウント6分、Google Workspace 30分。大量処理はバッチを分割してタイムベーストリガーで連続実行する。
GAS function batchProcess() { const folder = DriveApp.getFolderById( CARD_FOLDER_ID ); const files = folder.getFiles(); let count = 0; while (files.hasNext()) { // 実行時間チェック(5分で停止) if (count >= 50) break; const file = files.next(); // 処理済みフラグを確認 if (isProcessed(file.getId())) continue; processWithErrorHandling(file.getId()); // 処理済みとしてマーク markAsProcessed(file.getId()); count++; // APIレート制限対策 Utilities.sleep(2000); } Logger.log(`処理完了: ${count}件`); }

ハンズオン

実際に手を動かして名刺OCRアプリを構築しよう

SECTION 17 — ハンズオン

ハンズオン 1: Googleフォームを作成

HANDS-ON 01
約15分
想定所要時間
初級
難易度
個人
作業形式
1

forms.google.com にアクセスして新しいフォームを作成

タイトルを「名刺登録フォーム」に設定する

2

「ファイルのアップロード」質問を追加

許可するファイル形式: 「画像」のみ / 最大ファイルサイズ: 10MB

3

スプレッドシートと連携

「回答」タブ > スプレッドシートアイコン > 「新しいスプレッドシートを作成」

4

フォームにテスト送信

手元の名刺を撮影して送信。スプレッドシートに回答が記録されることを確認する

check_circle
完了確認: スプレッドシートの「フォームの回答 1」シートに送信データが表示され、DriveにF列のURLが表示されていること

SECTION 17 — ハンズオン

ハンズオン 2: GASでOCR処理を実装

HANDS-ON 02

スプレッドシートのApps Scriptに以下を貼り付けて実装する

GAS // ===== Vertex AI 経由で名刺OCRを実行 ===== // GCPプロジェクトIDを設定 const PROJECT_ID = 'YOUR_GCP_PROJECT_ID'; const LOCATION = 'us-central1'; // スプレッドシート連携フォームのトリガー // e.values[N] でフォーム回答を取得 function onFormSubmit(e) { // e.values: [タイムスタンプ, 回答1, 回答2, ...] const imageUrl = e.values[1]; // DriveのファイルIDを抽出 const fileId = imageUrl .match(/[-\w]{25,}/)?.[0]; if (fileId) processBusinessCard(fileId); }
1

スプレッドシートを開く

「拡張機能」>「Apps Script」でエディタを開く

2

コードを貼り付けて保存

配布のサンプルコードを全てコピーしてCtrl+Sで保存

3

GCPプロジェクトIDを設定

コード冒頭のPROJECT_IDを自社のGCPプロジェクトIDに書き換える

4

トリガーを設定

トリガーアイコン > 「トリガーを追加」> フォーム送信時 > onFormSubmit

SECTION 17 — ハンズオン

ハンズオン 3: 実際の名刺で動作テスト

HANDS-ON 03

テスト手順

1

手元の名刺をスマホで撮影

照明を確保して斜めにならないように撮影。ピントが合っているか確認する。

2

フォームから送信

作成したフォームのURLをスマホで開いて画像をアップロード送信する。

3

スプレッドシートで確認

「名刺データ」シートに1〜2分以内にデータが追加されることを確認する。

4

GASのログを確認

エラーが出た場合はApps Scriptの「実行数」ログでエラー内容を確認する。

チェックリスト

  • スプレッドシートに「名刺データ」シートが自動作成された
  • 会社名・氏名・メールが正確に取得できた
  • エラーログシートに何も記録されていない
  • 2枚目の名刺でも正常に動作する
bug_report
うまくいかない場合: GASのログ(実行数)でエラー内容を確認。最もよくあるのは「APIキーが未設定」か「トリガーが設定されていない」の2パターン。

SECTION 17 — まとめ

このセクションで学んだこと

SUMMARY
architecture

システム設計の考え方

スマホ撮影→フォーム→GAS→Gemini API→スプレッドシートの一連のフローを設計・実装する方法を理解した。

psychology

Gemini Vision APIの活用

画像をBase64エンコードしてAPIに送信し、JSON形式でOCR結果を取得するプロンプト設計を習得した。

shield

堅牢な実装パターン

エラーハンドリング・重複チェック・APIキーの安全な管理など、本番運用に必要な要素を組み込む方法を学んだ。

名刺管理OCRアプリは「業務自動化の入門として最適」なプロジェクト。Gemini Vision APIを使えば、従来は人手で行っていたデータ入力作業を完全自動化できる。

応用・発展のアイデア

  • Salesforce / HubSpot等の外部CRMへのAPI連携
  • 名刺画像の自動タグ付け・分類(業種別など)
  • QRコード名刺への対応(Vision APIで同様に処理可能)

SECTION 17 完了

名刺管理OCRアプリの構築・実装・テストが完了しました

arrow_forward 次のセクション: SECTION 17「実践: リーガルチェックAI」へ
SLIDES
21
HANDS-ON
3
CODE SAMPLES
8
研修ポータル 補足: GAS×Vertex AI移行ガイド この章の動画 動画一覧