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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

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

Twitter

Twitterは、140文字以内の「ツイート」と呼ばれる短文を投稿できるサービスです。Twitter上のほぼ全ての機能に対応するAPIが存在し、その関連サービスが多く公開されています。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

Q&A

解決済

1回答

2738閲覧

スプレッドシートにある検索ワードをtwitterで検索し、ツイートにいいね or RTをする。その後、この動作を一定期間毎に繰り返すBotを作成したいのですが、動作を繰り返しません。

cusmix

総合スコア2

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

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

Twitter

Twitterは、140文字以内の「ツイート」と呼ばれる短文を投稿できるサービスです。Twitter上のほぼ全ての機能に対応するAPIが存在し、その関連サービスが多く公開されています。

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

0グッド

1クリップ

投稿2021/11/21 02:49

前提・実現したいこと

Google Apps Scriptで動作するTwitter Botを作成中です。

スプレッドシートにある検索ワードをtwitterで検索し、ツイートにいいね or RTをする。その後、この動作を一定期間毎に繰り返すBotを作成したいです。

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

下記の記事を参考にさせていただき、動作させようとしています。

https://moripro.net/gas-twitter-bot/
https://teratail.com/questions/240990

スプレッドシートの検索キーワードで検索した、最終TweetIDがスプレッドシートに上書きされて、その後、それをもとに、

"Twitteを検索"→"スプレッドシートの最終TweetIDが更新"→いいね or RTをする→"最終TwitterID以降で、検索ワードをTwitterで検索"

としたいのですが、スプレッドシートの最終TweetIDが更新されません。

こちらについて、前回の質問と同じくなのですが、ご回答いただくために、不足情報が何かもわからない状況です。そのあたりから、ご教示いただきたいです。

現在のソースコード

//認証用インスタンスの生成 var twitter = TwitterWebService.getInstance( '         ',//API Key '         '//API secret key ); // 認証 function authorize() { twitter.authorize(); } // 認証解除 function reset() { twitter.reset(); } // 認証後のコールバック function authCallback(request) { return twitter.authCallback(request); } // セルを取得 var sheetData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1"); // 「シート1」はシート名 /** いいね or RT 機能 ① 検索ワードをスプレッドシートから取得する ② 検索ワードをTwitterで検索する(たくさん取れてしまうので「直近10分間」の検索を10分毎に行う) ③ ツイートに いいね or RT をする ④ 他に検索ワードがあれば②に戻る */ // ツイートを検索する // 【参考】 https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets function findTweets (searchWord, lastTweetId) { var service = twitter.getService(); var query = { q: searchWord, // 検索ワード lang: 'ja', // 日本語検索 locale: 'ja', // 日本限定で検索 result_type: 'recent', // 直近のツイートを検索 since_id: lastTweetId // これ以前のツイートは見ない } // 検索の内容を queryStr にまとめていく var queryStr = ''; for (var key in query) { // URLに日本語や記号を付けると上手く検索できないことがあるので#も変換する encodeURIComponent をする queryStr += key + '=' + encodeURIComponent(query[key]) + '&' } // &が余計に付いているので削除しておく var queryStr = queryStr.slice(0, -1); var response = service.fetch('https://api.twitter.com/1.1/search/tweets.json?' + queryStr); var result = JSON.parse(response) return result.statuses } function main () { // ① 検索ワードをスプレッドシートから取得する var searchWords = pickUpSearchWords(); // searchWordsの中身は // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'],....,] // という形式になっているので1つずつ見ていく for (var i = 0, il = searchWords.length; i < il; i++ ) { var searchWord = searchWords[i][0]; var type = searchWords[i][1]; var lastTweetId = searchWords[i][2]; // !!!!!! 追加 !!!!!!! var limit = searchWords[i][3]; // ② Twitterで検索する var tweetList = findTweets(searchWord, lastTweetId); var count = 0 // ③ 複数件ツイートを取得されるので for を使って1つずつツイートを取り出し いいね or RT をする for (var j = 0, jl = tweetList.length; j < jl; j++ ) { var tweet = tweetList[j]; if (tweet.id_str > lastTweetId) { lastTweetId = tweet.id_str; } // !!!!!! 追加 !!!!!!! if (count == limit) { // lastTweetIdを出来るだけ新しくしたい場合は continue; // 次回以降の実行で続きのツイートを使いたい場合は break; break; } count++; if (type == 'いいね') { putFavorite (tweet); } else if (type == 'RT') { putRetweet (tweet); } } // 最新のツイートIDを保存して重複処理をしないようにする var titleRow = 1; // 『検索ワード』とか書いている部分の行数 var lastTweetIdCol = 3; // 『最終TweetId』の列までなので3列目まで var updateCell = sheetData.getRange(i + 1 + titleRow, lastTweetIdCol, 1, 1); // i = 0 の時1行目なので+1してる updateCell.setValue(lastTweetId); } } // 検索ワードをスプレッドシートから取得する function pickUpSearchWords () { var titleRow = 1; // 『検索ワード』とか書いている部分の行数 var startRow = 1 + titleRow; // 1行目は『検索ワード』とか書いているので2行目から var startCol = 1; var endRow = sheetData.getLastRow() - titleRow; // 最後の行まで(2行目から始まっているので-1している) // !!!!!! 変更 !!!!!!! var endCol = 4; // 『実行回数』の列までなので4列目まで // 一括で取得する var cells = sheetData.getRange(startRow, startCol, endRow, endCol).getValues(); // cellsの中身は // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] ,....,] // という形式になる return cells; }

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

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

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

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

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

