質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
LINE Messaging API

LINE Messaging APIは、メッセージの送信・返信ができるAPIです。Web APIを経由しアプリケーションサーバとLINEのAPIでやり取りが可能。複数のメッセージタイプや分かりやすいAPIリファレンスを持ち、グループチャットにも対応しています。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

1314閲覧

LINEbotで応答しない【初心者】

Qchan.8

総合スコア2

LINE Messaging API

LINE Messaging APIは、メッセージの送信・返信ができるAPIです。Web APIを経由しアプリケーションサーバとLINEのAPIでやり取りが可能。複数のメッセージタイプや分かりやすいAPIリファレンスを持ち、グループチャットにも対応しています。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2023/01/03 17:00

編集2023/01/04 05:57

前提

LINE bot初心者です。
LINEbotで診断テストを作っているのですが、スプレッドシートに書かれた結果を読み取り、送信することができず困っています。アドバイスなど教えて頂けると嬉しいです。

実現したいこと

  1. 「Shitsumon_2」のテンプレートボタンをメッセージとして送信→成功

  2. LINE側で「Shitsumon_2」の選択ボタンを押す。→成功

  3. 選択肢1の場合、「result_ok_1」へイベントを送る。

  4. 「getdatafromSheet」にeventと「result_ok_1」のデータを送る。

3と4のように、選択肢に合った回答をスプレッドシートから読み取り、結果をメッセージとして送信したいのですが、ボタンを押してもLINE botから応答がなく困っています。解決策やアドバイスなどありましたら、教えて頂けると嬉しいです。

発生している問題・エラーメッセージ

実行後、エラーはないのですが、別のスプレッドシートのlogは何も記載されず、LINE botの応答がありません。

該当のソースコード

JavaScript

