第6章:AIとVBAを学び続ける!あなたの「超効率化」を止めないヒント
これまでの章で、あなたはAIと共にExcelVBAの「書かない自動化」の基礎を習得し、コード生成からエラー解決までを経験しました。AIを「自分だけのVBA先生」として活用し、Excel作業を効率化するイメージは掴めたはずです。
この章を読み終える頃には、あなたは単にコードを生成できるだけでなく、AI×VBAを自身の業務課題にどう結びつけ、どのように安全に、そして継続的に活用していくかという実践的な視点を身につけているでしょう。あなたのExcel業務をAIと共にさらに加速させるための、具体的な一歩を踏み出す力を養うことが、この章の目標です。
- AIプロンプト最適化のヒント:さらに“伝わる”プロンプトの書き方
- ステップアップ!AIと挑戦するより高度な応用自動化事例
- VBAとGemini API連携:AIコーディングアシスタントの構築
- まとめ:AIと共に進化する「書かない自動化」のその先へ
第7章:さらなる高みへ!AI×VBA応用テクニックの世界
おわりに:AI×VBAはあなたの未来を変える強力な武器 (付録付き)
AIプロンプト最適化のヒント:さらに“伝わる”プロンプトの書き方
長いプロンプトは面倒? AIを活用する本当の価値
- ユーザーフォームを構成する各コントロールの名前やプロパティ(TextBox、ComboBox、Caption、Nameなど)。
- それらのコントロールを操作するVBAのオブジェクトモデル(Me.txtDate.Valueなど)。
- 入力チェックのためのIsDate、IsNumericといった関数や条件分岐の構文。
- シートへのデータ転記における最終行の取得方法や、セルの値の代入方法。
- エラーハンドリングやメッセージボックスの表示方法。
これら一つ一つを学習し、記憶し、正しい構文で記述し、そしてデバッグする労力は計り知れません。
Markdownとは?(AIがプロンプトを「理解」するためのヒント)
- 太字(強調): **キーワード**
- 記述方法: 強調したい単語やフレーズを **二重のアスタリスク** で挟みます。
- AIへの効果: AIにその部分が特に重要であることを明確に伝えます。例えば、「ファイル操作には**FileSystemObject**を使用すること」と書けば、AIは一般的なファイル操作よりもFileSystemObjectを用いたコードを優先的に検討する可能性が高まります。
- 使いどころ:
- 特定のオブジェクト名、関数名、シート名、フォルダ名など、AIに正確に認識してほしい固有名詞。
- 必須条件や、特に注意してほしい重要な指示。
- 箇条書き(構造化): * 項目 または 1. 項目
- 記述方法: 複数の指示や要件を並べる際に、行の先頭に *(アスタリスクと半角スペース)または 1.(数字とピリオド、半角スペース)を置きます。
- AIへの効果: 指示が複数の独立した項目から構成されていることをAIに伝えます。これにより、AIは指示の見落としを防ぎ、一つ一つの項目に対して網羅的に対応しようとします。また、プロンプトが長くなっても、内容が整理されAIが理解しやすくなります。
- 使いどころ:
- フォームに必要なコントロールの一覧。
- 実装してほしい機能のリスト。
- コードが満たすべき条件のリスト。
活用例:ユーザーフォームのプロンプトの場合
難しい記号を覚える必要はありません。
重要な単語を**で囲んだり、複数の指示を箇条書きにしたりするだけでも、AIの回答の質と、あなたの“書かない自動化”の効率を大きく高めることができるでしょう。
ステップアップ!AIと挑戦するより高度な応用自動化事例
ここからは、さらに一歩踏み込み、より複雑で実用的なシナリオにAIと共に挑戦してみましょう。
これらの事例は、いずれも単なる繰り返し作業の自動化に留まらず、より高度なデータ処理や他アプリケーションとの連携、さらには外部情報との連携をAIと共に行う強力な一歩となるでしょう。
1. 複数のExcelファイルにまたがるデータ集計
- 部署ごとの月次売上ファイルをまとめて、全社売上集計表を作成する。
- 各担当者が入力した日報ファイルを自動で集計し、週次報告用のデータを作成する。
- プロジェクトごとの進捗ファイルを横断的に参照し、全体進捗サマリーを自動生成する。
- 従業員一人ひとりの経費精算書や交通費精算書から、必要なデータを抽出して経理部門の集計表にまとめる。
- 顧客アンケートの回答が個別のファイルになっている場合、すべての回答を一つに統合して分析基盤を作る。
これらをすべて手作業で行うと、ファイルを開いてはコピーし、別のファイルに貼り付けるという単純作業の繰り返しになり、時間もかかりますし、ミスの原因にもなります。しかし、AIとVBAを使えば、この手間のかかる作業をあっという間に終わらせることができます。
これらのファイルを、週次または月次で集計し、全体の売上を把握する必要があります。
- 目的ファイル(集計先): 集計_売上データ.xlsm (このファイルにマクロを記述します)
- 対象ファイル(集計元): 〇〇店_売上データ_20240501.xlsx、△△店_売上データ_20240501.xlsx のように、特定のフォルダ内に複数の店舗別売上ファイルがあると仮定します。
- 集計する内容: 各店舗ファイルの特定のシート(例:日別売上シート)にある、特定範囲のデータ(例:A列の「日付」、B列の「商品名」からE列の「売上金額」まで)を、目的ファイルの全店集計シートにコピー&ペーストでまとめたい。その際、どの店舗のデータか分かるように、ファイル名から店舗名を抽出して新しい列として追加します。さらに、集計シートに同一店舗の同一日付のデータがすでに存在する場合は、既存のデータを削除してから新しいデータを追加することで、重複を避けます。
【店舗別売上ファイルの「日別売上」シートの例】

日付 | 商品名 | 数量 | 単価 | 売上金額 |
2024/5/1 | りんご | 3 | 150 | 450 |
2024/5/1 | みかん | 2 | 100 | 200 |
2024/5/1 | バナナ | 5 | 120 | 600 |

日付 | 店舗名 | 商品名 | 数量 | 単価 | 売上金額 |
2024/5/1 | A店 | りんご | 3 | 150 | 450 |
2024/5/1 | A店 | みかん | 2 | 100 | 200 |
2024/5/1 | A店 | バナナ | 5 | 120 | 600 |
2024/5/1 | B店 | りんご | 2 | 150 | 300 |
2024/5/1 | B店 | みかん | 1 | 100 | 100 |
2024/5/1 | B店 | バナナ | 3 | 120 | 360 |
- 何がしたいのか?: 複数のExcelファイルからデータを集計したい。
- どのファイルを対象にするのか?: 特定のフォルダにあるファイル。ファイル名の規則があれば伝える(例:〇〇店_売上データ_日付.xlsx)。
- どのシートのどの範囲のデータを集めるのか?: 各ファイルの日別売上シートのA列からE列まで。
- どこにまとめるのか?: マクロがあるファイルの全店集計シート。
- データはどのように貼り付けるのか?:
- 各対象ファイルからデータを読み込むたびに、集計シート内で重複チェックとデータ追加を行う。
- 読み込んだデータ各行について、日付と店舗名(ファイル名から抽出)の組み合わせを特定する。ファイル名が「〇〇店_売上データ_YYYYMMDD.xlsx」のような形式なので、「店」の前の部分を店舗名とする。
- 集計シート内で、上記で特定した「日付」と「店舗名」の組み合わせと完全に一致する既存のすべての行を削除する。
- その後、読み込んだデータ全体(各行に抽出した店舗名を追加したもの)を、「全店集計」シートの現在の最終行の次の行にまとめて貼り付ける。
- その他: 処理の開始と終了がわかるメッセージボックスを表示する。生成されるVBAコードではFileSystemObjectを使用してファイル操作を行い、各処理の内容をコメントで簡潔に解説してください。※FileSystemObjectに関しては、Dir関数より汎用的なので筆者がこだわって追記しました。
これを踏まえて、AIに以下のようにプロンプトを作成してみましょう。
Excel VBAコードを作成してください。
目的:このマクロがあるExcelファイルと同じフォルダ内にある「店舗データ」フォルダ内の複数のExcelファイルからデータを集計し、このマクロがあるファイルのシートにまとめる。
### 手順:
1. このマクロが保存されているExcelファイルと同じフォルダ内にある「**店舗データ**」フォルダ(このフォルダにはすでに集計対象のExcelファイルが格納されているものとする)を対象とする。
2. 「店舗データ」フォルダ内にある、ファイル名に「**店_売上データ**」という文字列が含まれ、拡張子が**.xlsx**のExcelファイルすべてを対象とする。ファイル操作には**FileSystemObject**を使用すること。
3. 対象となる各ファイルについて、以下の処理を繰り返す。
a. 対象ファイルを開き、「**日別売上**」という名前のシートを選択する。
b. そのシートの**A列からE列まで**のデータ(ただし、**タイトル行は含まない**で、データが入力されている範囲のみ)を読み込む。
c. 読み込んだデータについて、各行から「日付」(読み込んだデータのA列)と、現在のファイル名から抽出した「店舗名」の組み合わせを特定する。ファイル名が「〇〇店_売上データ_YYYYMMDD.xlsx」の場合、「**店**」の前の部分(例:「〇〇店」)を店舗名とする。
d. 「**全店集計**」シート内で、上記で特定した「日付」と「店舗名」の組み合わせと**完全に一致する既存のすべての行を削除**する。
e. 読み込んだデータ全体(各行に抽出した店舗名を追加したもの)を、「**全店集計**」シートの現在の**最終行の次の行**にまとめて貼り付ける。
f. 対象ファイルの処理が終わったら、そのファイルを閉じる(**保存はしない**)。
処理の開始と終了がわかるように**メッセージボックス**を表示してください。
生成されるVBAコードには、各処理の内容を**コメント**で簡潔に解説してください。