CHERRY

2021/11/21 14:04

> ReferenceError: 「putRetweet」が定義されていません。 > (中略) > というエラーが出てしまいました。 質問に記載されれているコードに putRetweet はないようですが、どこかに記載されていますか?
cusmix

2021/11/21 14:26

CHERRYさん、 コードがわかりづらくて申し訳ございません。 下記の点線で囲まれている場所で、表現してみました。 (どのように表現したらよいか分からず、お伝えすることが出来れば良いのですが...) ----------------------- 、、、 ここがエラーの箇所です。 putRetweet (tweet); 、、、 ----------------------- 下記が質問のコードに、エラー箇所を書き加えたものです。 -------------------------------------- //認証用インスタンスの生成 var twitter = TwitterWebService.getInstance( '         ',//API Key '         '//API secret key ); // 認証 function authorize() { twitter.authorize(); } // 認証解除 function reset() { twitter.reset(); } // 認証後のコールバック function authCallback(request) { return twitter.authCallback(request); } // セルを取得 var sheetData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1"); // 「シート1」はシート名 /** いいね or RT 機能 ① 検索ワードをスプレッドシートから取得する ② 検索ワードをTwitterで検索する(たくさん取れてしまうので「直近10分間」の検索を10分毎に行う) ③ ツイートに いいね or RT をする ④ 他に検索ワードがあれば②に戻る */ // ツイートを検索する // 【参考】 https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets function findTweets (searchWord, lastTweetId) { var service = twitter.getService(); var query = { q: searchWord, // 検索ワード lang: 'ja', // 日本語検索 locale: 'ja', // 日本限定で検索 result_type: 'recent', // 直近のツイートを検索 since_id: lastTweetId // これ以前のツイートは見ない } // 検索の内容を queryStr にまとめていく var queryStr = ''; for (var key in query) { // URLに日本語や記号を付けると上手く検索できないことがあるので#も変換する encodeURIComponent をする queryStr += key + '=' + encodeURIComponent(query[key]) + '&' } // &が余計に付いているので削除しておく var queryStr = queryStr.slice(0, -1); var response = service.fetch('https://api.twitter.com/1.1/search/tweets.json?' + queryStr); var result = JSON.parse(response) return result.statuses } function main () { // ① 検索ワードをスプレッドシートから取得する var searchWords = pickUpSearchWords(); // searchWordsの中身は // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'],....,] // という形式になっているので1つずつ見ていく for (var i = 0, il = searchWords.length; i < il; i++ ) { var searchWord = searchWords[i][0]; var type = searchWords[i][1]; var lastTweetId = searchWords[i][2]; // !!!!!! 追加 !!!!!!! var limit = searchWords[i][3]; // ② Twitterで検索する var tweetList = findTweets(searchWord, lastTweetId); var count = 0 // ③ 複数件ツイートを取得されるので for を使って1つずつツイートを取り出し いいね or RT をする for (var j = 0, jl = tweetList.length; j < jl; j++ ) { var tweet = tweetList[j]; if (tweet.id_str > lastTweetId) { lastTweetId = tweet.id_str; } // !!!!!! 追加 !!!!!!! if (count == limit) { // lastTweetIdを出来るだけ新しくしたい場合は continue; // 次回以降の実行で続きのツイートを使いたい場合は break; break; } count++; if (type == 'いいね') { putFavorite (tweet); } else if (type == 'RT') { 、、、 ここがエラーの箇所です。 putRetweet (tweet); 、、、 } } // 最新のツイートIDを保存して重複処理をしないようにする var titleRow = 1; // 『検索ワード』とか書いている部分の行数 var lastTweetIdCol = 3; // 『最終TweetId』の列までなので3列目まで var updateCell = sheetData.getRange(i + 1 + titleRow, lastTweetIdCol, 1, 1); // i = 0 の時1行目なので+1してる updateCell.setValue(lastTweetId); } } // 検索ワードをスプレッドシートから取得する function pickUpSearchWords () { var titleRow = 1; // 『検索ワード』とか書いている部分の行数 var startRow = 1 + titleRow; // 1行目は『検索ワード』とか書いているので2行目から var startCol = 1; var endRow = sheetData.getLastRow() - titleRow; // 最後の行まで(2行目から始まっているので-1している) // !!!!!! 変更 !!!!!!! var endCol = 4; // 『実行回数』の列までなので4列目まで // 一括で取得する var cells = sheetData.getRange(startRow, startCol, endRow, endCol).getValues(); // cellsの中身は // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] ,....,] // という形式になる return cells; }
guest

