Googleフォームでの回答内容をGAS(Google Apps Script)で参照する方法です。
Googleフォームの値を取得するには2種類の方法があります。
今回は、「フォームを指定して回答内容を取得」する方法についての説明です。
フォームオブジェクトの取得
フォームオブジェクトを取得する方法には2つあります。
アクティブなフォームを開く
フォームからスクリプトエディタを開いてスクリプトを作成する場合には、アクティブなフォームが取得できます。
フォームID/フォームURLを指定してフォームを開く
もうひとつが、フォームIDかフォームURLを指定する方法です。
変数 = FormApp.openByUrl(フォームURL)
フォームの編集URLが下記の場合にフォームIDは、赤字の部分となります。
実際のコードでは下記のように書きます。
function formObject() { //フォームID var formId = '1234567890abcdefghijklmnopqrstuvwxyz' //フォームオブジェクトの取得 var form = FormApp.openById(formId) }
フォームURLは、青字の部分で、最後のスラッシュは必要です。
URLを指定した場合のサンプルコードです。
function formObject() { //フォームURL var formUrl = 'https://docs.google.com/forms/d/1234567890abcdefghijklmnopqrstuvwxyz/' //フォームオブジェクトの取得 var form = FormApp.openByUrl(formUrl) }
フォームの回答を取得する
フォームの回答を取得するには3段階の手順が必要です。
- フォームの全回答を取得
- ひとつの回答を選択
- 質問と回答内容を取得
フォームの全回答を取得
上で取得したフォームオブジェクトを指定して全回答を取得します。取得した回答は配列([1件目の回答, 2件目の回答, 3件目の回答, .....])となっているので回答数はlengthでわかります。
※ 実行する際には、var formId = 'フォームID' のフォームIDの部分を書き換えてください。
function formObject() { //フォームID var formId = '1234567890abcdefghijklmnopqrstuvwxyz' //フォームオブジェクトの取得 var form = FormApp.openById(formId) //全回答の取得 var formResponses = form.getResponses() //全回答数 Logger.log('回答数 = ' + formResponses.length) }
現在の回答数が3件であることがわかります。
回答数 = 3
ひとつの回答を選択
上のサンプルコードで全回答を取得した変数formResponsesは配列になっています。いま3件の回答があるので下記のようにして各々を取得できます。
- formResponses[0] ・・・ 1件目の回答
- formResponses[1] ・・・ 2件目の回答
- formResponses[2] ・・・ 3件目の回答
そして、getItemResponses()で回答内容が取得できます。
取得した回答内容にいくつの質問があるのかは、lengthで求められます。サンプルで使用しているフォームの質問は「日付」「時刻」「氏名」と3つです。
結果が3となるかを確認します。
function formObject() { //フォームID var formId = '1234567890abcdefghijklmnopqrstuvwxyz' //フォームオブジェクトの取得 var form = FormApp.openById(formId) //全回答の取得 var formResponses = form.getResponses() //1件目の回答を取得 var itemResponses = formResponses[0].formResponse.getItemResponses() //質問件数 Logger.log('質問項目数 = ' + itemResponses.length) }
質問項目数 = 3
質問と回答内容を取得
これでやっと回答内容を取得する準備が整いました。
フォームの質問を取得するには
フォームの回答を取得するには
で、取得できます。
下記のコードでで1件目の回答の1つ目の質問と回答内容が取得できます。
function formObject() { //フォームID var formId = '1234567890abcdefghijklmnopqrstuvwxyz' //フォームオブジェクトの取得 var form = FormApp.openById(formId) //全回答の取得 var formResponses = form.getResponses() //1件目の回答を取得 var itemResponses = formResponses[0].getItemResponses() //1件目の回答の1つ目の質問と回答を取得 var title = itemResponses[0].getItem().getTitle() var response = itemResponses[0].getResponse() Logger.log('質問内容 = ' + title) Logger.log('回答内容 = ' + response) }
質問内容 = 日付 回答内容 = 2021-01-10
全回答内容の取得
回答数、質問数はlengthで求められるので、全回答内容を表示するサンプルです。
function formObject() { //フォームID var formId = '1234567890abcdefghijklmnopqrstuvwxyz' //フォームオブジェクトの取得 var form = FormApp.openById(formId) //全回答の取得 var formResponses = form.getResponses() //i件目の回答を取得 for (var i = 0; i < formResponses.length; i++) { //回答を格納する配列 var arr = [] //i件の回答を取得 var itemResponses = formResponses[i].getItemResponses() for (var j = 0; j < itemResponses.length; j++) { //i件目の回答のj番目の質問と回答を取得 var title = itemResponses[j].getItem().getTitle() var response = itemResponses[j].getResponse() arr[j] = '【' + title + '】 ' + response } Logger.log(i+1 + '件目の回答 = ' + arr) } }
1件目の回答 = 【日付】 2021-01-10,【時刻】 10:10,【氏名】 象と散歩 2件目の回答 = 【日付】 2021-01-11,【時刻】 11:11,【氏名】 キリンと散歩 3件目の回答 = 【日付】 2021-01-12,【時刻】 12:12,【氏名】 イルカと散歩
フォームから回答内容が一致するものを探す
formの回答内容検索して回答内容が一致するものを探すサンプルプログラムとなります。(2022/6/19追記)
一致させる内容については、サンプルを簡単にするために変数としています。
- 質問内容='氏名'
- 回答内容='象と散歩'
変数で指定した条件と一致する回答があれば、質問内容と回答内容を出力して、一致するものがなければ '一致なし' と出力します。
複数一致するものがあれば複数回出力されます。
function formObject() { //一致条件 var questionTitle = '氏名' var costomerName ='キリンと散歩' //フォームID var formId = '1234567890abcdefghijklmnopqrstuvwxyz' //フォームオブジェクトの取得 var form = FormApp.openById(formId) //全回答の取得 var formResponses = form.getResponses() var ans = 0 //一致する回答を見つけた場合に1にする for (var i = 0; i < formResponses.length; i++) { //i件目の回答を取得 var itemResponses = formResponses[i].getItemResponses() for (var j = 0; j < itemResponses.length; j++) { //i件目の回答のj個目の質問と回答を取得 var title = itemResponses[j].getItem().getTitle() var response = itemResponses[j].getResponse() //質問項目が questionTitle で 回答内容が costomerName かを確認 if (title == questionTitle && response == customerName) { Logger.log('質問内容 = ' + title) Logger.log('回答内容 = ' + response) ans = 1 } } } if (ans == 0) { Logger.log('一致なし') } }
タイムスタンプを指定して回答を取得
getResponses(タイプスタンプ)でタイムスタンプが一致するフォームの回答を取得できます。
以下の例は、シートのタイプスタンプ(A列)と一致する回答編集用のURLを取得してシートのE列に書き込む例です。シートIDはフォームIDと同様に取得して変更してください。
function formObject() { //フォームID var formId = '1234567890abcdefghijklmnopqrstuvwxyz' //シートID var sheetId = 'abcdefghijklmnopqrstuvwxyz1234567890' //シート名 var sheetName = 'フォームの回答 1' //フォームオブジェクトの取得 var form = FormApp.openById(formId) var formResponses = form.getResponses() //シートオブジェクトの取得 var sheet = SpreadsheetApp.openById(sheetId).getSheetByName(sheetName) var lastRow = sheet.getLastRow() // 最終行の取得 //シートの2行目から最終行までを処理 for (var i =2; i <= lastRow; i++) { //A列からタイムスタンプを取得 var timeStamp = sheet.getRange('A' + i).getValue() //タイムスタンプが一致するフォームの回答を取得 var formResponses = form.getResponses(timeStamp) //編集用URLの取得 var editUrl = formResponses[0].getEditResponseUrl() //編集用URLをハイパーリンク形式に var strEditUrl = '=HYPERLINK("' + editUrl + '","編集用URL")' //編集用URLをE列に書き込む sheet.getRange('E' + i).setValue(strEditUrl) } }
シートのA列にあるタイムスタンプを取得して変数timeStampに格納して、タイムスタンプが一致する回答を取得しているのがこの部分です。
タイムスタンプが一致した回答は配列の0番目に格納されています。getEditResponseUrl()で編集用URLが取得できます。
タイムスタンプはミリ秒まであるので通常は問題ないと思いますが、タイムスタンプが一致する回答が複数あった場合の挙動はわかりません。
シートが下記のように更新されます。回答編集用URLは長いのでハイパーリンクにしました。
GASの基礎を学べる参考図書
ある程度プログラミンがわかっていれば、WEBやYoutubeでも十分に調べられると思いますが、初歩的なところからであれば参考図書は有効な学習手段です。
「詳解! Google Apps Script完全入門 [第3版]」は、プラグラミング初心者にわかりやすく説明されています。GASを最初に学ぶ一冊として良書です。
Udemy オススメ講座
【新IDE対応】Google Apps Script(GAS)の基礎を完全習得
講師:事務職たらこ
印象に残りやすい手書き風スライドを用いGASの基本的なプログラミングを気軽に学ぶことができる。本講座でGASを活用した自動化ができるレベルにはなれないが、基礎としては十分。
分かりやすくて参考にさせていただいています。
返信削除ただ、ちょっと分からないのですがシートを見るとタイムスタンプが秒までではないかと。
また、回答を編集するとform のspread sheet ではタイムスタンプが編集した時刻に変更されますが、編集用のURLは同じ回答を編集できるのでしょうか。 すみません、かなりの初心者です。
シートのタイムスタンプは見た目は秒までですが、実際にはミリ秒まで保有しています。=text(A2,"hh:mm:ss.000") などミリ秒まで確認する方法もあります。
返信削除また回答を編集した場合にはシートのタイムスタンプもフォームで保持しているタイムスタンプも更新されますが、編集用URLは変わりません。回答になっていますでしょうか。
なるほどぉ。ありがとうございます! 編集用URLはタイムスタンプを元に都度生成されるのかと思っていましたが、最初に生成されたときのまま変わらないんですね。もやもやが晴れました。
削除ありがとうございます。素人なので殆どコピペで使わせて頂いています。
返信削除あるチェックボックスの質問の、ある回答が空白の場合、エラーが出るのですが、よろしければ回避の仕方を教えて下さい。
フォームの回答が必須項目になっていない場合、回答されていない項目は配列上に存在しません。回答をすべて必須項目とするのがいちばん簡単な回避策ですが、必須とできないのであれば回答の質問内容と一致させる必要があります。
削除ありがとうございます。参考にさせていただきました。一点ご質問ですが、当方の記述が悪いかもしれませんが、チェックボックスで回答した内容を取得しようとすると、初めの回答しか取得されないようです。回答がカンマで区切られているからでしょうか。チェックボックスが3つあれば3つとも回収したいのですが、何か良い方法はありませんでしょうか?
返信削除もしかしたら、「ひとつの回答を選択」のサンプルコードを使われているのではないでしょうか?こちらのサンプルは、1件目の回答の1つ目の質問と回答を取得するサンプルコードです。「全回答内容の取得」にあるサンプルコードを使ってみてください。
削除ご回答ありがとうございます。無事解決しました!!。
返信削除初心者です。
返信削除すごくわかりやすく、参考にさせていただきました。
今回、『シートのA列にあるタイムスタンプを取得して変数timeStampに格納して、タイムスタンプが一致する回答を取得している』とのことでしたが、タイムスタンプ以外の文字列でも同じようなコードで『一致する回答を取得』できるのでしょうか?
例えば、
シートのA列にあるお客様名を取得して変数customerNameに格納。
var formResponses = form.getResponses(costomerName);
これでお客様名が一致する回答を取得できるのでしょうか?
実行してみたところエラーが出てしまったため、ご質問させていただきました。
よろしくお願いいたします。
ご質問ありがとうございます。
削除var formResponses = form.getResponses(costomerName);
ではできません。itemのTitleとResponseを取得して一致するものを探す必要があります。「フォームから回答内容が一致するものを探す」を追記いたしましたので、こちらを参考にしてみてください。
ひとつの回答を選択
返信削除………
取得した回答内容にいくつの質問があるのかは、lenghtで求められます。
--> length ですね。
ご指摘の通り【誤】lenght【正】length です。修正いたしました。ありがとうございます!!!
削除GASの初心者です。
返信削除勉強の為とちょっとした制作物を作るのに参考にさせて頂いております。
質問なのですが、ひとつの回答を取得する時、getItemResponsesで未定義のプロパティを読み取れないとエラーが出てしまいます。単純なタイプミスなのか、何かが悪さしてるのか分からないのですが、どんな原因が推測されるでしょうか?
推測できるエラーとしては、別な方も質問されていますが、
削除フォームの回答が必須項目になっていない場合、回答されていない項目は配列上に存在しません。回答をすべて必須項目とするのがいちばん簡単な回避策ですが、必須とできないのであれば回答の質問内容と一致させる必要があります。
回答内容と一致させる方法は「フォームから回答内容が一致するものを探す」を参照してください。