(これはあくまで一例であり、AIの回答によってコードの構造や詳細が異なる場合があります。)
Sub 全店売上データ集計()
' 画面更新と警告メッセージを一時的に無効化し、処理を高速化する
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim fso As Object ' FileSystemObjectのオブジェクト
Dim targetFolderObj As Object ' 対象フォルダのオブジェクト
Dim file As Object ' 処理中のファイルのオブジェクト
Dim wbSource As Workbook
Dim wsSource As Worksheet
Dim wsTarget As Worksheet
Dim lastRowTarget As Long
Dim i As Long
Dim storeName As String
Dim dateToMatch As Date
Dim targetRow As Long
Dim tempArray() As Variant ' 読み込んだデータを一時的に格納する配列
Dim rowCount As Long
Dim currentFilePath As String ' 現在処理中のファイルのフルパス
' FileSystemObjectを生成(CreateObjectを使用するため、参照設定は不要)
Set fso = CreateObject("Scripting.FileSystemObject")
' このマクロが保存されているExcelファイルと同じフォルダ内の「店舗データ」フォルダを指定
Dim parentFolderPath As String
parentFolderPath = ThisWorkbook.Path
Dim dataFolderPath As String
dataFolderPath = parentFolderPath & "\店舗データ\"
' 対象フォルダが存在するか確認し、オブジェクトとして設定
If Not fso.FolderExists(dataFolderPath) Then
MsgBox "「店舗データ」フォルダが見つかりません。パスを確認してください: " & dataFolderPath, vbCritical
GoTo ExitSub
End If
Set targetFolderObj = fso.GetFolder(dataFolderPath)
' 「全店集計」シートを設定
Set wsTarget = ThisWorkbook.Sheets("全店集計")
' 処理開始メッセージをユーザーに通知
MsgBox "店舗売上データの集計を開始します。", vbInformation
' 指定フォルダ内のExcelファイルを順に処理
For Each file In targetFolderObj.Files
' ファイル名に「店_売上データ」が含まれ、拡張子が.xlsxのファイルを対象とする
If InStr(file.Name, "店_売上データ") > 0 And LCase(fso.GetExtensionName(file.Name)) = "xlsx" Then
currentFilePath = file.Path ' 現在処理中のファイルのフルパスを取得
' 対象ファイルを開く
Set wbSource = Workbooks.Open(currentFilePath)
Set wsSource = wbSource.Sheets("日別売上")
' 店舗名をファイル名から抽出 (例: "A店_売上データ_20240501.xlsx" から "A店" を抽出)
Dim baseFileName As String
baseFileName = fso.GetBaseName(file.Name) ' 拡張子を除いたファイル名
Dim nameParts() As String
nameParts = Split(baseFileName, "_")
storeName = nameParts(LBound(nameParts)) ' 例: "A店" が取得されることを想定
' ソースシートのA列からE列までのデータ範囲を取得(タイトル行を除く)
' データが1行もない場合はスキップ
If wsSource.Cells(Rows.Count, "A").End(xlUp).Row < 2 Then
' データがないため、次のファイルへ
wbSource.Close SaveChanges:=False
GoTo NextFileInLoop
End If
' データ範囲を配列に読み込む (A2セルから最終行のE列まで)
rowCount = wsSource.Cells(Rows.Count, "A").End(xlUp).Row - 1 ' データ行数 (タイトル行を除く)
tempArray = wsSource.Range("A2:E" & wsSource.Cells(Rows.Count, "A").End(xlUp).Row).Value
' 新しいデータを格納する一時的な二次元配列を準備
' (日付 + 店舗名 + 元の5列 = 6列)
Dim processedData() As Variant
ReDim processedData(1 To rowCount, 1 To 6)
' 読み込んだデータと店舗名を結合し、processedData配列に格納
' そして、集計シート内の重複行を削除
For i = 1 To rowCount
dateToMatch = tempArray(i, 1) ' 日付を取得
' 「全店集計」シート内の既存データをチェックし、重複する行があれば削除
' 同一日付・同一店舗のデータはすべて削除する
Dim currentTargetLastRow As Long
currentTargetLastRow = wsTarget.Cells(Rows.Count, "A").End(xlUp).Row
' 既存データ(2行目から最終行まで)をループして重複をチェック
' 下から上へループすることで、行削除による影響を避ける
For targetRow = currentTargetLastRow To 2 Step -1
' 日付 (A列) と店舗名 (B列) が一致するかを確認
If wsTarget.Cells(targetRow, "A").Value = dateToMatch And _
wsTarget.Cells(targetRow, "B").Value = storeName Then
wsTarget.Rows(targetRow).Delete Shift:=xlUp ' 重複行を削除
End If
Next targetRow
' 処理済みのデータとして一時配列に格納
processedData(i, 1) = tempArray(i, 1) ' 日付
processedData(i, 2) = storeName ' 店舗名
processedData(i, 3) = tempArray(i, 2) ' 商品名
processedData(i, 4) = tempArray(i, 3) ' 数量
processedData(i, 5) = tempArray(i, 4) ' 単価
processedData(i, 6) = tempArray(i, 5) ' 売上金額
Next i
' 全店集計シートの最終行の次の行に、新しいデータをまとめて貼り付け
lastRowTarget = wsTarget.Cells(Rows.Count, "A").End(xlUp).Row
wsTarget.Range("A" & lastRowTarget + 1).Resize(UBound(processedData, 1), UBound(processedData, 2)).Value = processedData
' ソースファイルを閉じる(保存しない)
wbSource.Close SaveChanges:=False
End If
NextFileInLoop:
Next file
' 処理終了メッセージをユーザーに通知
MsgBox "店舗売上データの集計が完了しました。", vbInformation
ExitSub:
' 画面更新と警告メッセージを有効に戻す
Application.ScreenUpdating = True
Application.DisplayAlerts = True
' オブジェクトの解放
Set fso = Nothing
Set targetFolderObj = Nothing
Set file = Nothing
Set wbSource = Nothing
Set wsSource = Nothing
Set wsTarget = Nothing
End Sub
コードの解説
- 変数宣言: 必要な変数を定義します。
fso: FileSystemObject のオブジェクトを格納します。
targetFolderObj: 対象フォルダのオブジェクトを格納します。
file: 処理中のファイルのオブジェクトを格納します。
wbSource, wsSource: 開いているソースファイルとシートのオブジェクトを格納します。
wsTarget: 集計先となる「全店集計」シートのオブジェクトを格納します。
lastRowTarget: 「全店集計」シートの最終行番号を格納します。
i, targetRow: ループ処理で使用するカウンター変数です。
storeName: ファイル名から抽出した店舗名を格納します。
dateToMatch: 読み込んだデータの日付を格納します。
tempArray: ソースシートから読み込んだ元のデータを一時的に格納する配列です。
rowCount: tempArrayの行数(データ件数)を格納します。
processedData: 店舗名を追加し、集計シートに貼り付ける形に整形されたデータを一時的に格納する配列です。
currentFilePath: 現在処理中のファイルのフルパスを格納します。 - 処理開始メッセージ: マクロの開始をユーザーに知らせるメッセージボックスを表示します。
- FileSystemObjectの作成とパスの取得:
Set fso = CreateObject("Scripting.FileSystemObject"): ファイルやフォルダを操作するためのFileSystemObjectを作成します。
CreateObjectを使用する遅延バインディングの場合、VBAエディターでの参照設定は不要です。これにより、マクロの配布が容易になります。
このマクロが保存されているExcelファイル (ThisWorkbook) のパスを取得し、それを使って対象の「店舗データ」フォルダのフルパスを構築します。
fso.FolderExistsで対象フォルダの存在を確認し、存在しない場合はエラーメッセージを表示して処理を中断します。
fso.GetFolderで対象フォルダのオブジェクトを設定します。 - 「全店集計」シートの設定:
このマクロが動作しているブック内の「全店集計」という名前のシートを特定し、wsTargetとして設定します。
このコードでは、シートの存在確認やヘッダー行の追加は行っていません。必要に応じて、事前にシートを作成し、ヘッダー行を設定しておく必要があります。 - ファイルループとデータ処理:
- For Each file In targetFolderObj.Files で、targetFolderObj(「店舗データ」フォルダ)内の全てのファイルを一つずつループ処理します。
- If InStr(file.Name, "店_売上データ") > 0 And LCase(fso.GetExtensionName(file.Name)) = "xlsx" Then で、ファイル名に「店_売上データ」が含まれ、かつ拡張子が「.xlsx」であるファイルのみを対象とします。
- ファイルを開く: 条件に合致したExcelファイルを開き、その中の「日別売上」シートをwsSourceとして設定します。file.Pathでファイルのフルパスを取得します。
- 店舗名の抽出: fso.GetBaseName(file.Name)で拡張子を除いたファイル名を取得し、それを_で分割して店舗名(例: A店)を抽出します。
データ読み込み: 「日別売上」シートのA2セルからE列の最終行までのデータをtempArray配列に読み込みます。 - 重複チェックと行削除:
- 読み込んだtempArrayの各行について、その日付と抽出した店舗名を使って、「全店集計」シート内を検索します。
- For targetRow = currentTargetLastRow To 2 Step -1 のループで、集計シートの最終行から上に向かって検索し、日付と店舗名が一致する行が見つかれば、その行を丸ごと削除します。これにより、該当する日付と店舗名のすべての行が削除されます。下から削除することで、行が削除されてもループの範囲に影響が出ないようにしています。
- データの整形と準備: 読み込んだtempArrayのデータに抽出した店舗名を加えて、processedData配列に格納します。
- データの一括貼り付け: 重複削除の処理が終わった後、processedData配列に格納された全てのデータを、「全店集計」シートの現在の最終行の次の行に、一括で書き込みます。
- ファイルのクローズ: 処理が完了したソースファイルを保存せずに閉じ、次のファイルの処理に移ります。
- 処理終了メッセージ: 全てのファイルの処理が完了した後、完了をユーザーに知らせるメッセージボックスを表示します。
- 設定のリセットとオブジェクトの解放: 最後に、画面更新と警告メッセージの表示設定を元に戻し、使用したオブジェクトを解放してメモリをクリーンアップします。
事前準備
- 作業フォルダの準備: マクロを記述するExcelファイル(例:集計_売上データ.xlsm)と同じ場所に、店舗データという名前のフォルダをあらかじめ作成します。
その中に、集計対象となるいくつかの店舗別売上データファイル(例:A店_売上データ_20240501.xlsx、B店_売上データ_20240501.xlsx)を作成して入れておきましょう。各ファイルには日別売上シートを作り、A列からE列にダミーデータを入れておくとテストがしやすいです。 - 集計用シートの準備: マクロを記述するExcelファイル(例:集計_売上データ.xlsm)内に、集計結果を書き込むための「全店集計」という名前のシートを作成しておきます。
使用方法
- 集計したいExcelファイル(このマクロを保存するファイル)を開きます。
- Alt + F11 を押してVBAエディタを開きます。
- VBAエディタの左側のプロジェクトエクスプローラーで、VBAProject(集計_売上データ.xlsm) を展開し、「標準モジュール」を右クリックします。
- 「挿入」→「標準モジュール」を選択します。
- 開いたモジュールに上記のVBAコードをコピー&ペーストします。
- VBAエディタを閉じます。
- Excelシートに戻り、Alt + F8 を押してマクロダイアログを開きます。
- 「全店売上データ集計」を選択し、「実行」をクリックします。
2. ユーザーフォームの作成と操作
- 目的ファイル(マクロ記述先): 日報管理.xlsm
- 入力データ:
- 日付(カレンダー形式で選択)
- 氏名(ドロップダウンリストから選択)
- 業務内容(複数行入力可能)
- 作業時間(時間単位で数値入力、小数も可)
- 特記事項(任意入力)
- フォームの機能:
- 入力必須項目(日付、氏名、業務内容、作業時間)のチェック。未入力の場合は警告メッセージを表示。
- 入力値の妥当性チェック(例:作業時間が負の値でないか、数値として正しいか)。
- 「登録」ボタンで、入力されたデータをシートの最終行に追加。
- 「クリア」ボタンで、入力フォームの各項目を初期化。
- 「閉じる」ボタンでフォームを閉じる。
- 転記先シート: 「日報データ」というシートのA列からF列までを想定。
- A列: 連番
- B列: 日付
- C列: 氏名
- D列: 業務内容
- E列: 作業時間
- F列: 特記事項