回答1

0

ベストアンサー

ソースコード自体に問題はないと思います。

最初に「シート1」に下記のように入力してmain()関数を実行したところ
正常にスプレッドシート上のlastTweetIdが更新されました。(セルC2)

【実行前】
イメージ説明

【実行後】
イメージ説明

 

lastTweetIdが更新されない理由として、
条件(「lastTweetId以降」)にあてはまるツイートが1件も取得できていない可能性が考えられます。

(その背景として、シート1上の検索ワードが、それほど頻繁につぶやかれている単語ではない、ということが考えられます)

初回、lastTweetID(C列)を空欄または0にしてスクリプトを実行すると、
lastTweetIdは取得したツイートの最大IDに更新されます。

ただし、Twitter APIのデータ反映にはタイムラグがあります。

ブラウザやTwitterアプリ上で当該検索ワードを含む新しいツイートがあるように見えても、
一定時間経過しないと、APIでは当該ツイート(直近で取得したtweetIdより後のツイート)が取得できないことがあります。

(なお、上記の画像の場合「Twitter」という単語を含むツイートは世界中で常時つぶやかれているため、
10秒間隔で実行しても、シート1上のlastTweetIdは実行する度更新されます)


追記(コメントより)

20:39:36 お知らせ 実行開始
20:39:37 エラー
ReferenceError: 「putRetweet」が定義されていません。
main @ コード.gs:94

というエラーが出てしまいました。

とのことですが、これはメッセージの通り、putRetweetという関数がどこにも定義されていないのにputRetweetを呼び出そうとしたからです。

下記のように、putRetweetやputFavoritesを実装する必要があります。
(下記ソースコードの「以下追加」以降の部分)
(前の御質問のコメント記載のソースを参考にして修正)

下記を保存の上、シート1のB列を「RT」、C列を空欄、D列を10等にして実行すると、
検索ワードを含むツイートが自動でRTされ、C列は最新のlastTweetIdに更新されると思います。
(※実行時にシート1のD列にも数字を入れる必要があります。D列が空欄だとRTやいいねが実行されません)

なお、一定時間内に大量にキーワード検索や、RT・Fav(「いいね」)を実行した場合、API制限がかかってしばらく検索・RT・Favができなく場合があるので、実行する際は注意してください。

追記2

該当部分に、コードを追加したところ、新たにエラーが出てしまったので、

すでにリツイート済みのツイートに重ねてリツイートしようとしたり、
すでにいいねが済んでいるツイートに、重ねて「いいね」をしようとしたため、エラーで停止しています。

下記コードについて、エラーが発生しても停止せずエラー内容を表示するように修正しました。
(try ~ catch文で囲む)

 

