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

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

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

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

DNS

DNSとは、Domain Name Systemのことで、インターネットなどのTCP/IPネットワーク上でドメイン名やホスト名と、IPアドレスとの対応づけを管理するシステムです。DNSのデータベースは、IPアドレスの4つの数字を通知するDNSサーバーで構築されており、IPアドレスをドメイン名から引き出す機能やドメイン名に関するメールサーバ情報を取り扱っています。

Google Apps Script

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

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

Twitter

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

Q&A

解決済

2回答

2940閲覧

【GAS】TwitterAPIを使用して、Google Apps Scriptから画像ファイルの投稿時のエラー対応方法(Exception: DNS エラー: http://ファイル名.png(行))

unity_level1

総合スコア8

Google スプレッドシート

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

DNS

DNSとは、Domain Name Systemのことで、インターネットなどのTCP/IPネットワーク上でドメイン名やホスト名と、IPアドレスとの対応づけを管理するシステムです。DNSのデータベースは、IPアドレスの4つの数字を通知するDNSサーバーで構築されており、IPアドレスをドメイン名から引き出す機能やドメイン名に関するメールサーバ情報を取り扱っています。

Google Apps Script

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

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

Twitter

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

0グッド

1クリップ

投稿2020/11/01 16:34

編集2020/11/17 08:43

Google Apps ScriptからTwitterAPIを使用して、BOTを作成しようとしているのですが、画像ファイルを投稿する部分でうまくいかない状況です。
下記エラーの対応方法と、画像ファイル投稿方法についてご教示いただけますと幸いです。

実行環境


■Google Apps Script
■Twitter API
■Googleスプレッドシート
■Googleドライブ

実施内容


Googleスプレッドシート内に記載した画像ファイルのIDを取得して、Twitter上に自動ツイートするスクリプトを記載しております。
対象の画像ファイルはGoogleドライブにアップロード済みです。

TwitterAPI認証用スクリプト // 認証用URL取得 function getOAuthURL() { Logger.log(getService().authorize()); } // サービス取得 function getService() { return OAuth1.createService('Twitter') .setAccessTokenUrl('https://api.twitter.com/oauth/access_token') .setRequestTokenUrl('https://api.twitter.com/oauth/request_token') .setAuthorizationUrl('https://api.twitter.com/oauth/authorize') // 設定した認証情報をセット .setConsumerKey(PropertiesService.getScriptProperties().getProperty("CONSUMER_API_KEY")) .setConsumerSecret(PropertiesService.getScriptProperties().getProperty("CONSUMER_API_SECRET")) .setCallbackFunction('authCallback') // 認証情報をプロパティストアにセット(これにより認証解除するまで再認証が不要になる) .setPropertyStore(PropertiesService.getUserProperties()); } // 認証成功時に呼び出される処理を定義 function authCallback(request) { var service = getService(); var authorized = service.handleCallback(request); if (authorized) { return HtmlService.createHtmlOutput('success!!'); } else { return HtmlService.createHtmlOutput('failed'); } }

testBot2の関数を実行しようとするとエラーが発生します

スプレッドシート画像ファイル、ツイート内容取得用 function testBot2(){ const activeSheet = SpreadsheetApp.getActiveSheet(); const lastRow = activeSheet.getLastRow(); for(let i = 2; i <= lastRow; i++){ //getValue()で対象のセルの値をチェック //セル内が空の場合はfalse、文字列が1以上の場合はtrueとなる var sell = activeSheet.getRange(i,5); if(!sell.getValue()){ sell.setValue(true); //本文と画像の変数 var tweetBot = activeSheet.getRange(i,4).getValue();    //下記、エラー原因行1    //ファイルのIDはスプレッドシートのセル(i,3)に記載しており、その値を取得して、変数に格納しようとしております var tweetCapture = DriveApp.getFileById(activeSheet.getRange(i,3).getValue()); //画像の取得    //エラー原因行2    //下記UrlFetchApp.fetchの引数にtweetCapture を指定。ここでエラーが発生 var imgUrl = UrlFetchApp.fetch(tweetCapture).getBlob(); var imgCapture = Utilities.base64Encode(imgUrl.getBytes()); //ツイート用の関数にメッセージと画像ファイルが格納された変数の引数を渡している toTweet(tweetBot,imgCapture); if(i >= lastRow){ activeSheet.getRange(2,5,lastRow - 1).clearContent(); } break; } } }
ツイート用のAPIを起動する関数 function toTweet(tweetBot,imgCapture) { var endPointStatus = 'https://api.twitter.com/1.1/statuses/update.json'; var endPointMedia = 'https://upload.twitter.com/1.1/media/upload.json'; var twitterService = getService(); if (twitterService.hasAccess()) { // 投稿 var twMethod = { method:"POST" }; twMethod.payload = { status: tweetBot }; //TwitterAPIはJSONでファイルを取得している var img_option = { 'method' : "POST", 'payload': { 'media_data': imgCapture } }; //JSONをパースしてGASで使用する準備をする var image_upload = JSON.parse(twitterService.fetch(endPointMedia, img_option)); var sendoption = { 'status' : tweetBot, 'media_ids': image_upload[media_id_string] }; //twitterService.fetch(endPointStatus, {method: 'post', payload: sendoption}); Twitter.api('statuses/update',sendoption); Logger.log(response.getContentText()); } else { Logger.log(twitterService.getLastError()); } }

エラー内容


Exception: DNS エラー: http://ファイル名.png(行 99、ファイル「コード」)

99行目のコード

//testBoxt2関数内の var tweetCapture = DriveApp.getFileById(activeSheet.getRange(i,3).getValue()); var imgUrl = UrlFetchApp.fetch(tweetCapture).getBlob();

対象ファイルのIDからURLを確認している処理と認識しており、そのURLが誤ったものになっているため、
エラーが発生していると考えております。

https~を取得すべき部分が、httpで取得しようとしているためエラーが出ている可能性を考えてます。

お手数ですが、上記エラーの対処方法、また、可能であれば、上記TwitterAPIのスクリプトをあまり理解できていないため、
画像ファイルの投稿スクリプトも合わせてご教示いただけますと幸いです。

どうぞよろしくお願いします

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

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

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

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

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

guest

回答2

0

ベストアンサー

[1]
まず
Exception: DNS エラー: http://ファイル名.png(行 99、ファイル「コード」)

というエラーが出ている原因ですが,

testBot2関数内の

var tweetCapture = DriveApp.getFileById(activeSheet.getRange(i,3).getValue()); var imgUrl = UrlFetchApp.fetch(tweetCapture).getBlob();

の2行について・・・

DriveApp.getFileById(id) 関数は、引数に指定したファイルIDのファイルオブジェクトを取得するものである一方、
UrlFetchApp.fetch(url) 関数は、引数に指定したURLのリソースをダウンロードしてくる関数です。
(参照:Googleの公式マニュアル1

したがって上の2行のコードを合わせると、ファイルIDから取得したファイルオブジェクトをURLに指定してダウンロードするという処理になってしまっているため、エラーが発生します。

UrlFetchApp.fetch(url)関数の引数 url には、画像ダウンロード用のURLを指定してあげる必要があります。

質問者様のpython版の別質問に対して回答させていただきました内容を参照されればお分かりになるかと思いますが、
Googleドライブのファイルダウンロード用のURLは

https://drive.google.com/uc?export=view&id=**ファイルID**」

という形式になっておりますので、この形式のURLを渡してやればよいです。

[2]
全体として整理し自分の手元で動いた全文コードを下記に掲示いたします。(紙面がないので認証周りの手順は省略しています)

個人的に冗長なくらいわかりやすくコメントを付けたつもりです。(実際は極力コメントはつけずコードだけでわかるように書く方がいいという風潮もありますが、あくまで学習のためです)

私自身、GASはまだ人生で4-5時間くらいしか触っていないため、詳しい方からすれば拙いコードかもしれませんが、質問者様の学習に役立てば幸いです。

このスクリプト、というかツイッターの仕様上の理解のポイントとして、「画像つきツイート」とは
・画像のアップロード

・アップロードした画像を付加したツイートの投稿
という2つの異なる機能を合わせたものである、ということを念頭におさえると、少し見やすくなるかもしれません。

function getOAuthURL() { Logger.log(getService().authorize()); } // サービス取得 function getService() { return OAuth1.createService('Twitter') .setAccessTokenUrl('https://api.twitter.com/oauth/access_token') .setRequestTokenUrl('https://api.twitter.com/oauth/request_token') .setAuthorizationUrl('https://api.twitter.com/oauth/authorize') // 設定した認証情報をセット .setConsumerKey(PropertiesService.getScriptProperties().getProperty("CONSUMER_API_KEY")) .setConsumerSecret(PropertiesService.getScriptProperties().getProperty("CONSUMER_API_SECRET")) .setCallbackFunction('authCallback') // 認証情報をプロパティストアにセット(これにより認証解除するまで再認証が不要になる) .setPropertyStore(PropertiesService.getUserProperties()); } // 認証成功時に呼び出される処理を定義 function authCallback(request) { var service = getService(); var authorized = service.handleCallback(request); if (authorized) { return HtmlService.createHtmlOutput('success!!'); } else { return HtmlService.createHtmlOutput('failed'); } } function testBot2(){ // アクティブシートの取得 const activeSheet = SpreadsheetApp.getActiveSheet(); // 最下行の取得 const lastRow = activeSheet.getLastRow(); for(let i = 2; i <= lastRow; i++){ // i行目5列目のセルの内容を取得。 var sell = activeSheet.getRange(i,5); // i行目5列目のセルの内容が空ならば、そのセルにTrueを書き込む。 if(!sell.getValue()){ sell.setValue(true); // メッセージ本文をセルi行目4列目から取得。 var tweetBot = activeSheet.getRange(i,4).getValue(); Logger.log(tweetBot);     // i行目3列目のセルから、画像ファイルのIDを取得する。 var fileId = activeSheet.getRange(i,3).getValue(); // 画像ファイルIDから、画像取得用URLを組み立てる。 var imgUrl = "https://drive.google.com/uc?export=view&id=" + fileId; // 画像取得用URL経由で画像データを取得し、Base64にエンコードする。 var imgBlob = UrlFetchApp.fetch(imgUrl).getBlob(); var imgCapture = Utilities.base64Encode(imgBlob.getBytes()); Logger.log(imgCapture); // メッセージ本文と画像データをツイート用関数に渡す toTweet(tweetBot, imgCapture); if(i >= lastRow){ activeSheet.getRange(2,5,lastRow - 1).clearContent(); } break; } } } /*************************************************** 画像付きメッセージをツイートする関数 引数: tweetBot : メッセージ本文 imgCapture : Base64エンコードされた画像データ ****************************************************/ function toTweet(tweetBot,imgCapture) { // ツイートを投稿するためのエンドポイント。 var endPointStatus = 'https://api.twitter.com/1.1/statuses/update.json'; // 画像をアップロードするためのエンドポイント。 var endPointMedia = 'https://upload.twitter.com/1.1/media/upload.json'; // twitterを操作するためのサービスオブジェクトの取得。 var twitterService = getService(); // 認可が得られている状態ならば、画像付きツイートを投稿する処理に入る。 if (twitterService.hasAccess()) { // 画像アップロードのためのoptionを組み立てる。 var img_option = { 'method' : "POST", 'payload': { 'media_data': imgCapture } }; // 画像をアップロードし、返ってくるJSONをパースする(JSON内のmedia_idを取得するため) var image_upload = JSON.parse(twitterService.fetch(endPointMedia, img_option)); Logger.log(image_upload); // 画像付きツイートを投稿するためのオプションを組み立てる。 var sendoption = { 'status' : tweetBot, 'media_ids': image_upload['media_id_string'] }; // 画像付きツイートを投稿する。レスポンスがresponse変数に格納される。 response = twitterService.fetch(endPointStatus, {method: 'post', payload: sendoption}); // レスポンスの内容をログに記録。 Logger.log(response.getContentText()); } else { // 認可が得られていないため、直近のエラーログを記録する。 Logger.log(twitterService.getLastError()); } }

その他:
・tweetBot, imgCapture という変数名はわかりにくいかもしれません。
たとえばそれぞれ tweet_text, img_64 等がわかりやすいかも。

参考にしたサイト:
https://developer.twitter.com/ja/docs/
https://lookbackmargin.blog/2019/08/11/img-tweet-via-gas/
初期設定
https://tech-cci.io/archives/4228

投稿2020/11/20 14:22

編集2020/11/20 15:12
sfdust

総合スコア1135

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

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

unity_level1

2020/11/21 18:45

sfdust様 詳細なご回答いただきありがとうございます。 こちらについても、ご教示いただきました内容で実行したところ上手く画像をツイートすることができました。 Pythonの質問と同様に、解決していただくだけでなく、後学になるように、詳しい説明などを含めていただき本当にありがたいです。 プログラミング自体ほぼ未経験だったのですが、BOTを作る必要が直近で出てきたため本当に助かりました。 引き続き、動画を投稿できるようにしたいため、そちらはご教示いただきました内容をもとにまずは自分でプログラムを書いてみようと思います。 分からなかったときは、またTeraTailで質問をさせていただきますため、その際にお時間がございましたらご教示いただけますと幸いです。 Pythonの質問は、別途試させていただき結果をご報告させていただきます。 本件、ご回答いただき本当にありがとうございました。
guest

0

var imgUrl = UrlFetchApp.fetch(tweetCapture).getBlob();
の、imgUrlが正常かLOGを出力してみてください。

投稿2020/11/19 05:31

herobo

総合スコア153

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

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

unity_level1

2020/11/21 18:50

herobo様 本件、お返事が遅くなってしまい申し訳ございませんでした。 本問題につきまして、無事解決することができました。 当方、プログラミングの経験が浅いため、また質問をさせていただくことがあると思います。 その際には、またご回答いただけますと幸いです。 本件ご回答いただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問