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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Google Apps Script

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

Twitter

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

2回答

2364閲覧

TwitterAPIとGASで画像つきツイートをしたい

Gfon

総合スコア15

Google Apps Script

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

Twitter

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2017/10/29 13:08

編集2017/10/29 13:32

###前提・実現したいこと
下記のサイトを参考にgoogle App Script(GAS)を使用してBotを制作しています.サイトの丁寧な説明もあり,テキストのツイートまではできたのですが,画像つきのツイートの方法がわからずに困っております.
画像はGoogleDriveもしくは他のオンライン上にあるものを使用したいと考えております.

サイト
http://yukiblg777.blog.fc2.com/blog-entry-47.html
https://kijtra.com/article/twitter-api-for-google-apps-script-without-oauthconfig/

お力添え,よろしくお願い致します.

###該当のソースコード
メインのスクリプト

Google

1// 最初にこの関数を実行し、ログに出力されたURLにアクセスしてOAuth認証する 2function twitterAuthorizeUrl() { 3 Twitter.oauth.showUrl(); 4} 5 6// OAuth認証成功後のコールバック関数 7function twitterAuthorizeCallback(request) { 8 return Twitter.oauth.callback(request); 9} 10 11// OAuth認証のキャッシュをを削除する場合はこれを実行(実行後は再度認証が必要) 12function twitterAuthorizeClear() { 13 Twitter.oauth.clear(); 14} 15 16 17var Twitter = { 18 projectKey: "このprojectのProjectKey", 19 20 consumerKey: "TwitterのconsumerKey", 21 consumerSecret: "TwitterのconsumerSecret", 22 23 apiUrl: "https://api.twitter.com/1.1/", 24 25 oauth: { 26 name: "twitter", 27 28 service: function(screen_name) { 29 // 参照元:https://github.com/googlesamples/apps-script-oauth2 30 31 return OAuth1.createService(this.name) 32 // Set the endpoint URLs. 33 .setAccessTokenUrl('https://api.twitter.com/oauth/access_token') 34 .setRequestTokenUrl('https://api.twitter.com/oauth/request_token') 35 .setAuthorizationUrl('https://api.twitter.com/oauth/authorize') 36 37 // Set the consumer key and secret. 38 .setConsumerKey(this.parent.consumerKey) 39 .setConsumerSecret(this.parent.consumerSecret) 40 41 // Set the project key of the script using this library. 42 .setProjectKey(this.parent.projectKey) 43 44 45 // Set the name of the callback function in the script referenced 46 // above that should be invoked to complete the OAuth flow. 47 .setCallbackFunction('twitterAuthorizeCallback') 48 49 // Set the property store where authorized tokens should be persisted. 50 .setPropertyStore(PropertiesService.getUserProperties()); 51 }, 52 53 showUrl: function() { 54 var service = this.service(); 55 if (!service.hasAccess()) { 56 Logger.log(service.authorize()); 57 } else { 58 Logger.log("認証済みです"); 59 } 60 }, 61 62 callback: function (request) { 63 var service = this.service(); 64 var isAuthorized = service.handleCallback(request); 65 if (isAuthorized) { 66 return HtmlService.createHtmlOutput("認証に成功しました.このタブは閉じても問題ありません"); 67 } else { 68 return HtmlService.createHtmlOutput("認証に失敗しました"); 69 } 70 }, 71 72 clear: function(){ 73 OAuth1.createService(this.name) 74 .setPropertyStore(PropertiesService.getUserProperties()) 75 .reset(); 76 } 77 }, 78 79 api: function(path, data) { 80 var that = this, service = this.oauth.service(); 81 if (!service.hasAccess()) { 82 Logger.log("先にOAuth認証してください"); 83 return false; 84 } 85 86 path = path.toLowerCase().replace(/^//, '').replace(/.json$/, ''); 87 88 var method = ( 89 /^statuses/(destroy/\d+|update|retweet/\d+)/.test(path) 90 || /^media/upload/.test(path) 91 || /^direct_messages/(destroy|new)/.test(path) 92 || /^friendships/(create|destroy|update)/.test(path) 93 || /^account/(settings|update|remove)/.test(path) 94 || /^blocks/(create|destroy)/.test(path) 95 || /^mutes/users/(create|destroy)/.test(path) 96 || /^favorites/(destroy|create)/.test(path) 97 || /^lists/[^/]+/(destroy|create|update)/.test(path) 98 || /^saved_searches/(create|destroy)/.test(path) 99 || /^geo/place/.test(path) 100 || /^users/report_spam/.test(path) 101 ) ? "post" : "get"; 102 103 var url = this.apiUrl + path + ".json"; 104 var options = { 105 method: method, 106 muteHttpExceptions: true 107 }; 108 109 if ("get" === method) { 110 if (!this.isEmpty(data)) { 111 url += '?' + Object.keys(data).map(function(key) { 112 return that.encodeRfc3986(key) + '=' + that.encodeRfc3986(data[key]); 113 }).join('&'); 114 } 115 } else if ("post" == method) { 116 if (!this.isEmpty(data)) { 117 options.payload = Object.keys(data).map(function(key) { 118 return that.encodeRfc3986(key) + '=' + that.encodeRfc3986(data[key]); 119 }).join('&'); 120 121 if (data.media) { 122 options.contentType = "multipart/form-data;charset=UTF-8"; 123 } 124 } 125 } 126 127 try { 128 var result = service.fetch(url, options); 129 var json = JSON.parse(result.getContentText()); 130 if (json) { 131 if (json.error) { 132 throw new Error(json.error + " (" + json.request + ")"); 133 } else if (json.errors) { 134 var err = []; 135 for (var i = 0, l = json.errors.length; i < l; i++) { 136 var error = json.errors[i]; 137 err.push(error.message + " (code: " + error.code + ")"); 138 } 139 throw new Error(err.join("\n")); 140 } else { 141 return json; 142 } 143 } 144 } catch(e) { 145 this.error(e); 146 } 147 148 return false; 149 }, 150 151 error: function(error) { 152 var message = null; 153 if ('object' === typeof error && error.message) { 154 message = error.message + " ('" + error.fileName + '.gs:' + error.lineNumber +")"; 155 } else { 156 message = error; 157 } 158 159 Logger.log(message); 160 }, 161 162 isEmpty: function(obj) { 163 if (obj == null) return true; 164 if (obj.length > 0) return false; 165 if (obj.length === 0) return true; 166 for (var key in obj) { 167 if (hasOwnProperty.call(obj, key)) return false; 168 } 169 return true; 170 }, 171 172 encodeRfc3986: function(str) { 173 return encodeURIComponent(str).replace(/[!'()]/g, function(char) { 174 return escape(char); 175 }).replace(/*/g, "%2A"); 176 }, 177 178 //Twitterに画像を投稿します。 179//引数 text・・・画像と一緒に投稿するテキスト 180//    picture・・・投稿する画像 181 iamge_upload: function(text,picture) { 182 var that = this, service = this.oauth.service(); 183 if (!service.hasAccess()) { 184 Logger.log("先にOAuth認証してください"); 185 return false; 186 } 187 188 189 var boundary = "cuthere"; 190 var requestBody = Utilities.newBlob( 191 "--"+boundary+"\r\n" 192 + "Content-Disposition: form-data; name=\"status\"\r\n\r\n" 193 + text+"\r\n"+"--"+boundary+"\r\n" 194 + "Content-Disposition: form-data; name=\"media[]\"; filename=\""+picture.getName()+"\"\r\n" 195 + "Content-Type: " + picture.getContentType()+"\r\n\r\n").getBytes(); 196 197 requestBody = requestBody.concat(picture.getBytes()); 198 requestBody = requestBody.concat(Utilities.newBlob("\r\n--"+boundary+"--\r\n").getBytes()); 199 200 var options = { 201 method: "post", 202 contentType: "multipart/form-data; boundary="+boundary, 203 payload: requestBody, 204 muteHttpExceptions: true 205 }; 206 207 var url = "https://api.twitter.com/1.1/statuses/update_with_media.json"; 208 209 try { 210 var result = service.fetch(url, options); 211 var json = JSON.parse(result.getContentText()); 212 } catch(e) { 213 214 } 215 216 return json; 217 }, 218 //画像ツイートここまで 219 220 init: function() { 221 this.oauth.parent = this; 222 return this; 223 } 224}.init(); 225 226 227/******************************************************************** 228以下はサポート関数 229*/ 230 231// ツイートする 232Twitter.tweet = function(data, reply) { 233 var path = "statuses/update"; 234 if ("string" === typeof data) { 235 data = {status: data}; 236 } else if(data.media) { 237 path = "statuses/update_with_media "; 238 } 239 240 if (reply) { 241 data.in_reply_to_status_id = reply; 242 } 243 244 return this.api(path, data); 245}; 246