① 検索ワードをスプレッドシートから取得する
② 検索ワードをTwitterで検索する(たくさん取れてしまうので「直近10分間」の検索を10分毎に行う)
③ ツイートに いいね or RT をする
④ 他に検索ワードがあれば②に戻る
の順番通りにコードを並べる必要があるのかと思い

実際のところ、順番通りに並べる必要はありません。
呼び出し元より後ろにある関数であっても、自動的に探して認識してくれます。
今回のエラーの原因は、上述のようにリツイート済みのツイートに重ねてリツイートしようとしたためです。

さらに、putRetweet関数や、putFavorite関数を直接実行されようとしたのではないでしょうか。

putRetweet関数や、putFavorite関数は、main()関数から呼び出される専用の関数です。

元のコードで、putRetweet関数や、putFavorite関数を直接実行すると、引数tweetが空っぽ(undefined)のため、
「undefined からプロパティ「id_str」を読み取れません。」というエラーが発生します。

下記のコードでは、putRetweet関数や、putFavorite関数を直接実行してしまった場合、引数tweetが空かどうかを判定し、空の場合はreturnすることでエラー停止を回避するように修正しました。

このプログラムは(一度authorize()関数を実行してTwitter認証が完了していれば)基本的に、main()を実行するだけでよいです。(main()以外を実行しても正常に動作しません)

【回答コード(全体)】

js