1const CHANNEL_ACCESS_TOKEN = "F3a+******Xj5RDIIWFm/FstrDv/pRPCHpcsm8ulh9XWGpJHjbfXEKhlYczFfdLlvcmUz61BB6eiuAj9l2pgp2/FyXnyBJbBdO5dDYIbiuMw0Uu8x2s8XQeOexUDJHqjI5bggI5gdB04t89/1O/w1cDnyilFU="; 2const url = "https://api.line.me/v2/bot/message/reply"; 3const spreadsSheet = SpreadsheetApp.openById("****GJFdlDY5Zs72mH293qM_qIGynSTk"); 4 5const push_url = "https://api.line.me/v2/bot/message/push"; 6 7function doPost(e) { 8 try { 9 doPostProxy(e); 10 } catch (err) { 11 debug(JSON.stringify(err.stack || err.message, undefined, 1)); 12 }//例外処理 13} 14//dopostの関数定義 15function doPostProxy(e) { 16 var json = e.postData.contents 17 //返信するためのJSONの取得 18 var events = JSON.parse(json).events; 19 events.forEach(function (event) { 20 if (event.type == "follow") {//① 21 shokaibun_1(event);//①→2 22 }//相手が友達追加したら場合のみ起きる。 23 else if (event.type == "message"){ 24 var reply_message = event.message.text; 25 //shokaibun_1(event); 26 if("スタート" === reply_message) { 27 var reply_message = event.message.text; 28 shitsumon_2(event); 29 } 30 } 31 32//ここからスプレッドシート「rensyu」用のコード 33 else if(event.type == "postback"&& JSON.parse(event.postback.data).action==="aite_senpai"){//(38) 34 getresultFromSheet(event,result_ok_1(event)); 35 }else if(event.type == "postback"&& JSON.parse(event.postback.data).action==="aite_kohai"){//(38) 36 getresultFromSheet(event,result_ok_2(event)); 37 } 38 if (typeof replyToken === 'undefined') { 39 return; 40 } 41 } 42 ); 43}; 44 //質問文2 45 function shitsumon_2(e) {//(5) 46 let Msg2 = { 47 "replyToken" : e.replyToken, 48 "messages" : [ 49 { 50 "type": "template", 51 "altText": "選択", 52 "template": { 53 "type": "buttons", 54 "title": "誰に送る?", 55 "text": "誰に送る?", 56 "actions": [ 57 { 58 "type": "postback", 59 "label": "選択1", 60 "text": "送る相手は\n選択1", 61 "data": JSON.stringify({"action":"aite_senpai"}) 62 }, 63 { 64 "type": "postback", 65 "label": "選択2", 66 "text": "送る相手は\n選択2", 67 "data": JSON.stringify({"action":"aite_kohai"}) 68 } 69 ] 70 } 71 } 72 ] 73 }; 74 75 let pro_2 = { 76 "method" : "post", 77 "headers" : { 78 "Content-Type" : "application/json", 79 "Authorization" : "Bearer " + CHANNEL_ACCESS_TOKEN 80 }, 81 82 "payload" : JSON.stringify(Msg2) 83 }; 84 var response = UrlFetchApp.fetch(url, pro_2); 85 // return response.getResponseCode(); 86 return ContentService.createTextOutput(JSON.stringify({ 87 'content': 'post ok' 88 })).setMimeType(ContentService.MimeType.JSON); 89 }; 90//最終選択まとめ1 91function result_ok_1(e){ 92 var sheet = spreadsSheet.getSheetByName('rensyu'); 93 //スプレッドシートの読み込み 94 var replytextList1 = sheet.getRange('D2').getValue();//D2のデータを設定。 95 //シートの全受信語句と返信語句を二次元配列で取得する//(2,8)→(2,45):F45まで 96 //返信語句を格納するための空配列を宣言する 97 return replytextList1; 98}; 99//最終選択まとめ2 100function result_ok_2(e){ 101 var sheet = spreadsSheet.getSheetByName('rensyu'); 102 //スプレッドシートの読み込み 103 var replytextList1 = sheet.getRange('D3').getValue();//D3のデータを設定。 104 //シートの全受信語句と返信語句を二次元配列で取得する//(2,8)→(2,45) 105 //返信語句を格納するための空配列を宣言する 106 return replytextList1; 107}; 108 109//スプレッドシートの中の結果を配列に移動させ、出力するプログラム 110function getresultFromSheet(e,replyTextList){ 111 //var reply_token = data.events[0].replyToken;//→replyTOkenの引き渡しとeventの設定(12/26) 112 //LINEで受信した語句がシートの受信語句と一致しない場合、関数を終了する 113 if(replyTextList.length < 1) { 114 return;//何もセル内にテキストが含まれていないとき 115 } else if(replyTextList.length > 5) {//5個以上のメッセージがセルの中に含まれているとき 116 var messageLength = 5; 117 } else {//1つ以上5個未満のメッセージがセルの中に含まれている時 118 var messageLength = replyTextList.length; 119 } 120 var messageArray = []; 121 122 for(var j = 0; j < messageLength; j++) { 123 messageArray.push({"type": "text", "text": replyTextList[j]}); 124 } 125 var postData = { 126 "replyToken" : e.replyToken, 127 "messages" : messageArray, 128 }; 129 let option1 = { 130 "method" : "post", 131 "headers" : { 132 "Content-Type" : "application/json", 133 "Authorization" : "Bearer " + CHANNEL_ACCESS_TOKEN 134 }, 135 "payload" : JSON.stringify(postData), 136 "muteHttpExceptions" : true, 137 "validateHttpCertificates" : false, 138 "followRedirects" : false 139 }; 140 try{ 141 var response = UrlFetchApp.fetch(push_url, option1); 142 Logger.log(response); 143 144 }catch(e) { 145 // 例外エラー処理 146 Logger.log("Error:"); 147 Logger.log(e); 148 } 149 }; 150 151//エラー処理 152function debug(message) { 153 spreadsSheet.getSheetByName('log').appendRow([message]); 154} 155 156 157

試したこと

・編集後、新しくデプロイしWebhookのURLを更新。
・スプレッドシート名、URLの確認

補足情報(FW/ツールのバージョンなど)

参考にしたサイト:

  1. https://uxmilk.jp/25841「スプレッドシートの読み取り方法についてまとめられたもの」
  2. https://www.yukibnb.com/entry/linemessagingapi_sheet#%E8%A4%87%E6%95%B0%E3%81%AE%E5%90%B9%E3%81%8D%E5%87%BA%E3%81%97%E3%82%92LINE-BOT%E3%81%AB%E8%BF%94%E4%BF%A1%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84%E5%A0%B4%E5%90%88「スプレッドシートの一つのセル内に複数の文字が含まれている場合の読み取りと出力方法についてまとめられたもの」

スプレッドシートはこのようになっています。
イメージ説明|列1|列2|列3|
|:--|:--:|--:|
||||
コードを書き換える度、デプロイとWebhookのURLを新しく更新しています。
アクセスするユーザーは全員としました。
LINE botでのメッセージの取得、カーセルボタンによる分岐は上手くいったのですが、スプレッドシートに書かれた結果を取得し、送ることがうまく出来ず困っています。
お手隙の方、解決方法等、ご教示頂きたいです。よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2023/01/03 22:27

ご自身のプログラムがどのように動作しているか確認されたのでしょうか?
yuma.inaura

2023/01/04 01:18

スプレッドシートを介さずLINE bot を反応させることには成功しているんでしょうか?
Qchan.8

2023/01/04 05:51

お返事ありがとうございます。スプレッドシートの部分以外は動作しており、LINE botからメッセージを受け取り、返事も送ることはできているのですが、スプレッドシートとの連携とデータの取得の部分が上手くいっていません。
YAmaGNZ

2023/01/04 06:15

>スプレッドシートとの連携とデータの取得の部分が上手くいっていません。 ということはどこが正常に動作していないのか確認出来ているということですか? そうなのであればどこか提示してください。
Qchan.8

2023/01/04 06:39

・33〜34、91〜98行目、110〜149行目 ・35〜36、100〜149行目 にかけてがそれぞれスプレッドシートの一つのセルの中のデータを取得、LINE botに送信する部分になり、正常に動作していません。 ・15から89行目までは正常に動作しています。(33から37行目を除く) よろしくお願いいたします。
YAmaGNZ

2023/01/04 08:33

33~34行となると、そもそもevent.typeの値によって91~とか上げている関数が呼ばれていないだけなどあるじゃないですか なのでevent.typeの値などをログに出力するなりしてデバッグする必要があるわけです。 result_ok_1やresult_ok_2の関数だったらLINEの応答とは直接関係なさそうですし 関数単体でのテストも行えそうです。 そのあたりを確認しましたかということです。
Qchan.8

2023/01/04 11:02

アドバイスありがとうございます。早速、result_ok_1とresult_ok_2は両方とも、ログで確認し、スプレッドシートの値を読み取ることができたのですが、LINEbotに送るとなると何も送られなくなってしまいます。今のコードより、分解して一つずつ調べているのですが、まだなぜ何も送られてこないのか解明していないため、アドバイスなどありましたら、教えてくださると嬉しいです。
YAmaGNZ

2023/01/04 11:41

Shitsumon_2の選択ボタンを押した時にスクリプトが動作しているのは確認しましたか? その時33行目のif文の条件を満たすのかどうかを確認しましたか? event.typeの値はどうなっていますか? event.postback.dataの値は? JSON.parse(event.postback.data).actionの値は? ご自身の作成したスクリプトがどこまで動いているのか確認しましょう。 そして、想定している部分が動いていないのであれば、そこが動くための条件を満たしているのかを確認しましょう。
guest

回答2

0

アドバイスを頂き、ありがとうございます。配列やfor文を使ったものの理解がまだ勉強不足と感じたため、これらを使わず一つの値だけをセルから取り出すプログラムを複数書く方法で行ったら、スプレッドシートから値を取り出しLINE botに送信することができました。
この方法だと、プログラムのFanctionがあまりにも多く、大変だったため、頂いたアドバイスを基に配列を用いたものにももう一度、挑戦し直したいと思います。また、つまずいた際に知恵を貸して頂けると嬉しいです。ありがとうございます。

投稿2023/01/04 18:04

Qchan.8

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

実行後、エラーはないのですが、別のスプレッドシートのlogは何も記載されず、LINE botの応答がありません。

→エラーはないとのことですが、実際にはエラーは発生しています。
しかし質問者さん自身のオリジナルレシピコードのせいで、そのエラー内容がシートに表示されなくなっています。

140行目から149行目の

js

1 try{ 2 var response = UrlFetchApp.fetch(push_url, option1); 3 Logger.log(response); 4 5 }catch(e) { 6 // 例外エラー処理 7 Logger.log("Error:"); 8 Logger.log(e); 9 } 10 };

により、(仮に)例外が発生すると Logger.log の行が実行されます。しかしWebアプリなので(プロジェクトをGCPに紐付けていない限り)ログ内容をエディタで確認することはできません。

もともとエラーログを確認できるように、doPost を try ~ catch で囲んでいますが、さらに内部に try ~ catchを設置して(つまり上記の try ~ catch で)処理されてしまうと、(そのcatch内で例外が発生しない限り) doPost側 の catch には移行しません。
結果、ログシートにエラーが記録されなくなっています。
ここは、try~catch を挟む必要はありません。また doPostの処理中に Logger や console を使っても、GCPに紐付けていない限りエディタのログに表示されないので、シートに出力するようにします。

js

1 var response = UrlFetchApp.fetch(url, option); 2 debug(response.getContentText(); // Logger.log/console.log とすると内容が確認できないのでシートに出力。 3 // doPost を try~catch で囲んでいるのでここをさらに囲む必要はない

エラーと修正

じゃあ具体的なエラーは何なのか、という話。

1つ目は、カルーセルで選択した後のリプライをプッシュメッセージで送っている点です。
141行目

js

1 var response = UrlFetchApp.fetch(push_url, option1);

プッシュメッセージは、あて先(toプロパティー)なしで送れません。(エラーになる)
ここは、メッセージデータにリプライトークンを付けていることから、

js

1 var response = UrlFetchApp.fetch(url, option1);

としたかったのだと推測しました。


2つ目は、スプレッドシートから渡す返信データが(渡し方がまずいために)不正なデータとして扱われてしまう場合があるという点です。
スプレッドシートのrensyu シート画像を見るに、カルーセル選択後に返信するデータは、セル内改行されています。
選択肢1を選んだときに返信する文字は、画像の通りであれば
A
B
C
というものですが、これを元質問のコードで処理した場合 replyTextListは「A\nB\nC\n」という文字列になります。
そして getresultFromSheet 関数の 122~124行目

js

1 for(var j = 0; j < messageLength; j++) { 2 messageArray.push({"type": "text", "text": replyTextList[j]}); 3 }

という処理によって、messageArray は ['A', '\n', 'B', '\n', 'C', '\n']という配列になります。
つまり改行を含めて1文字ずつ区切られてしまうわけです。

これを LINE BOTでリプライメッセージとして返信させようとすると、2文字目の「\n」という改行文字を処理した時点で下記のようなエラーが返ってきて失敗します。

{"message":"May not be empty","property":"messages[1].text"}

なぜなら、改行文字1文字だけでは、テキストの内容が空(empty)であると判定されてしまうからです。

(参考にしたとされる記事内容との整合性はひとまず置いといて)ここは改行文字で区切った配列を replyTextList として getresultFromSheet 関数に渡せばよいでしょう。

diff

1 //ここからスプレッドシート「rensyu」用のコード 2 else if (event.type == "postback" && JSON.parse(event.postback.data).action === "aite_senpai") {//(38) 3- getresultFromSheet(event, result_ok_1(event)); 4+ getresultFromSheet(event, result_ok_1(event).split('\n'));

js

12//dopostの関数定義 3function doPostProxy(e) { 4 var json = e.postData.contents 5 //返信するためのJSONの取得 6 var events = JSON.parse(json).events; 7 8 events.forEach(function (event) { 9 if (event.type == "follow") {//① 10 shokaibun_1(event);//①→2 11 }//相手が友達追加したら場合のみ起きる。 12 else if (event.type == "message") { 13 var reply_message = event.message.text; 14 //shokaibun_1(event); 15 if ("スタート" === reply_message) { 16 var reply_message = event.message.text; 17 shitsumon_2(event); 18 } 19 } 20 21 //ここからスプレッドシート「rensyu」用のコード 22 else if (event.type == "postback" && JSON.parse(event.postback.data).action === "aite_senpai") {//(38) 23 getresultFromSheet(event, result_ok_1(event).split('\n')); 24 } else if (event.type == "postback" && JSON.parse(event.postback.data).action === "aite_kohai") {//(38) 25 getresultFromSheet(event, result_ok_2(event).split('\n')); 26 } 27 if (typeof replyToken === 'undefined') { 28 return; 29 } 30 } 31 ); 32}; 33 34//質問文2 35function shitsumon_2(e) {//(5) 3637}; 38 39//最終選択まとめ1 40function result_ok_1(e) { 4142}; 43//最終選択まとめ2 44function result_ok_2(e) { 4546}; 47 48//スプレッドシートの中の結果を配列に移動させ、出力するプログラム 49function getresultFromSheet(e, replyTextList) { 50 logger(replyTextList) 51 //var reply_token = data.events[0].replyToken;//→replyTOkenの引き渡しとeventの設定(12/26) 52 //LINEで受信した語句がシートの受信語句と一致しない場合、関数を終了する 53 if (replyTextList.length < 1) { 54 return;//何もセル内にテキストが含まれていないとき 55 } else if (replyTextList.length > 5) {//5個以上のメッセージがセルの中に含まれているとき 56 var messageLength = 5; 57 } else {//1つ以上5個未満のメッセージがセルの中に含まれている時 58 var messageLength = replyTextList.length; 59 } 60 var messageArray = []; 61 62 for (var j = 0; j < messageLength; j++) { 63 messageArray.push({ "type": "text", "text": replyTextList[j] }); 64 } 65 66 var postData = { 67 "replyToken": e.replyToken, 68 "messages": messageArray, 69 }; 70 71 let option1 = { 72 "method": "post", 73 "headers": { 74 "Content-Type": "application/json", 75 "Authorization": "Bearer " + CHANNEL_ACCESS_TOKEN 76 }, 77 "payload": JSON.stringify(postData), 78 "muteHttpExceptions": true, 79 "validateHttpCertificates": false, 80 "followRedirects": false 81 }; 82 83 var response = UrlFetchApp.fetch(url, option1); 84 if (response.getResponseCode() !== 200) { 85 throw new Error(response.getContentText()); 86 } 87 88}; 89以下略

投稿2023/01/04 14:24

編集2023/01/04 14:44
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問