ツイート用のスクリプト

Google

1function Tweet(){ 2 Twitter.tweet("Test Tweet"); 3}

###試したこと
iamge_uploadに引数として画像のURLやbase64に変換した画像のデータを与えてみましたが,何もツイートされませんでした.

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

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

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

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

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

guest

回答2

0

自己解決

umyuさまのご指摘の通り,update_with_mediaを使用しておりますので,今後使えなくなる可能性もございますが,ここに解決方法を記しておきます.

###解決方法

まず,メインのスクリプトにimage投稿用の関数を追加します.

Google

1Twitter.image = function(text,picture){ 2 this.iamge_upload(text,picture); 3};

続いてこの関数に引数を与えますが,

  • インターネット上の画像を利用する場合
  • GoogleDrive内の画像を利用する場合

の二通りがあります.

Google

1//インターネット上の画像を利用する場合 2 3//画像の取得 4var GetImage = UrlFetchApp.fetch('画像のURL'); 5var Image = GetImage.getBlob(); 6 7function Tweet(){ 8 Twitter.image("ImageTweetTest",Image); 9} 10

Google

1//GoogleDrive上の画像を利用する場合 2//GoogleDrive内に画像ファイルを置いておく.ファイル名に拡張子がある場合は拡張子もお忘れなく 3 4//GogleDrive上の画像取得 5var file_name = 'ファイル名'; 6var file_temp = DriveApp.getFilesByName(file_name).next(); 7var Imagedata = file_temp.getBlob(); 8 9function ImageTweet(){ 10 Twitter.image("ImageTweetTest2",Imagedata); 11} 12