- 何がしたいのか?: ユーザーフォームを作成し、データ入力とシートへの転記を行いたい。
- フォームのレイアウト: どのようなコントロール(テキストボックス、コンボボックス、コマンドボタンなど)を配置し、それぞれに何を表示させたいか。
- 入力項目とその型: 日付、氏名、業務内容など、それぞれの項目がどのような形式(日付、文字列、数値など)で、どのような制約があるか。
- 入力データの処理: 必須チェック、妥当性チェック、シートへの転記方法(どのシートのどの列に、どのように追加するか)。
- ボタンの機能: 登録、クリア、閉じるボタンにそれぞれどのような機能を割り当てるか。
- その他: エラーメッセージの表示方法、フォームを開くトリガー(例:ボタンクリック)。
これを踏まえて、AIに以下のようにプロンプトを作成してみましょう。
Excel VBAで、以下の仕様を持つユーザーフォームと、それに関連するVBAコードを作成してください。
### ユーザーフォームの仕様:
* **フォーム名**: `frmNippoInput`
* フォームに必要な以下のコントロールと、それに付随するラベルを作成してください:
* `txtDate`: **日付入力用**のテキストボックス
* `cmbMemberName`: **氏名選択用**のコンボボックス
* `txtTaskDescription`: **業務内容入力用**の**複数行対応**テキストボックス
* `txtWorkTime`: **作業時間入力用**のテキストボックス(時間単位で小数も可)
* `txtRemarks`: **特記事項入力用**のテキストボックス
* `cmdRegister`: ボタン「**登録**」
* `cmdClear`: ボタン「**クリア**」
* `cmdClose`: ボタン「**閉じる**」
### VBAコードの仕様:
1. **フォーム表示用マクロ**:
* `ShowNippoForm` という名前の**標準モジュール**に`Public Sub`を作成し、フォームを表示するようにしてください。
2. **フォーム初期化時 (`UserForm_Initialize`)**:
* `cmbMemberName` に初期値として「田中」「佐藤」「鈴木」を設定する。
* 各テキストボックスとコンボボックスをクリアし、初期状態にする。
3. **「登録」ボタンクリック時 (`cmdRegister_Click`)**:
* **入力チェック**:
* `txtDate`、`cmbMemberName`、`txtTaskDescription`、`txtWorkTime` が**未入力**の場合は、「日付、氏名、業務内容、作業時間は必須入力です。」という**メッセージボックス**を表示し、処理を中断する。
* `txtDate` が**有効な日付形式でない**場合、「日付の入力形式が正しくありません。」と表示し、処理を中断する。
* `txtWorkTime` が**数値として有効でない**場合、または**負の値**の場合、「作業時間は0以上の数値を入力してください。」と表示し、処理を中断する。
* **シートへの転記**:
* 「**日報データ**」という名前のシートにデータを転記する。もしシートが存在しない場合は**作成**し、ヘッダー行(連番, 日付, 氏名, 業務内容, 作業時間, 特記事項)を追加する。
* シートの**最終行**に以下のデータを追加する:
* A列: 連番(既存データの最終行の連番+1、初回は1)
* B列: `txtDate` の値
* C列: `cmbMemberName` の値
* D列: `txtTaskDescription` の値
* E列: `txtWorkTime` の値
* F列: `txtRemarks` の値
* データ転記後、「日報を登録しました。」という**メッセージボックス**を表示する。
* 登録後、フォームの各項目を**クリア**する。
4. **「クリア」ボタンクリック時 (`cmdClear_Click`)**:
* すべての入力コントロール(テキストボックス、コンボボックス)の内容をクリアする。
5. **「閉じる」ボタンクリック時 (`cmdClose_Click`)**:
* フォームを閉じる。
生成されるVBAコードには、各処理の内容を**コメント**で簡潔に解説してください。
' --- 標準モジュール(例: Module1)に記述 ---
Sub ShowNippoForm()
' 日報入力フォームを表示する
' AIが生成したユーザーフォーム (frmNippoInput) を呼び出します。
Load frmNippoInput ' フォームをメモリにロード
frmNippoInput.Show ' フォームを表示 (モーダル表示: フォームを閉じるまで他の操作ができない)
End Sub
コードの解説:
- Sub ShowNippoForm(): このプロシージャは、作成したユーザーフォーム frmNippoInput を表示するための入り口となります。
- Load frmNippoInput: これはユーザーフォームをメモリに読み込むための命令です。
- frmNippoInput.Show: ロードしたフォームを表示します。Show メソッドは通常、ユーザーがフォームを閉じるまで他のExcel操作をブロックする「モーダル」表示になります。
VBEでfrmNippoInputをダブルクリックすると開くウィンドウに貼り付けてください。
' --- ユーザーフォームモジュール(frmNippoInput)に記述 ---
Private Sub UserForm_Initialize()
' フォームが初期化されるときに実行される(フォームが開かれる際に一度だけ実行)
' 氏名コンボボックスに初期値を設定
With Me.cmbMemberName
.AddItem "田中"
.AddItem "佐藤"
.AddItem "鈴木"
.ListIndex = -1 ' 初期選択なし (何も選択されていない状態にする)
End With
' 各コントロールをクリア(初期化)
Call ClearFormControls
End Sub
Private Sub cmdRegister_Click()
' 登録ボタンがクリックされたときに実行される
Dim ws As Worksheet ' 転記先シートを格納する変数
Dim lastRow As Long ' 転記先シートの最終行を格納する変数
Dim nextRenban As Long ' 連番を格納する変数
Dim workTimeValue As Double ' 作業時間を数値として格納する変数
' --- 入力チェック ---
' 必須項目(日付、氏名、業務内容、作業時間)が入力されているかチェック
If Trim(Me.txtDate.Value) = "" Or _
Me.cmbMemberName.ListIndex = -1 Or _
Trim(Me.txtTaskDescription.Value) = "" Or _
Trim(Me.txtWorkTime.Value) = "" Then
MsgBox "日付、氏名、業務内容、作業時間は必須入力です。", vbExclamation
Exit Sub ' 処理を中断する
End If
' 日付形式の有効性をチェック
If Not IsDate(Me.txtDate.Value) Then
MsgBox "日付の入力形式が正しくありません。例: 2024/05/01", vbExclamation
Exit Sub
End If
' 作業時間が数値として有効かチェック
If Not IsNumeric(Me.txtWorkTime.Value) Then
MsgBox "作業時間は数値を入力してください。", vbExclamation
Exit Sub
End If
' 数値に変換し、負の値でないかチェック
workTimeValue = CDbl(Me.txtWorkTime.Value)
If workTimeValue < 0 Then
MsgBox "作業時間は0以上の数値を入力してください。", vbExclamation
Exit Sub
End If
' --- シート準備とデータ転記 ---
' 「日報データ」シートが存在するか確認し、存在しない場合は作成する
On Error Resume Next ' エラーが発生しても処理を継続する
Set ws = ThisWorkbook.Sheets("日報データ")
On Error GoTo 0 ' エラーハンドリングを元に戻す
If ws Is Nothing Then
' シートが存在しない場合、新しくシートを作成し名前を設定
Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = "日報データ"
' ヘッダー行を追加
With ws
.Cells(1, 1).Value = "連番"
.Cells(1, 2).Value = "日付"
.Cells(1, 3).Value = "氏名"
.Cells(1, 4).Value = "業務内容"
.Cells(1, 5).Value = "作業時間"
.Cells(1, 6).Value = "特記事項"
.Rows(1).Font.Bold = True ' ヘッダーを太字に設定
End With
End If
' データを転記する最終行を取得(A列の最終データ行)
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
' 連番の決定
' ヘッダー行のみの場合や、データが全くない場合は1から開始
If lastRow = 1 And ws.Cells(1, 1).Value <> "連番" Then
nextRenban = 1
ElseIf lastRow = 1 And ws.Cells(1, 1).Value = "連番" Then
nextRenban = 1
Else ' 既存データがある場合は、最終行の連番に1を加算
nextRenban = ws.Cells(lastRow, "A").Value + 1
End If
' フォームからのデータをシートに転記
With ws
.Cells(lastRow + 1, 1).Value = nextRenban ' 連番
.Cells(lastRow + 1, 2).Value = CDate(Me.txtDate.Value) ' 日付 (日付型に変換)
.Cells(lastRow + 1, 3).Value = Me.cmbMemberName.Value ' 氏名
.Cells(lastRow + 1, 4).Value = Me.txtTaskDescription.Value ' 業務内容
.Cells(lastRow + 1, 5).Value = workTimeValue ' 作業時間 (数値型)
.Cells(lastRow + 1, 6).Value = Me.txtRemarks.Value ' 特記事項
End With
MsgBox "日報を登録しました。", vbInformation ' 登録完了メッセージ
' 登録後、フォームの各項目をクリアする
Call ClearFormControls
End Sub
Private Sub cmdClear_Click()
' クリアボタンがクリックされたときに実行される
Call ClearFormControls ' フォーム内のコントロールをクリアするサブルーチンを呼び出す
End Sub
Private Sub cmdClose_Click()
' 閉じるボタンがクリックされたときに実行される
Unload Me ' フォームをメモリから解放し、閉じる
End Sub
' フォーム内のコントロールをクリアするサブルーチン
Private Sub ClearFormControls()
Me.txtDate.Value = "" ' 日付テキストボックスをクリア
Me.cmbMemberName.ListIndex = -1 ' コンボボックスの選択を解除
Me.txtTaskDescription.Value = "" ' 業務内容テキストボックスをクリア
Me.txtWorkTime.Value = "" ' 作業時間テキストボックスをクリア
Me.txtRemarks.Value = "" ' 特記事項テキストボックスをクリア
Me.txtDate.SetFocus ' 日付テキストボックスにカーソルを置く
End Sub
コードの解説:
- UserForm_Initialize:フォームが表示される直前に実行され、コンボボックスの項目設定とフォームの初期化を行います。
- cmdRegister_Click:
- 1入力チェック:各入力フィールドが空でないか、日付や数値として正しい形式かを厳密にチェックします。
・特に「作業時間」については、IsNumeric関数で数値であることを確認後、CDblでDouble型に変換し、その値が負でないかをチェックすることで、型エラーを防ぎ、妥当な数値のみを受け付けるようにしました。 - シート準備:日報データシートが存在しない場合、自動的に作成し、見出し行を設定します。
- データ転記:シートの最終行を特定し、その次の行にフォームからの入力データを転記します。連番も自動で付与されます。
転記後、完了メッセージを表示し、フォームの内容をクリアします。
- 1入力チェック:各入力フィールドが空でないか、日付や数値として正しい形式かを厳密にチェックします。
- cmdClear_Click:フォーム内のすべての入力フィールドをクリアし、初期状態に戻します。
- cmdClose_Click:ユーザーフォームを閉じます。
- ClearFormControls:入力フィールドをクリアする共通の処理として定義されており、UserForm_InitializeとcmdRegister_Clickから呼び出されます。これにより、コードの重複を避け、保守性を高めています。
ユーザーフォームの作成とコードの配置手順
- Excelファイルの準備:
新しいExcelブックを作成し、名前を「日報管理.xlsm」として保存します。このブックには、「日報データ」という名前のシートを作成しておくことを推奨します。もしシートが存在しない場合でも、マクロが自動で作成するようにコードは記述されていますが、事前に準備しておくとスムーズです。
- VBAエディタを開く:
「日報管理.xlsm」を開き、Alt + F11 キーを押してVBAエディタ(VBE)を開きます。
- ユーザーフォームの挿入と名前変更:
- VBEの左側にあるプロジェクトエクスプローラーで、VBAProject(日報管理.xlsm) を右クリックします。
- 「挿入」→「ユーザーフォーム」を選択します。新しいユーザーフォーム(通常はUserForm1という名前)が作成されます。
- 作成されたフォームを選択した状態で、VBEの左下にあるプロパティウィンドウを探します。
- プロパティウィンドウの(名前)という項目を、frmNippoInput に変更します。この名前はAIが生成するコードと連動しています。
- コントロールの配置とプロパティ設定:
- VBEでfrmNippoInputをダブルクリックし、フォームのデザイン画面を表示します。
- ツールボックス(通常はVBEの左側に表示)から必要なコントロール(ラベル、テキストボックス、コンボボックス、コマンドボタン)をドラッグ&ドロップでフォーム上に配置してください。
- 配置した各コントロールを選択し、プロパティウィンドウで以下の設定を行います。
- ラベル:
Captionプロパティをそれぞれ「日付:」「氏名:」「業務内容:」「作業時間 (時間):」「特記事項:」に設定します。(「作業時間」には単位を追加しました) - テキストボックス:
日付入力用: (名前)をtxtDateに設定
業務内容入力用: (名前)をtxtTaskDescriptionに設定し、MultiLineプロパティをTrueに設定
作業時間入力用: (名前)をtxtWorkTimeに設定
特記事項入力用: (名前)をtxtRemarksに設定 - コンボボックス:
氏名選択用: (名前)をcmbMemberNameに設定 - コマンドボタン:
「登録」ボタン: (名前)をcmdRegisterに設定し、Captionプロパティを「登録」に設定
「クリア」ボタン: (名前)をcmdClearに設定し、Captionプロパティを「クリア」に設定
「閉じる」ボタン: (名前)をcmdCloseに設定し、Captionプロパティを「閉じる」に設定
- ラベル:
- 標準モジュールの挿入:
- VBEの左側にあるプロジェクトエクスプローラーで、VBAProject(日報管理.xlsm) を右クリックします。
- 「挿入」→「標準モジュール」を選択します。新しいモジュール(通常はModule1という名前)が作成されます。
- コードのコピー&ペースト:
AIが生成したVBAコードを、それぞれのモジュールに正確にコピー&ペーストします。- 上記の「1.標準モジュール (Module1など) に記述するコード」の内容を、作成した標準モジュール(例: Module1)のコードウィンドウに貼り付けます。
- 上記の「2.ユーザーフォームモジュール (frmNippoInput のコードウィンドウ) に記述するコード」の内容を、作成したユーザーフォーム(frmNippoInput)をダブルクリックして開いたコードウィンドウに貼り付けます。
- フォームの実行:
- Excelシートに戻り、適当な場所に図形やボタンを挿入します。
- 挿入した図形やボタンを右クリックし、「マクロの登録」を選択します。
- 表示されたダイアログで「ShowNippoForm」を選択し、「OK」をクリックします。
- これで、図形やボタンをクリックすると、作成したユーザーフォームが表示されるはずです。フォームの各機能(入力、登録、クリア、閉じる)を試してみてください。