1//認証用インスタンスの生成 2var twitter = TwitterWebService.getInstance( 3 '         ',//API Key 4 '         '//API secret key 5); 6 7// 認証 8function authorize() { 9 twitter.authorize(); 10} 11 12// 認証解除 13function reset() { 14 twitter.reset(); 15} 16 17// 認証後のコールバック 18function authCallback(request) { 19 return twitter.authCallback(request); 20} 21 22// セルを取得 23var sheetData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1"); // 「シート1」はシート名 24 25/** 26 いいね or RT 機能 27 ① 検索ワードをスプレッドシートから取得する 28 ② 検索ワードをTwitterで検索する(たくさん取れてしまうので「直近10分間」の検索を10分毎に行う) 29 ③ ツイートに いいね or RT をする 30 ④ 他に検索ワードがあれば②に戻る 31*/ 32// ツイートを検索する 33// 【参考】 https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets 34function findTweets (searchWord, lastTweetId) { 35 var service = twitter.getService(); 36 var query = { 37 q: searchWord, // 検索ワード 38 lang: 'ja', // 日本語検索 39 locale: 'ja', // 日本限定で検索 40 result_type: 'recent', // 直近のツイートを検索 41 since_id: lastTweetId // これ以前のツイートは見ない 42 } 43 // 検索の内容を queryStr にまとめていく 44 var queryStr = ''; 45 for (var key in query) { 46 // URLに日本語や記号を付けると上手く検索できないことがあるので#も変換する encodeURIComponent をする 47 queryStr += key + '=' + encodeURIComponent(query[key]) + '&' 48 } 49 // &が余計に付いているので削除しておく 50 var queryStr = queryStr.slice(0, -1); 51 52 var response = service.fetch('https://api.twitter.com/1.1/search/tweets.json?' + queryStr); 53 var result = JSON.parse(response) 54 return result.statuses 55} 56 57function main () { 58 // ① 検索ワードをスプレッドシートから取得する 59 var searchWords = pickUpSearchWords(); 60 61 // searchWordsの中身は 62 // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'],....,] 63 // という形式になっているので1つずつ見ていく 64 for (var i = 0, il = searchWords.length; i < il; i++ ) { 65 var searchWord = searchWords[i][0]; 66 var type = searchWords[i][1]; 67 var lastTweetId = searchWords[i][2]; 68 69 // !!!!!! 追加 !!!!!!! 70 var limit = searchWords[i][3]; 71 72 // ② Twitterで検索する 73 var tweetList = findTweets(searchWord, lastTweetId); 74 75 var count = 0 76 // ③ 複数件ツイートを取得されるので for を使って1つずつツイートを取り出し いいね or RT をする 77 for (var j = 0, jl = tweetList.length; j < jl; j++ ) { 78 var tweet = tweetList[j]; 79 if (tweet.id_str > lastTweetId) { 80 lastTweetId = tweet.id_str; 81 } 82 83 // !!!!!! 追加 !!!!!!! 84 if (count == limit) { 85 // lastTweetIdを出来るだけ新しくしたい場合は continue; 86 // 次回以降の実行で続きのツイートを使いたい場合は break; 87 break; 88 } 89 count++; 90 91 if (type == 'いいね') { 92 putFavorite (tweet); 93 } else if (type == 'RT') { 94 putRetweet (tweet); 95 } 96 } 97 98 // 最新のツイートIDを保存して重複処理をしないようにする 99 var titleRow = 1; // 『検索ワード』とか書いている部分の行数 100 var lastTweetIdCol = 3; // 『最終TweetId』の列までなので3列目まで 101 var updateCell = sheetData.getRange(i + 1 + titleRow, lastTweetIdCol, 1, 1); // i = 0 の時1行目なので+1してる 102 updateCell.setValue(lastTweetId); 103 } 104} 105 106// 検索ワードをスプレッドシートから取得する 107function pickUpSearchWords () { 108 var titleRow = 1; // 『検索ワード』とか書いている部分の行数 109 var startRow = 1 + titleRow; // 1行目は『検索ワード』とか書いているので2行目から 110 var startCol = 1; 111 var endRow = sheetData.getLastRow() - titleRow; // 最後の行まで(2行目から始まっているので-1している) 112 113 // !!!!!! 変更 !!!!!!! 114 var endCol = 4; // 『実行回数』の列までなので4列目まで 115 116 // 一括で取得する 117 var cells = sheetData.getRange(startRow, startCol, endRow, endCol).getValues(); 118 119 // cellsの中身は 120 // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] ,....,] 121 // という形式になる 122 123 return cells; 124} 125 126// ------------------------------以下追加------------------------------ 127 128// いいね を付ける 129// 【参考】 https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-create 130function putFavorite(tweet) { 131 // tweetが空っぽ(undefined)の場合はreturn 132 if (typeof tweet === "undefined") return; 133 var service = twitter.getService(); 134 var options = { method: 'post' }; 135 // エラーが発生したら、catchのブロックにジャンプ。 136 try { 137 service.fetch('https://api.twitter.com/1.1/favorites/create.json?id=' + tweet.id_str, options); 138 } catch(e) { 139 // メッセージに「"code":139」という文字列が含まれている場合は、内容を表示 140 if (e && e.message.indexOf('{"code":139') > -1) { 141 Logger.log("このツイートにはすでに「いいね」を押しています。\n[id] "+tweet.id_str +" [username]" + tweet.user.name + "\n[tweet]「"+ tweet.text.slice(0, 40) + "...」"); 142 } else { 143 Logger.log("エラー:" + e.message) 144 } 145 } 146} 147 148// RT を付ける 149// 【参考】 https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id 150function putRetweet(tweet) { 151 // tweetが空っぽ(undefined)の場合はreturn 152 if (typeof tweet === "undefined") return; 153 var service = twitter.getService(); 154 var options = { method: 'post' }; 155 // エラーが発生したら、catchのブロックにジャンプ。 156 try { 157 service.fetch('https://api.twitter.com/1.1/statuses/retweet/' + tweet.id_str +'.json', options); 158 } catch(e) { 159 // メッセージに「"code":327」という文字列が含まれている場合は、内容を表示 160 if (e && e.message.indexOf('{"code":327') > -1) { 161 Logger.log("このツイートはすでにリツイート済みです。\n[id] "+tweet.id_str +" [username]" + tweet.user.name + "\n[tweet]「"+ tweet.text.slice(0, 40) + "...」"); 162 } else { 163 Logger.log("エラー:" + e.message) 164 } 165 } 166}

投稿2021/11/21 05:21

編集2021/11/23 07:51
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

cusmix

2021/11/21 11:50

qnoirさん、 何度もご回答いただき、ありがとうございます。 確かに、検索ワードがマイナーなワードではあると思います。 こちらの記事を参考に、今回RTさせたいハッシュタグが付いた投稿は多くありませんでした。 https://blog.gelehrte.com/entry/discord%E3%81%A8IFTTT 初めから取得していない可能性を考えて、スプレッドシートの最終TweetIDを削除して、再度mainを実行してみたところ、 20:39:36 お知らせ 実行開始 20:39:37 エラー ReferenceError: 「putRetweet」が定義されていません。 main @ コード.gs:94 というエラーが出てしまいました。 私はどのように確認すべきだったのでしょうか? また、新たに出してしまったこちらのエラーの回避情報についても、ご教示いただけないでしょうか? 頼りにさせていただけて、大変感謝しております。
退会済みユーザー

