Translate

Post Date:2021年1月16日 

GASでGoogleフォームの値を取得する(フォームを指定)

ゾウでもわかる Google Apps Script

Googleフォームでの回答内容をGAS(Google Apps Script)で参照する方法です。

Googleフォームの値を取得するには2種類の方法があります。

  1. フォームが実行されたときに値を取得
  2. フォームを指定して回答内容を取得

今回は、「フォームを指定して回答内容を取得」する方法についての説明です。


フォームオブジェクトの取得

フォームオブジェクトを取得する方法には2つあります。


アクティブなフォームを開く

フォームからスクリプトエディタを開いてスクリプトを作成する場合には、アクティブなフォームが取得できます。

変数 = FormApp.getActiveForm()

フォームID/フォームURLを指定してフォームを開く

もうひとつが、フォームIDかフォームURLを指定する方法です。

変数 = FormApp.openBy(フォームID)
変数 = FormApp.openByUrl(フォームURL)

フォームの編集URLが下記の場合にフォームIDは、赤字の部分となります。

https://docs.google.com/forms/d/1234567890abcdefghijklmnopqrstuvwxyz/edit

実際のコードでは下記のように書きます。

function formObject() {
  //フォームID
  var formId = '1234567890abcdefghijklmnopqrstuvwxyz'

  //フォームオブジェクトの取得
  var form = FormApp.openById(formId)
}

フォームURLは、青字の部分で、最後のスラッシュは必要です。

https://docs.google.com/forms/d/1234567890abcdefghijklmnopqrstuvwxyz/edit

URLを指定した場合のサンプルコードです。

function formObject() {
  //フォームURL
  var formUrl    = 'https://docs.google.com/forms/d/1234567890abcdefghijklmnopqrstuvwxyz/'

  //フォームオブジェクトの取得
  var form  = FormApp.openByUrl(formUrl)
}

フォームの回答を取得する

フォームの回答を取得するには3段階の手順が必要です。

  1. フォームの全回答を取得
  2. ひとつの回答を選択
  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()で回答内容が取得できます。

変数 = formResponses[n番目].getItemResponses()

取得した回答内容にいくつの質問があるのかは、lengthで求められます。サンプルで使用しているフォームの質問は「日付」「時刻」「氏名」と3つです。

Google Sheets(フォーム回答内容)

結果が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

質問と回答内容を取得

これでやっと回答内容を取得する準備が整いました。

フォームの質問を取得するには

変数 = n番目の項目.getItem().getTitle()

フォームの回答を取得するには

変数 = n番目の項目.getResponse()

で、取得できます。

下記のコードでで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に格納して、タイムスタンプが一致する回答を取得しているのがこの部分です。

var formResponses = form.getResponses(timeStamp)

タイムスタンプが一致した回答は配列の0番目に格納されています。getEditResponseUrl()で編集用URLが取得できます。

var editUrl = formResponses[0].getEditResponseUrl()

タイムスタンプはミリ秒まであるので通常は問題ないと思いますが、タイムスタンプが一致する回答が複数あった場合の挙動はわかりません。

シートが下記のように更新されます。回答編集用URLは長いのでハイパーリンクにしました。

Google Sheets(回答編集URLを追加)

GASの基礎を学べる参考図書

ある程度プログラミンがわかっていれば、WEBやYoutubeでも十分に調べられると思いますが、初歩的なところからであれば参考図書は有効な学習手段です。

詳解! Google Apps Script完全入門 [第3版]」は、プラグラミング初心者にわかりやすく説明されています。GASを最初に学ぶ一冊として良書です。

Udemy オススメ講座

【新IDE対応】Google Apps Script(GAS)の基礎を完全習得

【新IDE対応】Google Apps Script(GAS)の基礎を完全習得

講師:事務職たらこ

印象に残りやすい手書き風スライドを用いGASの基本的なプログラミングを気軽に学ぶことができる。本講座でGASを活用した自動化ができるレベルにはなれないが、基礎としては十分。