GoogleDriveを用いる方についてはファイルがない場合やファイル名が重複している場合などの処理がないなど好ましくない点も多いですし,よりスマートな方法もありますが,最低限このスクリプトで動作いたしました.

投稿2017/11/01 00:46

Gfon

総合スコア15

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

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

0

回答ではありませんが、pythonで画像付きのTwitterボットを作った事があるため、参考情報として投稿します。

POST先のURLが

var url = "https://api.twitter.com/1.1/statuses/update_with_media.json";

となってますが、update_with_mediaは**deprecated(廃止)**されました。

画像アップロード手順としては公式ドキュメントが参考になります。
1,post-media-uploadで画像をアップロードし、返り値のmedia_idを取得
url => https://upload.twitter.com/1.1/media/upload.json

2,取得したmedia_idを元にpost-statuses-updateを行う。
url => https://api.twitter.com/1.1/statuses/update.json

◆注意事項
1,画像アップロードの制限があります。
2,post-statuses-updateは普通のツィートと同じ扱いです。連続して同一メッセージをツィートできません。末尾に半角スペースを付与して回避してください。

投稿2017/10/31 22:51

編集2017/10/31 23:16
umyu

総合スコア5846

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

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

Gfon

2017/10/31 23:51

ご回答ありがとうございます. 実はつい先程自己解決いたしました.(この後解決方法を投稿予定です)公式ドキュメントにおいて,update_with_mediaはdeprecatedであることは確認していたのですが,現段階ではまだ使用できるようです.ですが,廃止も近いと思われますので,近々media/upload等を使用した方法に書き換えたいと思います.また,注意事項についても大変参考になりました.この度はご回答ありがとうございました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問