退会済みユーザー

2021/11/21 17:33

エラーに関して、回答欄に追記しました。
cusmix

2021/11/25 15:15 編集

qnoirさん、 追記ありがとうございます。 先日、私が掲載したコードの一部が必要だったということなんですね。 該当部分に、コードを追加したところ、新たにエラーが出てしまったので、 ① 検索ワードをスプレッドシートから取得する ② 検索ワードをTwitterで検索する(たくさん取れてしまうので「直近10分間」の検索を10分毎に行う) ③ ツイートに いいね or RT をする ④ 他に検索ワードがあれば②に戻る の順番通りにコードを並べる必要があるのかと思い pickUpSearchWords findTweets putFavorite putRetweet main の順に並べたのですが、やはり同じエラーが出てしまいます。 お忙しい中、初心者の質問に、いつも丁寧にご対応いただき、本当に感謝しております!!! エラー箇所は3か所で、 putFavorite ---------------------------- 10:28:07 お知らせ 実行開始 10:28:07 エラー TypeError: undefined からプロパティ「id_str」を読み取れません。 putFavorite @ コード.gs:82 ---------------------------- putRetweet ---------------------------- 10:28:54 お知らせ 実行開始 10:28:55 エラー TypeError: undefined からプロパティ「id_str」を読み取れません。 putRetweet @ コード.gs:90 ---------------------------- main ---------------------------- 10:29:14 お知らせ 実行開始 10:29:15 エラー https://api.twitter.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: {"errors":[{"code":327,"message":"You have already retweeted this Tweet."}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください) (匿名) @ Service.gs:457 (匿名) @ Service.gs:305 putRetweet @ コード.gs:90 main @ コード.gs:130 ---------------------------- 下記が現在のコードです ---------------------------- //認証用インスタンスの生成 var twitter = TwitterWebService.getInstance( '        ',//API Key '        '//API secret key ); // 認証 function authorize() { twitter.authorize(); } // 認証解除 function reset() { twitter.reset(); } // 認証後のコールバック function authCallback(request) { return twitter.authCallback(request); } // セルを取得 var sheetData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1"); // 「シート1」はシート名 /** いいね or RT 機能 ① 検索ワードをスプレッドシートから取得する ② 検索ワードをTwitterで検索する(たくさん取れてしまうので「直近10分間」の検索を10分毎に行う) ③ ツイートに いいね or RT をする ④ 他に検索ワードがあれば②に戻る */ // 検索ワードをスプレッドシートから取得する function pickUpSearchWords () { var titleRow = 1; // 『検索ワード』とか書いている部分の行数 var startRow = 1 + titleRow; // 1行目は『検索ワード』とか書いているので2行目から var startCol = 1; var endRow = sheetData.getLastRow() - titleRow; // 最後の行まで(2行目から始まっているので-1している) // !!!!!! 変更 !!!!!!! var endCol = 4; // 『実行回数』の列までなので4列目まで // 一括で取得する var cells = sheetData.getRange(startRow, startCol, endRow, endCol).getValues(); // cellsの中身は // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] ,....,] // という形式になる return cells; } // ツイートを検索する // 【参考】 https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets function findTweets (searchWord, lastTweetId) { var service = twitter.getService(); var query = { q: searchWord, // 検索ワード lang: 'ja', // 日本語検索 locale: 'ja', // 日本限定で検索 result_type: 'recent', // 直近のツイートを検索 since_id: lastTweetId // これ以前のツイートは見ない } // 検索の内容を queryStr にまとめていく var queryStr = ''; for (var key in query) { // URLに日本語や記号を付けると上手く検索できないことがあるので#も変換する encodeURIComponent をする queryStr += key + '=' + encodeURIComponent(query[key]) + '&' } // &が余計に付いているので削除しておく var queryStr = queryStr.slice(0, -1); var response = service.fetch('https://api.twitter.com/1.1/search/tweets.json?' + queryStr); var result = JSON.parse(response) return result.statuses } // いいね を付ける // 【参考】 https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-create function putFavorite(tweet) { var service = twitter.getService(); var options = { method: 'post' }; service.fetch('https://api.twitter.com/1.1/favorites/create.json?id=' + tweet.id_str, options); } // RT を付ける // 【参考】 https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id function putRetweet(tweet) { var service = twitter.getService(); var options = { method: 'post' }; service.fetch('https://api.twitter.com/1.1/statuses/retweet/' + tweet.id_str +'.json', options); } function main () { // ① 検索ワードをスプレッドシートから取得する var searchWords = pickUpSearchWords(); // searchWordsの中身は // [ [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'] , [ '投稿内容', 'いいね or RT', '最終TweetId', '実行回数'],....,] // という形式になっているので1つずつ見ていく for (var i = 0, il = searchWords.length; i < il; i++ ) { var searchWord = searchWords[i][0]; var type = searchWords[i][1]; var lastTweetId = searchWords[i][2]; // !!!!!! 追加 !!!!!!! var limit = searchWords[i][3]; // ② Twitterで検索する var tweetList = findTweets(searchWord, lastTweetId); var count = 0 // ③ 複数件ツイートを取得されるので for を使って1つずつツイートを取り出し いいね or RT をする for (var j = 0, jl = tweetList.length; j < jl; j++ ) { var tweet = tweetList[j]; if (tweet.id_str > lastTweetId) { lastTweetId = tweet.id_str; } // !!!!!! 追加 !!!!!!! if (count == limit) { // lastTweetIdを出来るだけ新しくしたい場合は continue; // 次回以降の実行で続きのツイートを使いたい場合は break; break; } count++; if (type == 'いいね') { putFavorite (tweet); } else if (type == 'RT') { putRetweet (tweet); } } // 最新のツイートIDを保存して重複処理をしないようにする var titleRow = 1; // 『検索ワード』とか書いている部分の行数 var lastTweetIdCol = 3; // 『最終TweetId』の列までなので3列目まで var updateCell = sheetData.getRange(i + 1 + titleRow, lastTweetIdCol, 1, 1); // i = 0 の時1行目なので+1してる updateCell.setValue(lastTweetId); } } ----------------------------
退会済みユーザー