Post Date:2021年1月11日 

GASでGoogleフォームの値を取得する(トリガー編)

ゾウでもわかる Google Apps Script

Googleフォームでの回答内容をGAS(Google Apps Script)で参照する方法です。

Googleフォームの値を取得するには2種類の方法があります。

  1. フォームが実行されたときに値を取得
  2. フォームを指定して回答内容を取得

今回は、「フォームが実行されたときに値を取得」についての説明です。


Googleフォーム実行時に値を取得

Apps Scriptはトリガーを設定することができるのでフォームが送信されたときに実行することができます。

スクリプトは、フォームから直接か、

GoogleフォームでGoogle Scriptを書く

回答先のシートから記述します。

 GoogleシートでGoogle Scriptを書く

トリガーの設定

トリガーの設定は、スクリプトの左側にあるメニューの時計のアイコンからです。

スクリプトからトリガーを設定

下例では、後述するサンプルプログラムの getFormValue を選択しています。イベントの種類は「フォーム送信時」を選んでください。

トリガーの設定 

function(e)とは?

フォーム送信時のトリガーで関数が実行されると、フォームの回答内容が関数の()内に指定した引数に渡されます。

function(e) のように引数をeとしている例が多いですが、これはイベントオブジェクトの表記に基づいているからだと思いますが、別に引数は e でなくても問題ありません。


連想配列で取得する(namedValues)

namedValue を使うと {キー:} という形でデータを取得できます。pythonではディクショナリー(辞書型)と呼ばれている配列です。

実際のデータで説明するのがわかりやすいと思います。

① 下記のフォームで送信します

サンプル フォーム

② トリガーでフォーム送信時に getFormValue を実行するように設定

getFormValue関数には、下記のコードを記載します。

namedValues でキーに質問名、値に回答内容を連想配列として取得したものをログに出力します。

function getFormValue(e) {
  console.log(e.namedValues)
}

フォームの質問項目は、日付、時刻、氏名ですが、namedValues で取得すると、時刻、氏名、日付の順番となっています。タイムスタンプは、回答を送信したときの時間です。

{ '時刻': [ '11:11:00' ],
  '氏名': [ 'キリンと散歩' ],
  '日付': [ '2021/01/11' ],
  'タイムスタンプ': [ '2021/01/10 12:25:19' ] }

質問名で値を取得する

namedValues['質問名'][0]

で、質問の回答を取得できます。[0]は、質問名の0番目(最初)の値を意味しますが、値がひとつしかないので省略可能です。

下記のコードで、質問名が氏名の内容を出力します。

function getFormValue(e) {
  var name = e.namedValues['氏名'][0]
  console.log('氏名 = ' + name)
}

氏名 = キリンと散歩

一次元配列として取得する(values)

values を使うと一次元配列で取得できます。

function getFormValue(e) {
  console.log(e.values)
}

こちらはフォームの順番に従っています。

[ '2021/01/10 12:25:19', '2021/01/11', '11:11:00', 'キリンと散歩' ]

namedValuesでのサンプルコードと同じく氏名の値を取得するのであれば、4番目の項目となるのでvalues[3]とします。

※配列は0からの指定なので、上記のデータであれば

  • values[0]    タイムスタンプ
  • values[1]    日付
  • values[2]    時刻
  • values[3]    氏名

となります。

function getFormValue(e) {
  var name = e.values[3]
  console.log('氏名 = ' + name)
}

氏名 = キリンと散歩

通常の配列なので、lengthを使ってforループで回して全ての項目を出力することも可能です。

function getFormValue(e) {
  for (var i = 0; i < e.values.length; i++)  {
    console.log(e.values[i])
  }
}

2021/01/10 12:25:19
2021/01/11
11:11:00
キリンと散歩

分割代入で変数にフォーム値を代入

分割代入を使うと配列から値を取り出して個別の変数に代入することが可能です。