Excelユーザーフォーム入門
3. Excelデータを使ったWord文書の自動生成
シナリオ
AIへのプロンプトの考え方と例:テンプレートと置き換えを明確に
Wordテンプレート: 使用するWordテンプレートファイルのパスとファイル名、そしてテンプレート内に設定されたプレースホルダーの文字列(##氏名##、##日付##)。
出力先: 生成したWord文書をどこに、どのようなファイル名で保存するか。
プロンプト例
Excel VBAコードを作成してください。
目的:Excelデータを使ってWordテンプレートのプレースホルダーを置き換え、Word文書を自動生成する。
### 前提:
* マクロのあるExcelファイルと同じフォルダに以下が存在。
* データ元Excelファイル: `顧客リスト.xlsx`
* シート名: `名簿`、A列に氏名、B列に日付
* Wordテンプレートファイル: `案内状テンプレート.docx`
* テンプレート内のプレースホルダー: `##氏名##` と `##日付##`
### 手順:
1. `顧客リスト.xlsx`の「名簿」シートから、氏名(A列)と日付(B列)を1行ずつ読み込む(1行目はタイトル行)。
2. 各行のデータで`案内状テンプレート.docx`を開き、`##氏名##`を読み込んだ氏名に、`##日付##`を読み込んだ日付に置き換える。
3. 置き換え後、Excelと同じフォルダ内の「**生成済み文書**」フォルダに「`氏名_案内状.docx`」として保存する(フォルダは存在しない場合作成)。
4. Word文書の処理後、Wordを閉じる(保存不要)。
処理の開始と終了がわかるよう**メッセージボックス**を表示してください。
**参照設定が不要なコード**で作成してください。
生成されるVBAコードには、各処理の内容を**簡潔にコメント**してください。
AIが生成したVBAコードの例と解説
' 標準モジュールに貼り付けて実行
Sub CreateWordDocsFromExcelNoRef()
Dim wsData As Worksheet
Dim objWord As Object, objDoc As Object
Dim lastRow As Long, i As Long
Dim customerName As String, docDate As String
Dim saveFolderPath As String
' Word定数 (参照設定なしで使用するため)
Const wdReplaceAll As Long = 2 ' 置換オプション: すべて置換
' 処理開始メッセージ
MsgBox "Word文書の生成を開始します。", vbInformation
' 出力フォルダパスを設定し、なければ作成
saveFolderPath = ThisWorkbook.Path & "\生成済み文書\"
If Dir(saveFolderPath, vbDirectory) = "" Then MkDir saveFolderPath
' データシート設定
Set wsData = ThisWorkbook.Worksheets("名簿") ' 顧客リスト.xlsxのシートを想定
' 最終行取得(A列基準)
lastRow = wsData.Cells(Rows.Count, "A").End(xlUp).Row
' Wordアプリケーションを起動 (Late Binding)
On Error GoTo ErrorHandler ' エラーハンドリング設定
Set objWord = CreateObject("Word.Application")
On Error GoTo 0 ' エラーハンドリング解除
objWord.Visible = False ' Wordを非表示で実行
' 2行目から最終行までループ(1行目はタイトル行のため)
For i = 2 To lastRow
customerName = wsData.Cells(i, "A").Value ' 氏名取得
docDate = Format(wsData.Cells(i, "B").Value, "yyyy年m月d日") ' 日付取得、形式指定
' Wordテンプレートを開く
Set objDoc = objWord.Documents.Open(ThisWorkbook.Path & "\案内状テンプレート.docx")
' プレースホルダーを置き換え
With objDoc.Content.Find
.Text = "##氏名##": .Replacement.Text = customerName: .Execute Replace:=wdReplaceAll
.Text = "##日付##": .Replacement.Text = docDate: .Execute Replace:=wdReplaceAll
End With
' 文書を保存
objDoc.SaveAs2 saveFolderPath & customerName & "_案内状.docx"
' 文書を閉じる
objDoc.Close SaveChanges:=False
Next i
' Wordアプリケーションを終了
objWord.Quit
Set objDoc = Nothing
Set objWord = Nothing
' 処理終了メッセージ
MsgBox "Word文書の生成が完了しました。", vbInformation
Exit Sub
ErrorHandler:
MsgBox "Wordアプリケーションの起動に失敗しました。" & vbCrLf & _
"Wordがインストールされているか確認してください。", vbCritical
If Not objWord Is Nothing Then objWord.Quit
Set objDoc = Nothing
Set objWord = Nothing
End Sub
コードの解説
- CreateObject("Word.Application") を使うことで、参照設定なしでWordアプリケーションを操作できるようになります(Late Binding)。
- wdReplaceAllのようなWord固有の定数は、Const wdReplaceAll As Long = 2 のように数値で直接定義することで、参照設定なしで利用可能になります。
- Excelシートから氏名と日付を読み込み、指定されたWordテンプレートを開きます。
- objDoc.Content.Find メソッドを使用して、テンプレート内の##氏名##や##日付##といったプレースホルダーをExcelから取得したデータで置き換えます。
- objDoc.SaveAs2 で、指定したフォルダに新しいファイル名でWord文書を保存します。
- 処理後、開いたWord文書とWordアプリケーションを閉じ、使用したオブジェクトを解放します。
- Wordがインストールされていない場合などのエラーに対応するため、簡易的なエラーハンドリングを追加しています。
事前準備
- Excelデータファイル: マクロを保存するExcelファイルと同じフォルダ内に、「顧客リスト.xlsx」という名前のExcelファイルを作成し、中に「名簿」シートを準備します。A列に氏名、B列に日付を入力してください(1行目はタイトル行)。
- 例:
A列 B列
氏名 日付
山田太郎 2024/04/01
鈴木花子 2024/04/05
- 例:
- Wordテンプレートファイル: マクロを保存するExcelファイルと同じフォルダ内に、「案内状テンプレート.docx」という名前のWordファイルを作成します。このWordファイルの中に、置き換えたい箇所に##氏名##や##日付##といったプレースホルダーを入力しておきます。
使用方法
- 上記のVBAコードを、マクロを記述するExcelファイルの標準モジュールに貼り付けます。
- 「事前準備」で説明したExcelデータファイルとWordテンプレートファイルを準備し、適切に配置します。
- VBAエディタ(Alt + F11)からCreateWordDocsFromExcelNoRefマクロを実行します。
- マクロが完了すると、Excelファイルと同じフォルダ内に「生成済み文書」フォルダが作成され、中に個別のWord文書が保存されます。
4. Web上の情報を取得する(簡単なスクレイピング)
Web上の公開データや、社内システムの情報を自動でExcelに取り込む際に役立ちます。
- 対象URL: https://excel-ubara.com/GenerativeAI/GAI008.html
- 取得したい情報: このWebページ内に記述されている「プロンプトでのMarkdown記法とサンプル」という見出しの直下にある、Markdown記法とその効果についてまとめられた表(HTMLの<table>タグ)のデータ。
- 自動化の目的: この表の内容を自動的にExcelシートに抽出し、整理された形で出力することで、手作業によるコピー&ペーストの手間を削減し、常に最新の情報を効率的にExcelで管理できるようにします。
この自動化により、Webページの内容が更新された際も、マクロを実行するだけでExcelシートのデータが最新の状態に保たれ、業務の効率化と正確性の向上に貢献します。
- 目的のURL: どのWebサイトから情報を取得したいか。
- 取得したい情報: 表形式のデータ(<table>タグの内容)。
- 情報の特定方法: Webページ上でその表がどこにあるかのヒント。今回は、特定の見出しのテキスト(<h4>タグのテキスト)を基準に、その後に続く最初の<table>タグを特定します。
- 出力先: 取得した情報をExcelのどこに出力したいか(例:特定のシートのA1セルから)。
Excel VBAコードを作成してください。
目的:指定したWebページの「プロンプトでのMarkdown記法とサンプル」という見出しの下にあるテーブル(tableタグ)の内容を、Excelシートに表として出力する。
### 手順:
1. 以下のURLにアクセスする。
* `https://excel-ubara.com/GenerativeAI/GAI008.html`
2. Webページ内で、**`h4`タグのテキストが「プロンプトでのMarkdown記法とサンプル」と完全に一致する見出し**を特定する。
3. その見出しの**HTMLソースコード上での位置の直後にある最初の`table`タグ**の内容をすべて取得する。
4. 取得したテーブルのデータを、このマクロがあるExcelファイルの「**Markdown記法一覧**」という名前のシートの**A1セル**から表形式で貼り付ける。既存のデータはクリアする。
5. 処理の開始と終了がわかるように**メッセージボックス**を表示する。
**参照設定が不要なコード**で作成してください。
見出しを特定した後、その後のテーブルを確実に取得するロジックを実装してください。
生成されるVBAコードには、各処理の内容を**簡潔にコメント**してください。
' 標準モジュールに貼り付けて実行
Sub GetTableFromWebRobustFinal()
Dim ie As Object ' Internet Explorer オブジェクト (Late Binding)
Dim ws As Object ' 出力シート (Late Binding)
Dim htmlDoc As Object ' HTMLDocument オブジェクト
Dim h4Element As Object ' h4要素を格納
Dim allTables As Object ' ページ内のすべてのテーブル
Dim htmlTable As Object ' 目的のHTMLTable オブジェクト
Dim htmlRow As Object ' HTMLTableRow オブジェクト
Dim htmlCell As Object ' HTMLTableCell オブジェクト
Dim rowNum As Long, colNum As Long
Dim foundH4 As Boolean ' h4が見つかったかどうかのフラグ
Dim foundTable As Boolean ' テーブルが見つかったかどうかのフラグ
Dim h4Html As String ' h4要素のouterHTMLを格納
' 処理開始メッセージ
MsgBox "Webからのテーブル情報取得を開始します。", vbInformation
' IEオブジェクトを作成
On Error GoTo ErrorHandler ' エラーハンドリング設定
Set ie = CreateObject("InternetExplorer.Application")
On Error GoTo 0 ' エラーハンドリング解除
ie.Visible = False ' IEを非表示で実行
' 指定のURLにアクセス
ie.navigate "https://excel-ubara.com/GenerativeAI/GAI008.html"
' ページの読み込みが完了するまで待機
Do While ie.Busy Or ie.readyState <> 4
DoEvents
Loop
Set htmlDoc = ie.document
' 出力シートの準備
On Error Resume Next ' エラーを無視して続行
Set ws = ThisWorkbook.Sheets("Markdown記法一覧")
If ws Is Nothing Then
Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
ws.Name = "Markdown記法一覧"
End If
On Error GoTo 0 ' エラー無視を解除
ws.Cells.ClearContents ' 既存データをクリア
rowNum = 1 ' Excelの開始行
' すべてのh4要素を検索し、目的の見出しを特定
foundH4 = False
For Each h4Element In htmlDoc.getElementsByTagName("h4")
If h4Element.innerText = "プロンプトでのMarkdown記法とサンプル" Then
foundH4 = True
h4Html = h4Element.outerHTML ' h4のHTML文字列を取得
Exit For ' 見つかったらループを抜ける
End If
Next h4Element
If Not foundH4 Then
MsgBox "指定の見出し「プロンプトでのMarkdown記法とサンプル」が見つかりませんでした。", vbExclamation
ie.Quit
Set ie = Nothing
Exit Sub ' 処理を終了
End If
' ページ全体のHTMLを取得し、h4要素以降の部分を抽出
Dim pageHtml As String
pageHtml = htmlDoc.body.innerHTML ' body内の全HTML
' h4要素のHTML文字列が見つかった位置を特定
Dim h4Pos As Long
h4Pos = InStr(pageHtml, h4Html)
If h4Pos = 0 Then ' 万が一outerHTMLが特定できない場合(通常は発生しないはず)
MsgBox "内部エラー:見出しのHTMLを特定できませんでした。", vbExclamation
ie.Quit
Set ie = Nothing
Exit Sub
End If
' h4要素の終了タグ以降の文字列を取得
Dim afterH4Html As String
afterH4Html = Mid(pageHtml, h4Pos + Len(h4Html))
' afterH4Htmlの中から最初のテーブルを見つける
' 新しいHTMLDocumentオブジェクトを作成し、h4以降のHTMLをロードすることで、
' その中からテーブルを検索する
Dim tempDoc As Object
Set tempDoc = CreateObject("HTMLFile")
tempDoc.body.innerHTML = afterH4Html
Set allTables = tempDoc.getElementsByTagName("table")
If allTables.Length > 0 Then
Set htmlTable = allTables(0) ' 最初のテーブルを取得
foundTable = True
Else
foundTable = False
End If
If Not foundTable Then
MsgBox "指定の見出しの後にテーブルが見つかりませんでした。", vbExclamation
ie.Quit
Set ie = Nothing
Exit Sub ' 処理を終了
End If
' テーブルの行をループ
For Each htmlRow In htmlTable.getElementsByTagName("tr")
colNum = 1 ' Excelの開始列
' ヘッダーセル(<th>)をループ
For Each htmlCell In htmlRow.getElementsByTagName("th")
ws.Cells(rowNum, colNum).Value = htmlCell.innerText
colNum = colNum + 1
Next htmlCell
' データセル(<td>)をループ
For Each htmlCell In htmlRow.getElementsByTagName("td")
ws.Cells(rowNum, colNum).Value = htmlCell.innerText
colNum = colNum + 1
Next htmlCell
rowNum = rowNum + 1 ' 次のExcel行へ
Next htmlRow
' IEを閉じる
ie.Quit
Set ie = Nothing
Set tempDoc = Nothing ' 一時的なHTMLドキュメントも解放
' 処理終了メッセージ
MsgBox "Webからのテーブル情報取得が完了しました。", vbInformation
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました。Webサイトの構造変更やInternet Explorerのセキュリティ設定を確認してください。" & vbCrLf & _
"エラー内容: " & Err.Description, vbCritical
If Not ie Is Nothing Then ie.Quit
Set ie = Nothing
End Sub
コードの解説
- htmlDoc.getElementsByTagName("h4") でページ内のすべての<h4>タグ要素を取得し、そのinnerText(表示テキスト)が "プロンプトでのMarkdown記法とサンプル" と完全に一致する見出しを探します。
- 該当の<h4>タグが見つからなかった場合は、メッセージを表示して処理を終了します。
- 修正点(重要):
目的の<h4>タグが見つかったら、そのouterHTML(タグ自身を含むHTML文字列)を取得します。
ページ全体のinnerHTMLから、h4タグのouterHTMLが見つかった位置を特定し、その直後から始まる部分のHTML文字列を抽出します。
この抽出したHTML文字列を、新たに作成した一時的なHTMLFileオブジェクト(tempDoc)のbody.innerHTMLに読み込ませます。
これにより、tempDocはh4タグ以降のHTML構造を持つため、そのtempDocの中からgetElementsByTagName("table")で最初の<table>要素を取得すれば、それが目的のテーブルとなります。この方法はNextSiblingのテキストノード問題やNull問題を回避し、より確実に対象テーブルを特定できます。 - 目的のテーブルが見つからなかった場合も、同様にメッセージを表示して処理を終了します。
- 特定したテーブル内の各行(<tr>)をループし、さらに各セル(<th>や<td>)のテキスト内容を読み込みます。
- 取得したデータを、Excelシートの指定された位置(A1セルから)に表形式で貼り付けていきます。
- 「Markdown記法一覧」シートが存在しない場合は自動で作成します。
- 最後にIEを閉じ、使用したオブジェクト(ie と tempDoc)を解放します。
- Webサイトへのアクセス失敗などに対応するため、エラーハンドリングを含んでいます。
事前準備
- Internet Explorerの有効化: Windowsの機能でInternet Explorerが有効になっている必要があります。通常は有効ですが、無効になっている場合は「Windowsの機能の有効化または無効化」から有効にしてください。
- Webサイトの確認: プロンプト例に記載のURL(https://excel-ubara.com/GenerativeAI/GAI008.html)にアクセスし、目的のテーブルがHTML上でどのように構成されているかを確認しておくと、万が一コードが動作しない場合の原因特定に役立ちます。
使用方法
- 上記のVBAコードを、マクロを記述するExcelファイルの標準モジュールに貼り付けます。
- VBAエディタ(Alt + F11)からGetTableFromWebRobustFinalマクロを実行します。
- マクロが完了すると、Excelファイル内に「Markdown記法一覧」シートが作成され、指定したWebページから取得したテーブルデータが貼り付けられます。
今回のVBAはなかなか完成しませんでした。
何回も何回もテスト確認とそれをAIに伝えてVBA修正を重ねた結果要約完成したものです。
以下は、この経緯についてAI自身に書かせたものです。(筆者はポイントだけ伝えて)
VBAとGemini API連携:AIコーディングアシスタントの構築
Google Gemini APIを利用するには、まずGoogle Cloud PlatformでAPIキーを取得し、Excel側でいくつかの初期設定を行う必要があります。APIキーは、あなたがGoogleのAIサービスを利用するための「鍵」のようなものです。この鍵を使って、AIに正しくアクセスできるようになります。
APIとは何か? VBAとAI連携の基本
- あなたは司書に「〇〇について書かれた本を探しているんだけど」とか「△△のやり方がわかる本はないかな?」と、知りたいことややりたいこと(リクエスト) を伝えます。
- 司書(API) は、あなたの言葉(リクエスト)を受け取ると、図書館の膨大な蔵書(様々な情報や機能の宝庫)の中から、あなたの知りたいことや解決したい課題にぴったりの「本(情報や機能)」を探し出してくれます。
- そして、司書(API)は、見つけた本(必要な情報や機能の提供)をあなたの元に届けてくれます。
- Excelのデータに基づいて、AIに商品の紹介文やキャッチコピーを自動で生成させ、別のセルに表示する。
- 大量の顧客リストから特定の条件に合う顧客の情報をAIに要約させ、レポートにまとめる。
- VBAコードでエラーが出たとき、そのエラーメッセージをAIに送って、その場で修正案を提案してもらう。
まさに、AIがあなたのVBA開発の「共同作業パートナー」として、リアルタイムにコード生成やデバッグを支援してくれるようになるのです。
Google Cloud Platform (GCP) アカウントの作成とAPIキーの取得

- Google Cloud Platform (GCP) にアクセスする
- ウェブブラウザで以下のURLにアクセスし、GCPコンソールを開きます。
Google Cloud Console - Googleアカウントでログインします。初めてアクセスする場合は、利用規約への同意や、支払い情報の登録(無料枠でも必要となる場合がありますが、Gemini APIの無料利用枠の範囲であれば料金はかかりません)を求められることがあります。画面の指示に従って進めてください。
- ウェブブラウザで以下のURLにアクセスし、GCPコンソールを開きます。
- 新しいプロジェクトを作成する
- GCPコンソールの左上にある、現在選択されているプロジェクト名(例:「My First Project」や「test」などの表示)をクリックします。
- クリックすると、「プロジェクトを選択」というダイアログが表示されます。このダイアログの右上に「新しいプロジェクト」というボタンまたはリンクがあります。
- 【「新しいプロジェクト」ボタンが見当たらない場合】
- まれにUIの変更などで「新しいプロジェクト」ボタンの場所が異なる場合があります。その場合は、GCPコンソール画面上部にある大きな検索バーに「プロジェクトを作成」と入力し、検索結果から「プロジェクトを作成」または「新しいプロジェクトの作成」といった項目を選択しても、プロジェクト作成画面に直接移動します。
- まれにUIの変更などで「新しいプロジェクト」ボタンの場所が異なる場合があります。その場合は、GCPコンソール画面上部にある大きな検索バーに「プロジェクトを作成」と入力し、検索結果から「プロジェクトを作成」または「新しいプロジェクトの作成」といった項目を選択しても、プロジェクト作成画面に直接移動します。
- 「新しいプロジェクト」をクリックすると、「新しいプロジェクト」というタイトル(または同様の)の画面に切り替わります。
- この画面に「プロジェクト名」を入力するフィールドがあります。
- ここに、あなたが付けたいプロジェクト名(例:「VBA-API」など、後から見て内容が分かりやすい名前)を入力してください。
- 「プロジェクト名」を入力すると、その下にある「プロジェクト ID」が自動的に提案されます。プロジェクトIDは一度作成すると変更できませんが、プロジェクト名は何回でも変更可能ですので、ここでは分かりやすい名前を設定しましょう。
- 場所(組織やフォルダ)の選択が必要な場合は、適切なものを選択します。(個人の場合は、通常はデフォルトで問題ありません)
- 最後に「作成」ボタンをクリックすれば、指定した名前で新しいプロジェクトが作成されます。
- 作成が完了したら、再度プロジェクト選択プルダウンをクリックし、今作成したプロジェクトが選択されていることを確認します。
- GCPコンソールの左上にある、現在選択されているプロジェクト名(例:「My First Project」や「test」などの表示)をクリックします。
- Gemini API を有効にする
- GCPコンソールの左側のナビゲーションメニューから、「APIとサービス」→「ライブラリ」を選択します。(メニューが見当たらない場合は、左上の三本線のアイコンをクリックして開いてください。)
- 検索バーで「Gemini API」と入力し、検索します。
- 検索結果に表示される「Gemini API」をクリックします。
- Gemini APIのページで、「有効にする」ボタンをクリックします。これにより、あなたのプロジェクトでGemini APIが利用できるようになります。
- GCPコンソールの左側のナビゲーションメニューから、「APIとサービス」→「ライブラリ」を選択します。(メニューが見当たらない場合は、左上の三本線のアイコンをクリックして開いてください。)
- APIキーを作成する
- 左側のナビゲーションメニューから、「APIとサービス」→「認証情報」を選択します。
- 画面上部にある「認証情報を作成」をクリックし、ドロップダウンメニューから「APIキー」を選択します。
- 新しいAPIキーが生成され、画面に表示されます。
- 重要: このAPIキーは非常に重要です!画面に表示されたAPIキーを必ずコピーし、安全な場所に保存してください。(例:メモ帳に一時的に貼り付ける、パスワード管理ツールに登録するなど。)
- 警告: このAPIキーを直接Excelファイルに書き込んだり、GitHubなどの公開リポジトリにアップロードしたり、他者に安易に共有したりすることは絶対に避けてください。APIキーが漏洩すると、あなたのGCPアカウントが悪用され、意図しない課金が発生するなどのリスクがあります。
- APIキーの確認後、「閉じる」をクリックします。
- 【もしAPIキーを保存せずに閉めてしまっても大丈夫!】
- 万が一、APIキーを控えるのを忘れて画面を閉めてしまっても心配ありません。
- 再度「APIとサービス」→「認証情報」の画面に戻ると、作成済みのAPIキーのリストが表示されます。
- 確認したいAPIキーの右側にある「鉛筆アイコン」をクリックして、そのAPIキーの編集画面を開いてください。
- 編集画面の「詳細情報」セクションに「鍵を表示します。」というリンクがあります。これをクリックすると、伏せられていたAPIキーの文字列が一時的に表示されますので、そこでコピーして安全な場所に保存し直してください。
- ただし、セキュリティ上の理由から、APIキーは一度しか表示されないよう設計されているサービスもあります(GCPは「鍵を表示します」で再表示可能ですが)。基本的には、生成された直後に必ずコピーして保存する習慣をつけることを強くお勧めします。
- どうしても元のAPIキーを再確認できない、あるいはセキュリティ上の懸念がある場合は、同じ画面で「APIキーを削除」し、改めて「認証情報を作成」から新しいAPIキーを発行し直すことも可能です。無料枠の範囲であれば、この方法が最も確実で安全です。
- 左側のナビゲーションメニューから、「APIとサービス」→「認証情報」を選択します。
Excel VBA側の初期設定
- Excelを開き、Alt + F11 を押してVBAエディタ(VBE)を起動します。
- VBEのメニューバーから「ツール(T)」→「参照設定(R)...」を選択します。
- VBEのメニューバーから「ツール(T)」→「参照設定(R)...」を選択します。
- 参照設定ダイアログボックスが表示されます。スクロールして以下のライブラリを探し、チェックボックスをオンにします。
- Microsoft XML, v6.0 (または Microsoft XML, v3.0 や Microsoft XML, v5.0 など、利用可能な最新バージョン)
- このライブラリは、HTTPリクエストを送信し、Webサーバーと通信するためのオブジェクト (MSXML2.XMLHTTP60 など) を提供します。
- 「OK」ボタンをクリックしてダイアログボックスを閉じます。
VBAからAPIを呼び出す基本コードの作成(標準モジュール)
- ExcelのVBAエディタ(VBE)を開きます (Alt + F11)。
- VBEのメニューバーから「挿入(I)」→「標準モジュール(M)」を選択します。
- 新しく開いた真っ白なモジュールに、以下のコードをそのまま貼り付けてください。
Option Explicit
' ★ここにあなたのGemini APIキーを貼り付けてください★
Private Const GEMINI_API_KEY As String = "YOUR_GEMINI_API_KEY_HERE"
' Gemini APIのエンドポイントURL (モデル指定を含む)
' gemini-proではなく、より新しいモデルであるgemini-1.5-proを使用
Private Const GEMINI_API_URL As String = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent?key="
' ====================================================================
' 関数名: GetGeminiResponse
' 概要: Gemini APIを呼び出し、AIからの応答を取得する
' 引数:
' promptText (String): AIに送信するプロンプト(指示文)
' 戻り値:
' String: AIからの応答テキスト、またはエラーメッセージ
' ====================================================================
Public Function GetGeminiResponse(ByVal promptText As String) As String
' HTTP通信用のオブジェクトを宣言 (参照設定不要な「レイトバインディング」)
Dim objHttp As Object ' MSXML2.XMLHTTP60
Dim strURL As String
Dim strRequestBody As String
Dim strResponseText As String
Dim lngStatusCode As Long
Dim strErrorMessage As String
Dim startPos As Long
Dim endPos As Long
Dim tempText As String
On Error GoTo ErrorHandler
' HTTPオブジェクトの作成
Set objHttp = CreateObject("MSXML2.XMLHTTP")
' APIの完全なURLを構築
strURL = GEMINI_API_URL & GEMINI_API_KEY
' リクエストボディ(JSON形式)を構築
' JSON文字列を正しくエスケープする
' Chr(34)はダブルクォーテーション(")を表す
' Chr(92)はバックスラッシュ(\)を表す
' JSON内でダブルクォーテーションをエスケープするには \" と記述する
strRequestBody = "{" & Chr(34) & "contents" & Chr(34) & ":" & _
"[" & _
"{" & Chr(34) & "parts" & Chr(34) & ":" & _
"[" & _
"{" & Chr(34) & "text" & Chr(34) & ":" & _
Chr(34) & Replace(promptText, Chr(34), Chr(92) & Chr(34)) & Chr(34) & _
"}" & _
"]}" & _
"]}"
' HTTPリクエストの準備
objHttp.Open "POST", strURL, False ' False: 同期通信 (応答を待つ)
objHttp.setRequestHeader "Content-Type", "application/json" ' JSON形式でデータを送信することを宣言
' HTTPリクエストの送信
objHttp.send strRequestBody
' 応答のステータスコードを取得
lngStatusCode = objHttp.Status
' 応答内容を取得
strResponseText = objHttp.responseText
' ステータスコードが200 (OK) 以外の場合
If lngStatusCode <> 200 Then
strErrorMessage = "APIエラー (" & lngStatusCode . "): " & strResponseText
Debug.Print strErrorMessage
GetGeminiResponse = "エラー: " & strErrorMessage
GoTo CleanUp
End If
' JSON応答の解析
' "text": "応答内容" の部分を抽出する
' "text": (スペースの有無は問わない) の位置を見つける
startPos = InStr(strResponseText, """text"":")
If startPos > 0 Then
' "text":" の部分の長さをスキップし、その直後から最初のダブルクォーテーションを探す
startPos = startPos + Len("""text"":")
' 実際のテキストが始まる最初のダブルクォーテーションを探す
startPos = InStr(startPos, strResponseText, Chr(34))
If startPos > 0 Then ' ダブルクォーテーションが見つかったら
startPos = startPos + 1 ' ダブルクォーテーションの次からがテキスト開始
' テキストの終了を知らせる次のダブルクォーテーションを探す
' エスケープされたダブルクォーテーション \" を誤認識しないように注意
endPos = startPos ' 検索開始位置を現在の開始位置に設定
Do While endPos > 0
endPos = InStr(endPos, strResponseText, Chr(34)) ' 次のダブルクォーテーションを探す
If endPos > 0 Then
' そのダブルクォーテーションの直前がバックスラッシュでなければ、それが終了位置
If Mid(strResponseText, endPos - 1, 1) <> Chr(92) Then
Exit Do ' 見つかったらループを抜ける
Else
endPos = endPos + 1 ' エスケープされていたら、次の検索開始位置を一つ進める
End If
End If
Loop
If endPos > startPos Then
tempText = Mid(strResponseText, startPos, endPos - startPos)
' JSON文字列に含まれる \" (エスケープされたダブルクォーテーション) を " に戻す
GetGeminiResponse = Replace(tempText, Chr(92) & Chr(34), Chr(34))
' 改行コードのエスケープ(\n, \r)もあれば、適切な形式に変換
GetGeminiResponse = Replace(GetGeminiResponse, Chr(92) & "n", vbCrLf)
GetGeminiResponse = Replace(Chr(92) & "r", vbCr)
' タブ (\t) もよくエスケープされる
GetGeminiResponse = Replace(GetGeminiResponse, Chr(92) & "t", vbTab)
' バックスラッシュ自体がエスケープされている場合 (\\) も元に戻す
GetGeminiResponse = Replace(Chr(92) & Chr(92), Chr(92))
Else
GetGeminiResponse = "エラー: AI応答のテキスト部分の終了位置を解析できませんでした。応答: " & strResponseText
End If
Else
GetGeminiResponse = "エラー: AI応答のテキスト開始ダブルクォーテーションが見つかりませんでした。応答: " & strResponseText
End If
Else
GetGeminiResponse = "エラー: AI応答に 'text' フィールドが見つかりませんでした。応答: " & strResponseText
End If
CleanUp:
' オブジェクトの解放
Set objHttp = Nothing
Exit Function
ErrorHandler:
strErrorMessage = "予期せぬエラーが発生しました: " & Err.Description
Debug.Print strErrorMessage
GetGeminiResponse = "エラー: " & strErrorMessage
Resume CleanUp ' エラーが発生してもCleanup処理に進む
End Function
コードの解説
上記のVBAコードは、GetGeminiResponse という名前の関数を定義しています。この関数が、あなたがAIに指示を送り、その応答を受け取るための「窓口」となります。
- Option Explicit: VBAコードの先頭に記述するお勧めのステートメントです。変数をすべて明示的に宣言することを強制し、タイプミスなどによるエラーを防ぐのに役立ちます。
- Private Const GEMINI_API_KEY As String = "YOUR_GEMINI_API_KEY_HERE":
- ここに、先ほどGoogle Cloud Platformで取得したAPIキーを貼り付けます。「YOUR_GEMINI_API_KEY_HERE」の部分を、あなたのAPIキー文字列に置き換えてください。
- Const は定数(値を変更できない変数)を宣言するキーワードです。APIキーは固定値なので、定数として定義するのが適切です。
- 【重要】APIキーの扱い方については、この後も繰り返し注意喚起します。このコード例では直接記述していますが、実運用ではセルから読み込む、環境変数を使うなど、より安全な方法を検討すべきです。
- Private Const GEMINI_API_URL As String:
- これはGemini APIにアクセスするためのURLです。v1beta はAPIのバージョン、gemini-pro は利用するモデルの種類を示しています。現在のGeminiの主流モデルであるgemini-proを指定しています。
- Public Function GetGeminiResponse(ByVal promptText As String) As String:
- この行から関数が始まります。Public なので、Excelのシート上からでも、他のVBAプロシージャからでもこの関数を呼び出すことができます。
- promptText As String は、AIに送りたい「質問文」や「指示文」を文字列として受け取るための引数です。
- As String は、この関数がAIからの応答を文字列として返すことを意味します。
- Dim objHttp As Object:
- Web上のAPIと通信するために必要な XMLHTTP オブジェクトを宣言しています。
- As Object と宣言することで、特定の参照設定(Microsoft XML, v6.0など)がなくても動くレイトバインディングを実現しています。これにより、このExcelファイルを使う人の環境に左右されにくくなります。
- Set objHttp = CreateObject("MSXML2.XMLHTTP"):
- CreateObject メソッドを使って、XMLHTTP オブジェクトのインスタンスを生成しています。これが、APIとの通信役を担います。
- strURL = GEMINI_API_URL & GEMINI_API_KEY:
- APIの基本URLと、あなたのAPIキーを結合し、AIにリクエストを送るための完全なURLを作成しています。
- strRequestBody = "{""contents"":[{""parts"":[{""text"":""" & Replace(promptText, """", """""") & """]}]}}":
- AIに送る指示(プロンプト)をJSON(JavaScript Object Notation)形式の文字列として構築しています。JSONは、Web APIでデータをやり取りする際によく使われる軽量なデータ形式です。
- Replace(promptText, """", """""") は、プロンプトテキストの中にダブルクォーテーション(")が含まれていた場合に、JSONのルールに従ってエスケープ(\"のように変換)するための処理です。
- objHttp.Open "POST", strURL, False:
- APIにリクエストを送信するための準備をします。
- "POST": データを送信するHTTPメソッドです。
- strURL: リクエストを送るAPIのURLです。
- False: 通信を同期的に行うことを意味します。つまり、AIからの応答があるまで、VBAコードは次の行に進まずに待ちます。簡易的なテストや短い処理には適していますが、長い処理ではExcelが固まってしまう可能性があるため、非同期通信(True)も選択肢になります(本書では同期通信で解説します)。
- objHttp.setRequestHeader "Content-Type", "application/json":
- 送信するデータがJSON形式であることをAPIに伝えています。これはAPIがデータを正しく解釈するために必要な設定です。
- objHttp.send strRequestBody:
- 実際にAPIにリクエスト(指示とデータ)を送信します。
- lngStatusCode = objHttp.Status:
- APIサーバーからの応答の状態を示す「ステータスコード」を取得します。200 は「成功」、400 や 500 番台は「エラー」を示します。
- strResponseText = objHttp.responseText:
- AIからの実際の応答内容(生成されたテキストなど)を文字列として取得します。この応答も通常はJSON形式です。
- JSON応答の解析:
- InStr や Mid 関数を使って、JSON応答の中から"text":"AIの応答内容"という部分を抽出し、AIが生成した純粋なテキストを取り出しています。より複雑なJSON構造を扱う場合は、専用のJSONパーサーライブラリ(VBA-JSONなど)を導入すると便利ですが、本書ではこの簡易的な方法で進めます。
- ErrorHandler:
- 予期せぬエラーが発生した場合に、VBAコードが停止せずにエラーメッセージを表示して処理を終了するためのエラーハンドリングです。
- Set objHttp = Nothing:
- 使用し終わったオブジェクトは、メモリを解放するために Nothing を設定します。これはVBAでの良い習慣です。
- 使用し終わったオブジェクトは、メモリを解放するために Nothing を設定します。これはVBAでの良い習慣です。
VBEイミディエイトウィンドウからのAPI呼び出し実践とデバッグ
イミディエイトウィンドウは、VBAエディタ(VBE)の機能の一つで、VBAのコードを一行ずつ実行したり、変数の値を確認したり、関数やプロシージャを呼び出して即座に結果を表示したりするための便利なツールです。コードの動作確認やデバッグ作業において頻繁に利用されます。
- Excelを開き、Alt + F11 キーを押してVBEを起動します。
- VBEのメニューバーから「表示(V)」→「イミディエイト ウィンドウ(I)」を選択します。
- または、Ctrl + G ショートカットキーでも表示できます。
- VBEの下部、または任意の場所にイミディエイトウィンドウが表示されます。
イミディエイトウィンドウの入力欄に、以下のように入力し、Enterキーを押します。
?GetGeminiResponse("APIとは")
- ? は、GetGeminiResponse関数の戻り値をイミディエイトウィンドウに表示させるための指示です。
- "APIとは" は、AIに送信する質問(プロンプト)です。
- エラー内容:
APIエラー (400): {"error": {"code": 400, "message": "Invalid JSON payload received. Expected , or } after key:value pair.\n[{\"text\":\"APIとは\"]}]}}\n ^", "status": "INVALID_ARGUMENT" }
エラー: APIエラー (400): {"error": {"code": 400, "message": "Invalid JSON payload received. Expected , or } after key:value pair.\n[{\"text\":\"APIとは\"]}]}}\n ^", "status": "INVALID_ARGUMENT" } - AIを「リアルタイム・デバッガー」として活用:
- このエラーメッセージは、APIが「Invalid JSON payload received(不正なJSONデータを受け取った)」と明確に教えてくれています。さらに、[{\"text\":\"APIとは\"]}]}}という部分が不正であり、どこが問題か(^で示される箇所)まで示してくれます。
- これは、VBAで構築しているJSON文字列が、Gemini APIの要求する形式と異なっていることを示唆しています。特に、JSONではダブルクォーテーション(")を文字列内で使う場合、\"のようにバックスラッシュ(\)でエスケープする必要があります。しかし、VBAの文字列リテラルで"を表現する際に""と書くのと混同してしまい、不適切なエスケープ(例:"を""に置換していた)が行われていたことが原因でした。
- エラー内容:
APIエラー (404): { "error": { "code": 404, "message": "models/gemini-pro is not found for API version v1beta, or is not supported for generateContent. Call ListModels to see the list of available models and their supported methods.", "status": "NOT_FOUND" } }
エラー: APIエラー (404): { "error": { "code": 404, "message": "models/gemini-pro is not found for API version v1beta, or is not supported for generateContent. Call ListModels to see the list of available models and their supported methods.", "status": "NOT_FOUND" } } - AIを「リアルタイム・デバッガー」として活用:
- このエラーメッセージは、「models/gemini-pro is not found」と、問題がモデル名にあることを非常に具体的に教えてくれます。さらに、「Call ListModels to see the list of available models」と、利用可能なモデルのリストを確認するよう促しています。
- これは、gemini-proモデルが、現在のAPIバージョン(v1beta)では直接利用できないか、または別のモデル名に移行した可能性を示しています。APIの提供元は常にサービスを改善しており、モデル名や利用可能なエンドポイントは更新されることがあるため、適切なモデル(この場合はgemini-1.5-pro)への変更が必要でした。
- エラー内容:
エラー: AI応答に 'text' フィールドが見つかりませんでした。応答: { "candidates": [ ... (大量のJSONレスポンス) ... ] } - AIを「リアルタイム・デバッガー」として活用:
- このエラーが最も興味深い点でした。APIエラー (404)は解消され、VBA関数としてはエラーメッセージを返しているものの、その後に続く応答: { "candidates": [...] }の部分には、AIが生成した長文の回答が完璧なJSON形式で含まれていました。
- これは、API通信自体は成功し、AIからの応答データは問題なく受け取れているにも関わらず、VBAコードがそのJSONデータの中から、実際に必要なAIの回答テキスト("text"フィールド)を正しく探し出せていないことを示しています。AIが返すJSONの整形("text": の後に半角スペースがあるかないかなど)や、テキスト内に含まれる特殊文字(\や"、改行コードなど)のエスケープ解除ロジックが、期待通りに機能していなかったためです。
- AIからの「正しいJSON応答」というリアルタイムなフィードバックを基に、VBAのJSON解析ロジックを微調整することで、最終的なテキスト抽出に成功しました。
- APIの仕様は変化する: モデル名やエンドポイントは更新されるため、エラーメッセージを頼りに最新の情報を確認することが重要です。
- エラーメッセージを丁寧に読む: エラーメッセージには、問題解決のための具体的なヒントが詰まっています。AIからの応答も、デバッグのための貴重な情報源となります。
- JSONの構造とエスケープは厳密である: JSONは厳密な書式を持つため、手動で文字列を構築・解析する際には、エスケープルールや空白の有無に細心の注意が必要です。
- 試行錯誤の繰り返し: 一度で完璧なコードが書けることは稀です。エラーが発生したら、焦らず、原因を一つずつ特定し、コードを少しずつ修正しては動作を確認する、という地道な作業の繰り返しが成功に繋がります。
完成したVBAコード
このコードを標準モジュールに貼り付け、GEMINI_API_KEY をご自身のAPIキーに置き換えて使用してください。
Option Explicit
' ★ここにあなたのGemini APIキーを貼り付けてください★
Private Const GEMINI_API_KEY As String = "YOUR_GEMINI_API_KEY_HERE"
' Gemini APIのエンドポイントURL (モデル指定を含む)
' gemini-proではなく、より新しいモデルであるgemini-1.5-proを使用
Private Const GEMINI_API_URL As String = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent?key="
' ====================================================================
' 関数名: GetGeminiResponse
' 概要: Gemini APIを呼び出し、AIからの応答を取得する
' 引数:
' promptText (String): AIに送信するプロンプト(指示文)
' 戻り値:
' String: AIからの応答テキスト、またはエラーメッセージ
' ====================================================================
Public Function GetGeminiResponse(ByVal promptText As String) As String
' HTTP通信用のオブジェクトを宣言 (参照設定不要な「レイトバインディング」)
Dim objHttp As Object ' MSXML2.XMLHTTP60
Dim strURL As String
Dim strRequestBody As String
Dim strResponseText As String
Dim lngStatusCode As Long
Dim strErrorMessage As String
Dim startPos As Long
Dim endPos As Long
Dim tempText As String
On Error GoTo ErrorHandler
' HTTPオブジェクトの作成
Set objHttp = CreateObject("MSXML2.XMLHTTP")
' APIの完全なURLを構築
strURL = GEMINI_API_URL & GEMINI_API_KEY
' リクエストボディ(JSON形式)を構築
' JSON文字列を正しくエスケープする
' Chr(34)はダブルクォーテーション(")を表す
' Chr(92)はバックスラッシュ(\)を表す
' JSON内でダブルクォーテーションをエスケープするには \" と記述する
strRequestBody = "{" & Chr(34) & "contents" & Chr(34) & ":" & _
"[" & _
"{" & Chr(34) & "parts" & Chr(34) & ":" & _
"[" & _
"{" & Chr(34) & "text" & Chr(34) & ":" & _
Chr(34) & Replace(promptText, Chr(34), Chr(92) & Chr(34)) & Chr(34) & _
"}" & _
"]}" & _
"]}"
' HTTPリクエストの準備
objHttp.Open "POST", strURL, False ' False: 同期通信 (応答を待つ)
objHttp.setRequestHeader "Content-Type", "application/json" ' JSON形式でデータを送信することを宣言
' HTTPリクエストの送信
objHttp.send strRequestBody
' 応答のステータスコードを取得
lngStatusCode = objHttp.Status
' 応答内容を取得
strResponseText = objHttp.responseText
' ステータスコードが200 (OK) 以外の場合
If lngStatusCode <> 200 Then
strErrorMessage = "APIエラー (" & lngStatusCode & "): " & strResponseText
Debug.Print strErrorMessage
GetGeminiResponse = "エラー: " & strErrorMessage
GoTo CleanUp
End If
' JSON応答の解析
' "text": "応答内容" の部分を抽出する
' "text": (スペースの有無は問わない) の位置を見つける
startPos = InStr(strResponseText, """text"":")
If startPos > 0 Then
' "text":" の部分の長さをスキップし、その直後から最初のダブルクォーテーションを探す
startPos = startPos + Len("""text"":")
' 実際のテキストが始まる最初のダブルクォーテーションを探す
startPos = InStr(startPos, strResponseText, Chr(34))
If startPos > 0 Then ' ダブルクォーテーションが見つかったら
startPos = startPos + 1 ' ダブルクォーテーションの次からがテキスト開始
' テキストの終了を知らせる次のダブルクォーテーションを探す
' エスケープされたダブルクォーテーション \" を誤認識しないように注意
endPos = startPos ' 検索開始位置を現在の開始位置に設定
Do While endPos > 0
endPos = InStr(endPos, strResponseText, Chr(34)) ' 次のダブルクォーテーションを探す
If endPos > 0 Then
' そのダブルクォーテーションの直前がバックスラッシュでなければ、それが終了位置
If Mid(strResponseText, endPos - 1, 1) <> Chr(92) Then
Exit Do ' 見つかったらループを抜ける
Else
endPos = endPos + 1 ' エスケープされていたら、次の検索開始位置を一つ進める
End If
End If
Loop
If endPos > startPos Then
tempText = Mid(strResponseText, startPos, endPos - startPos)
' JSON文字列に含まれる \" (エスケープされたダブルクォーテーション) を " に戻す
GetGeminiResponse = Replace(tempText, Chr(92) & Chr(34), Chr(34))
' 改行コードのエスケープ(\n, \r)もあれば、適切な形式に変換
GetGeminiResponse = Replace(GetGeminiResponse, Chr(92) & "n", vbCrLf)
GetGeminiResponse = Replace(GetGeminiResponse, Chr(92) & "r", vbCr)
' タブ (\t) もよくエスケープされる
GetGeminiResponse = Replace(GetGeminiResponse, Chr(92) & "t", vbTab)
' バックスラッシュ自体がエスケープされている場合 (\\) も元に戻す
GetGeminiResponse = Replace(GetGeminiResponse, Chr(92) & Chr(92), Chr(92))
Else
GetGeminiResponse = "エラー: AI応答のテキスト部分の終了位置を解析できませんでした。応答: " & strResponseText
End If
Else
GetGeminiResponse = "エラー: AI応答のテキスト開始ダブルクォーテーションが見つかりませんでした。応答: " & strResponseText
End If
Else
GetGeminiResponse = "エラー: AI応答に 'text' フィールドが見つかりませんでした。応答: " & strResponseText
End If
CleanUp:
' オブジェクトの解放
Set objHttp = Nothing
Exit Function
ErrorHandler:
strErrorMessage = "予期せぬエラーが発生しました: " & Err.Description
Debug.Print strErrorMessage
GetGeminiResponse = "エラー: " & strErrorMessage
Resume CleanUp ' エラーが発生してもCleanup処理に進む
End Function


ExcelシートからAPI関数を利用してみる
- 質問を入力するセルを用意する
Excelシートの任意のセル(例:A1セル)に、AIに質問したい内容を入力します。 - 例:A1セルに「日本の首都はどこですか?」と入力します。
結果を表示するセルに数式を入力するAIの回答を表示させたいセル(例:B1セル)に、以下の数式を入力します。
この数式は、「A1セルの内容をGetGeminiResponse関数の引数として渡し、その関数の戻り値(AIの回答)をB1セルに表示する」という意味です。=GetGeminiResponse(A1)
- Enterキーを押して結果を確認する
- 数式を入力後、Enterキーを押すと、VBA関数が実行され、Google Gemini APIが呼び出されます。
- しばらく待つと、B1セルにAIからの回答が表示されるはずです。
- A1セルに質問「日本の首都はどこですか?」
- B1セルに数式「=GetGeminiResponse(A1)」
- B1セルにAIの回答「日本の首都は東京です。」と表示されるイメージです。
このように、VBAで作成した関数は、Excelの標準関数と同じようにシート上の数式として利用できます。セルの値を変更すれば、その都度AIが新しい回答を生成してくれるため、リアルタイムに近い形でAIとの対話や情報取得が可能です。
- 個人用マクロブックへの登録:
Excelには「PERSONAL.XLSB」という個人用マクロブックがあり、ここにマクロや関数を保存すると、どのExcelブックを開いてもそのマクロや関数が利用できるようになります。
VBAエディタでGetGeminiResponse関数が記述されたモジュールをPERSONAL.XLSBプロジェクトにコピーすることで実現できます。
個人用マクロブックに登録した関数は、イミディエイトウィンドウからも直接実行できます。
個人用マクロブックの詳しい使い方や、コードの登録方法については、別途AIに質問して確認してください。
これにより、=PERSONAL.XLSB!GetGeminiResponse(A1)のようにブック名を付加して呼び出すことが可能になります。
- アドイン化 (.xlam):
さらに高度な方法として、作成した関数を含むExcelファイルを「Excelアドイン (.xlam)」として保存し、Excelにインストールする方法があります。アドインとして登録することで、マクロ有効ブックを開く際にセキュリティ警告が表示されることなく、あたかもExcelの標準機能のように利用できるようになります。これは、複数のユーザーと機能を共有したり、配布したりする場合に特に便利です。アドイン作成の詳細については、以下のページをご参照ください。
Excel VBA マクロをアドイン化する|VBA技術解説・Excelアドインについて ・アドインファイルのフォルダ ・アドインの作り方 ・アドインの登録と有効化 ・ ・アドインで保存するVBA ・アドインを登録するVBA ・アドインを有効化するVBA ・登録されているアドインを確認するVBA ・アドインマネージャーを表示するVBA ・アドイン配布時に自動登録するVBA ・個人用マクロブックについて
API利用における注意点とセキュリティ
- 不正利用による課金: 悪意のある第三者があなたのAPIキーを使ってAPIを大量に呼び出し、その利用料があなたのGCPアカウントに請求されてしまう可能性があります。無料枠を超えた利用が発生した場合、高額な請求に繋がることもあります。
- データへの不正アクセス: もしAPIキーが、機密情報へのアクセス権限を持つ他のAPI(例えば、Google Drive APIやCloud Storage APIなど)と関連付けられていた場合、不正なアクセスやデータ漏洩に繋がるリスクがあります。
- サービスの停止: 悪意のある利用が検知された場合、GoogleによってAPIキーが無効化されたり、プロジェクトが停止されたりする可能性があります。
具体的な対策
- コードへの直接記述を避ける: 今回のVBAコードでは学習目的のためにAPIキーを直接記述していますが、コード内に直接書くと、ファイル共有やバージョン管理時に意図せず漏洩するリスクがあるため、実運用では推奨されません。
- より安全な方法の検討:
- Excelシートから読み込む: シートの特定のセルにAPIキーを保存し、VBAコードでそのセルの値を読み込む方法。ただし、Excelファイルを共有する際には注意が必要です。
- 環境変数として設定する: オペレーティングシステム(Windowsなど)の環境変数にAPIキーを設定し、VBAからそれを読み込む方法。これにより、APIキーがコードやファイル内に露出するのを防げます。
- 外部設定ファイルを利用する: 暗号化された設定ファイルや、アクセス制限されたINIファイルなどにAPIキーを保存し、VBAで読み込む方法。
- より安全な方法の検討:
- バージョン管理ツールでの管理: GitHubなどのバージョン管理システムを利用する場合、APIキーを直接コードに含めてコミットしないように細心の注意を払ってください。.gitignoreファイルなどを利用し、APIキーファイルや設定ファイルがリポジトリに含まれないように設定すべきです。
- 必要最小限の権限設定: GCPの「APIとサービス」→「認証情報」画面でAPIキーを編集する際に、「APIの制限」を設定できます。ここでは、そのAPIキーがどのAPI(例えば、Gemini APIのみ)にのみアクセスを許可するかを制限できます。これにより、万一APIキーが漏洩しても、被害を最小限に抑えることができます。
- 定期的なキーのローテーション: 定期的に新しいAPIキーを発行し、古いキーを無効化する(ローテーション)ことも、セキュリティを高める有効な手段です。
- 不要なAPIキーの削除: 使用しなくなったAPIキーは速やかに削除してください。
レベル | 方法 | セキュリティ | 実装難易度 |
初級 | コード内直接記述 | ★☆☆ | ★☆☆ |
中級 | Excelシートから読み込み | ★★☆ | ★★☆ |
上級 | 環境変数利用 | ★★★ | ★★★ |
プロ級 | 暗号化設定ファイル | ★★★ | ★★★ |
- 無料枠: 多くの場合、一定の範囲内であれば無料でAPIを利用できる「無料枠」が提供されています。しかし、この無料枠を超えて利用すると、課金が発生します。
- クォータと無料枠の区別: クォータは、APIの利用量に対する技術的な上限を示すもので、無料枠の上限とは異なる場合があります。クォータ内でも、無料枠を超えると課金が発生することがあるため、両者を区別して管理することが重要です。
- クォータの種類:
- リクエスト数: 1分あたり、1日あたりのAPI呼び出し回数に制限がある場合があります。
- トークン数: 送信するプロンプトや、AIが生成する応答の文字数(トークン数)に制限がある場合があります。
- モデル固有の制限: 特定の高性能モデル(例: gemini-1.5-proなど)は、他のモデルよりもクォータが厳しかったり、課金レートが高かったりする場合があります。
- 課金の確認: GCPコンソールの「課金」セクションで、現在のAPI利用状況とそれにかかる費用を確認できます。予期せぬ課金を防ぐため、定期的にこの画面を確認することをお勧めします。予算アラートを設定することも可能です。
- クォータの確認と引き上げ申請: GCPコンソールの「APIとサービス」→「有効なAPIとサービス」から各APIを選択し、「クォータ」タブで現在の利用状況と制限を確認できます。もし、無料枠を超える、またはプロジェクトの要件として現在のクォータでは不足する場合は、この画面からクォータの引き上げ申請を行うことができます。ただし、引き上げが承認されるには審査があり、課金が発生する可能性が高まります。
- 利用規約の遵守: Google Gemini APIの利用規約を遵守することが必須です。特定の用途(例: 違法行為、誤情報の拡散など)での利用は禁じられています。
- 応答時間の考慮: APIの応答には、ネットワーク状況やAIの処理負荷に応じて時間がかかることがあります。特に大量のデータを処理する場合や、UIに組み込む場合は、ユーザー体験を損なわないよう、非同期処理の検討やプログレスバーの表示などの工夫が必要です。
- エラーハンドリングの強化: 今回のVBAコードにもエラーハンドリングを導入しましたが、実運用ではより詳細なエラーログの記録や、エラーの種類に応じた適切なメッセージ表示、リトライ処理などの堅牢なエラーハンドリングを実装することが重要です。
これらの注意点を理解し、適切に対応することで、安全かつ効率的にGoogle Gemini APIをExcel VBAで活用できるようになります。
まとめ:AIと共に進化する「書かない自動化」のその先へ
- AIプロンプト最適化の深化: AIに意図が「伝わる」プロンプトの重要性を再認識し、より具体的で効果的な指示出しの技術を習得しました。これにより、AIが生成するVBAコードやアイデアの質を飛躍的に向上させることができます。
- AIとの協調による応用自動化: 複雑なデータ集計、ユーザーインターフェースの構築(ユーザーフォーム)、異種アプリケーション連携(Word文書生成)、さらにはWebからの情報取得(スクレイピング)といった、多様な業務課題に対してAIをコーディングアシスタントとして活用する具体的なアプローチを学びました。
- 外部連携とAPI活用の基礎: AIモデルそのものをVBAから直接操作するAPI連携の仕組みを理解し、APIキーの管理、利用制限(クォータ)、セキュリティといった実践的な注意点を把握しました。これにより、AIの能力をVBA環境に直接統合し、カスタマイズされた強力な自動化ツールを構築するための基盤を築きました。
これまでに学んだプロンプトの工夫、AIを巻き込んだ応用事例、そしてAPI連携の知識は、あなたの業務効率を飛躍的に向上させるための強力な武器となります。もはやあなたは、VBAコードを「ゼロから書く」必要はなく、AIと共に「創り出す」フェーズへと移行できるはずです。
あなた自身の視点や判断力が、AIによる自動化の質と成果を大きく左右します。
※本記事の作成にあたっては、生成AI(ChatGPT、Gemini、Claude)を活用し、文章および引用データの作成を行っています。最終的な内容は人間による確認・編集を経て掲載しています。
同じテーマ「AI×VBAで“書かない自動化”」の記事
AI時代のExcel革命:AI×VBAで“書かない自動化”超入門
第1章:AIって一体何?あなたのExcel作業をどう変える?(AI超基本)
第2章 VBAって怖くない!Excelを「言葉で動かす」(超入門)
第3章:AIを「自分だけのVBA先生」にする!質問・相談の超実践テクニック
第4章:【事例で学ぶ】AIとVBAでExcel作業を劇的に効率化する!
第5章:AI×VBAでつまづかない!トラブルシューティングとAIとの付き合い方
第6章:AIとVBAを学び続ける!あなたの「超効率化」を止めないヒント
新着記事NEW ・・・新着記事一覧を見る
第6章:AIとVBAを学び続ける!あなたの「超効率化」を止めないヒント|生成AI活用研究(2025-05-22)
第5章:AI×VBAでつまづかない!トラブルシューティングとAIとの付き合い方
|生成AI活用研究(2025-05-21)
第4章:【事例で学ぶ】AIとVBAでExcel作業を劇的に効率化する!
|生成AI活用研究(2025-05-20)
第3章:AIを「自分だけのVBA先生」にする!質問・相談の超実践テクニック|生成AI活用研究(2025-05-19)
第2章 VBAって怖くない!Excelを「言葉で動かす」(超入門)|生成AI活用研究(2025-05-18)
第1章:AIって一体何?あなたのExcel作業をどう変える?(AI超基本)|生成AI活用研究(2025-05-18)
AI時代のExcel革命:AI×VBAで“書かない自動化”超入門|生成AI活用研究(2025-05-17)
Geminiと100本ノック 23本目:シート構成の一致確認|生成AI活用研究(5月16日)
AIが問う出版の未来は淘汰か進化か:AIと書籍の共存の道とは|生成AI活用研究(2025-05-16)
Geminiと100本ノック 22本目:FizzBuzz発展問題|生成AI活用研究(5月15日)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.繰り返し処理(For Next)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.ひらがな⇔カタカナの変換|エクセル基本操作
6.RangeとCellsの使い方|VBA入門
7.メッセージボックス(MsgBox関数)|VBA入門
8.セルのクリア(Clear,ClearContents)|VBA入門
9.FILTER関数(範囲をフィルター処理)|エクセル入門
10.条件分岐(Select Case)|VBA入門
- ホーム
- 生成AI活用研究
- AI×VBAで“書かない自動化”
- 第6章:AIとVBAを学び続ける!あなたの「超効率化」を止めないヒント
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。