退会済みユーザー

2021/11/22 03:40 編集

すみませんが、確認と回答は夜以降になります 取り急ぎ、上のコメント内のAPI KEY, API SECRETは表に出してはいけない情報と思いますので、本当のKEYであるならば、早急に削除か空白に編集して頂くのがよろしいかと思います。(念の為運営には連絡しました) よろしくお願いいたします
退会済みユーザー

退会済みユーザー

2021/11/22 14:38 編集

回答欄に追記(「追記2」参照)、及び全体コードを一部修正しました。
cusmix

2021/11/25 15:27

qnoirさん、 本人も確認できない、非常事態(API kEY,API SECRET)について、運営様側にもご連絡いただき、大変ありがとうございました。 お礼をいくら言っても、言い尽くせないです。 何か、お礼のお品物をお贈りさせていただきたいのですが、それもかなう状況ではないですし...。 誠に、誠にありがとうございました。 以下のコメント、大変勉強になりました。ありがとうございます。 以前に頂いたコメントで、珍しいワードを検索ワードにしていると、リツイートが確認できないのでは?と仰っていただいていた通り、現在、動作確認ができました。 >このプログラムは(一度authorize()関数を実行してTwitter認証が完了し>ていれば)基本的に、main()を実行するだけでよいです。(main()以外>を実行しても正常に動作しません) >実際のところ、順番通りに並べる必要はありません。 >呼び出し元より後ろにある関数であっても、自動的に探して認識してくれ>ます。 >今回のエラーの原因は、上述のようにリツイート済みのツイートに重ねて>リツイートしようとしたためです。 >さらに、putRetweet関数や、putFavorite関数を直接実行されようとした>のではないでしょうか。 >putRetweet関数や、putFavorite関数は、main()関数から呼び出される>専用の関数です。 >元のコードで、putRetweet関数や、putFavorite関数を直接実行すると、>引数tweetが空っぽ(undefined)のため、 >「undefined からプロパティ「id_str」を読み取れません。」というエラ>ーが発生します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問