function getFormValue(e) {
  var [timeStamp, date, time, name] = e.values
  console.log(name)
}

キリンと散歩

実行する上での注意事項

フォームの値を取得する関数は、スクリプトエディタからは実行できません。

トリガー起動関数を手動で実行する

getFormValueをスクリプトから実行すると、eの引数に何も渡されていないので、e.namedValues で 'namedValues' of undefined とエラーとなります。


「送信後に編集」は変更項目のみ取得可能

フォームの設定で「送信後に編集」をオンにしておくと、回答者は回答を編集をすることができます。

回答を編集して送信された場合は、変更された内容しか取得できません。何も回答を変更せずに送信されると取得できる項目はタイムスタンプだけとなります。

function getFormValue(e) {
  console.log(e.namedValues)
  console.log(e.values)
}

{ '氏名': [ '' ],
  'タイムスタンプ': [ '2021/01/10 12:50:40' ],
  '時刻': [ '' ],
  '日付': [ '' ] }

[ '2021/01/10 12:50:40', '', '', '' ]

GASの基礎を学べる参考図書

ある程度プログラミンがわかっていれば、WEBやYoutubeでも十分に調べられると思いますが、初歩的なところからであれば参考図書は有効な学習手段です。

詳解! Google Apps Script完全入門 [第3版]」は、プラグラミング初心者にわかりやすく説明されています。GASを最初に学ぶ一冊として良書です。

Udemy オススメ講座

【新IDE対応】Google Apps Script(GAS)の基礎を完全習得

【新IDE対応】Google Apps Script(GAS)の基礎を完全習得

講師:事務職たらこ

印象に残りやすい手書き風スライドを用いGASの基本的なプログラミングを気軽に学ぶことができる。本講座でGASを活用した自動化ができるレベルにはなれないが、基礎としては十分。

Post Date:2021年1月9日 

掃除の基本は「掃いて」「拭く」(吾妻箒)

手編み箒 アズマ 匠125 匠箒 短柄

Amazonの初売りでアズマ工業の 匠125 匠箒 短柄 が特選タイムセールになっていたので、思わずポチリと。

年末に、

『US103 床を優しく掃けるほうきS』も、まだまだ現役として頑張れそうなので、くたびれてきたら次を考えたいと思います。

【引用】象と散歩: 掃除の基本は「掃いて」「拭く」(ホーキ編)

と書いたばかりでしたが、物欲には勝てませんでした。

匠125 匠箒 短柄 は、最初の1本としてお勧めした「短柄 手編みホーキ 匠」よりワンランク上の商品ですが、特選セールで 短柄 手編みホーキ 匠 よりも安くなっていました。


カーバー箒と手編み箒を比べてみる

下写真の左が以前から使っていたカバー箒「US103床を優しく掃けるほうきS」、右が新しく購入した手編み箒「匠125 匠箒 短柄」です。

カバー箒(左)と手編み箒(右)

写真からもわかるように明らかに違うのは穂の量です。

穂幅の4cmの差よりも、厚さ2cmの差で穂の量に大きな差があります。手編みという特性上、全体的に穂の量が多く、その分、重さでも130gの違いがあります。

 
床を優しく掃ける
ほうきS
匠125 匠箒 短柄
長さ 77cm 82cm
穂幅 29cm 33cm
厚さ 3cm 5cm
重量 270g 400g
通常価格 1,560 円
1,880円
3,750 円
5,280円

手編みの美しさ

アズマ工業の「匠125 匠箒」は、タイで生産されています。手編み箒という日本の伝統文化が、タイの職人によって脈々と引き継がれています。

タイの箒職人による編み上げは、丁寧でしっかりしていています。

この素晴らしい技術を日本でも絶やさないようにしてもらいたいと願う次第です。

TRADITIONAL CORN BROOM – Libman.com をみると、米国でもBroomcorn(ホウキモロコシ)の箒が伝統的な箒とあります。和のデザインとコシとしなやかさを持つ高品質のホウキモロコシを使った長柄箒であれば、エコやSDGsといった観点からも欧米でも室内掃除用具として受け入れらるのではないでしょうか。


掃き心地の違い

130gは、片手での掃き掃除では結構感じる重さです。アズマ工業が、カバー箒を作った理由のひとつが「軽い箒」というのが頷けます。

その重さの違いから、カバー箒では「サッ、サッ、サッ、サッ」というテンポで掃いていましたが、手編み箒では「サーッ、、、サーッ」とゆっくりとなります。

穂の量が多い分、1回で掃き出せる量も多いですが、掃くペースが異なるのでトータル的には同じように思えます。しかし、カーペットなど敷物の上を掃くときには、穂の密度が高い分、隙間に入り込んでいる細かいゴミをしっかりと掃き出してくれます。

総合的に考えると、手軽さではカバー箒、丁寧な掃除では、手編みに軍配が上がります。


座敷箒の使い方

座敷箒は、フローリング、畳、絨毯(じゅうたん)、カーペットと、どこにでも使えます。

力を入れずに穂先を立てて優しく掃くことで、座敷箒の「しなやかさ」を生かすことができ、埃やゴミをしっかり捉えます。柄を軽く持つと力を入れずに掃けます。

  • 柄を軽く持つ
  • 穂を立てる
  • 力を入れずに優しく掃く

この3つが座敷箒を使った掃き掃除の基本です。

あとは、フローリングや畳の目に沿って掃き掃除をしていきます。


サスティナブルな座敷箒

説明書きに「箒は正しく扱っていただく事で、何十年もの間使い続けることができます。どうぞ大切にご使用ください。」とあります。

「手編み箒ってそんなに長持ちするの?」と驚きですが、正しく扱うのひとつに収納があります。

穂先が床に着いてた状態で収納していると穂先に癖がついてしまうので、吊り下げて収納します。また穂先に癖がついてしまったときには、穂全体を水(ぬるま湯)に浸して形を整えて乾かせば再生します(カバー箒で実践済み)。

手編み箒は、大切に使おうという気持ちにさせてくれますし、長く使っていれば愛着も湧いてきそうです。


シールはドライヤーで剥がす

匠125は、Amazonの製品紹介の写真にあるように柄の部分に緑色のシールが貼られています。そんなに自己アピールしなくてもと剥がそうとしましたが、粘着力が強いシールで、手ではキレイに剥がせそうにありません。

アズマ 匠125 匠箒 短柄
アズマ 匠125 匠箒 短柄(Amazon)

ドライヤーを使うとキレイに剥がれます。柄にシールのベタベタが少し残りますが、中性洗剤をティッシュに付けて擦れば落とせます。

ドライヤーを使うときは、シールを熱して無理せず剥がせるようになってから、少しづつゆっくりと剥がしていけば、下記のようにシールを破らずに剥がすことができます。


商品タグ止め

「US103 床を優しく掃けるほうきS」も同じでしたが、商品タグが太いステープラーで箒に打ち込まれています。

これは、マイナスドライバーを差し込んでテコの原理で引き抜けます。


掃除を見直そう

「なぜ掃除機を使うのか?」ということに疑問を持つこともなく、掃除機を使い続けていました。掃除の基本である「掃いて」「拭く」を改めて考えるきっかけとなったのは、コロナ禍の新しいライフスタイルからです。

時間のない生活下では、ロボット掃除機という選択肢は考えましたが、箒で掃き掃除をしようという発想はありませんでした。

しかし、実際に箒を使ってみると「掃除=掃除機」という固定概念がなくなり、掃除機の必然性も感じなくなりました。

下記のブログも併せて読んで、フローリングワイパー、粘着式クリーナーと組み合わせて、テレワーク前の朝の掃除時間を楽しんでください。


象と散歩:人気の投稿(過去7日間)