Google Apps Scriptを触ってみるの巻 - その2
読んでもらうために書いたものではないので、読みにくいと思います。
前回のおさらい。
function myFunction() { var response = UrlFetchApp.fetch("http://lisiograph.webcrow.jp/others/json/sampledata.json"); var result = JSON.parse(response.getContentText()); var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getActiveSheet(); var range = sheet.getRange(1, 1); var result = result.daily_views; // スプレッドシート(データ)への書き込み for(var i=1; i<=Object.keys(result).length; i++) { var day_number = ("0" + i).slice(-2); var result_views = result['2013-02-' + day_number]; // 日付 range.offset(i, 0).setValue("2013-02-" + day_number); //Logger.log("2013-02-" + day_number); // データ range.offset(i, 1).setValue(result_views); //Logger.log(result_views); } }
こんなん作りました。
取得するURLを考える
取得するべきデータはこんな感じになっています。
http://stats.grok.se/json/ja/201308/%E5%B7%BD%E6%82%A0%E8%A1%A3%E5%AD%90
"http://stats.grok.se/json/ja/" + 年4桁 + 月2桁 + "/" + "氏名の漢字のUTF-8エンコード"
Class Utilities - Google Apps Script — Google Developers
年+月の部分はこう。後々の事を考えて年と月は分けておく。
function myFunction2() { var formattedDate_year = Utilities.formatDate(new Date(), "JST", "yyyy"); var formattedDate_month = Utilities.formatDate(new Date(), "JST", "MM"); Logger.log(formattedDate_year + formattedDate_month); }
おk。
名前はセルに入れたものを取得したいなー。
G1ぐらいに入れておく。
function myFunction2() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getActiveSheet(); var name = sheet.getRange(1, 7).getValue(); Logger.log(name); }
おk。
全部放り込む。
function myFunction2() { var formattedDate_year = Utilities.formatDate(new Date(), "JST", "yyyy"); var formattedDate_month = Utilities.formatDate(new Date(), "JST", "MM"); var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getActiveSheet(); var name = sheet.getRange(1, 7).getValue(); var responseURL = "http://stats.grok.se/json/ja/" + formattedDate_year + formattedDate_month + "/" + name; var response = UrlFetchApp.fetch(responseURL); }
大丈夫です。
前回作ったものと統合します。
修正を入れる
・データの書き込み位置は最終行にする
[GAS][スプレッドシート]シートの最終行を取得するには : 逆引きGoogle Apps Script
var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1);
・スプレッドシート等の取得方法を変えておく
Google Apps Scriptでスプレッドシートを操作してみる - ike-daiの日記
こうやってしておく方が後で便利だと思う。
var SPREADSHEET_ID = 'スプレッドシートID'; var SHEET_NAME = 'テンプレート'; ss = SpreadsheetApp.openById(SPREADSHEET_ID); sheet = ss.getSheetByName(SHEET_NAME);
セルの選択&値の取得: Googleスプレッドシート メモ
こういうのもある。
ss = SpreadsheetApp.openById(SPREADSHEET_ID); sheet = ss.getSheets()[0];
シートの1番目が[0]になる。こっちの方が簡単かも。
ここまでのまとめ。
function myFunction() { var formattedDate_year = Utilities.formatDate(new Date(), "JST", "yyyy"); var formattedDate_month = Utilities.formatDate(new Date(), "JST", "MM"); var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; var name = sheet.getRange(1, 7).getValue(); var responseURL = "http://stats.grok.se/json/ja/" + formattedDate_year + formattedDate_month + "/" + name; var response = UrlFetchApp.fetch(responseURL); var result = JSON.parse(response.getContentText()); var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1); var result = result.daily_views; // スプレッドシート(データ)への書き込み for(var i=1; i<=Object.keys(result).length; i++) { var day_number = ("0" + i).slice(-2); var result_views = result[formattedDate_year + '-' + formattedDate_month + '-' + day_number]; // 日付 range.offset(i, 0).setValue(formattedDate_year + '-' + formattedDate_month + '-' + day_number); // データ range.offset(i, 1).setValue(result_views); } }
取得するデータを制限する
今for文の中はi=1から日数分(n月20日なら20個)のデータを取得するようにしていますが、これを1ヶ月毎日繰り返すと1+2+3+4+5+...+31で31のデータを取得するために496のデータを持ってしまうことになり、非常に効率が悪いです。(スプレッドシートのjsonがデカくなると読み込グラフ表示の際の読み込みスピードが落ちることが想定されるため)
例えば、1個だけ書き込む場合の処理はこう
for(var i=Object.keys(result).length-1; i<=Object.keys(result).length; i++)
シンプル。
ただし、このapiは同じ時間に同じだけデータが更新されるとは限らない(ブレが大きくて扱いにくいんです。)ので、1日前のデータを取得、なければその1日前、それでもなければその前・・・という風にしたいと思います。
ということで、iのスタートを1日前にしてみます。
グラフを描く時に使ったものから流用しつつ。
function myFunction2() { var today = new Date(); var i_date = new Date( today.getTime() - 24*60*60*1000 ); for(var i=i_date.getDate(); i<=Object.keys(result).length; i++) 以下略 }
動かない。
多分iが大きかったのでループが始まらなかったのだと思う。
iの作り方を変える。
lastrowにある日付が入力されたセルをgetValueして日付に変換して+ 24*60*60*1000してgetDateすればいいはず。
1つずつやろう。
日付の変換はこれを参照。
parseメソッド - Dateクラス - JavaScript入門
function myFunction2() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1); //定義終了 var yesterday = range.getValue(); //rangeの値(日付の文字列)を取得 var yesterday = Date.parse(yesterday); //日付形式に変換(ミリ秒) Logger.log(yesterday); var target = yesterday + 24*60*60*1000; //24*60*60*1000で1日ずらす var target = new Date(target); //ミリ秒を日付形式に変換 var i_date = target.getDate(); //取得すべき日付 }
問題なし。
多くは1回の取得で終わるのでfor文はいらなさそうだが、取得のタイミング次第では2つ以上のデータを取得しなければならないときもあるので、一応残しておく。面倒くさいだけだという話もある。
取得すべきはこの日付のデータなのだから、現在日時の取得には意味がなくなる。
var formattedDate_year = Utilities.formatDate(new Date(), "JST", "yyyy"); var formattedDate_month = Utilities.formatDate(new Date(), "JST", "MM"); var responseURL = "http://stats.grok.se/json/ja/" + formattedDate_year + formattedDate_month + "/" + name;
この部分は
var target_year = target.getYear(); var target_month = target.getMonth(); var responseURL = "http://stats.grok.se/json/ja/" + target_year + target_month + "/" + name;
になる。
for文の中も変わる。
iが1じゃないところから始まると、offsetがずれるので修正
例えばiが15の時はlastrowの15行下の位置から書き込み始めることになる。
1個下にしたいので、iが15の時は、i-14のoffsetにする。
つまり、iより1小さい定数を先に定義しておけばいい。
var mod_i = i_date -1; //書き込み位置を設定 var x = i-mod_i;
んで、試したらgetMonthで月が1ずれた。あとこれ2桁に揃えなきゃいけない。
var target_month = target.getMonth() +1; var target_month = ("0" + target_month).slice(-2);
今日のまとめ
以上を踏まえて、
function myFunction() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1); var yesterday = range.getValue(); //rangeの値(日付の文字列)を取得 var yesterday = Date.parse(yesterday); //日付形式に変換(ミリ秒) var target = yesterday + 24*60*60*1000; //24*60*60*1000で1日ずらす var target = new Date(target); //ミリ秒を日付形式に変換 var i_date = target.getDate(); //取得すべき日付 var mod_i = i_date -1; //書き込み位置を設定 var target_year = target.getYear(); //取得すべき日付の年 var target_month = target.getMonth()+1; //取得すべき日付の月 var target_month = ("0" + target_month).slice(-2); //2桁揃え var name = sheet.getRange(1, 7).getValue(); var responseURL = "http://stats.grok.se/json/ja/" + target_year + target_month + "/" + name; var response = UrlFetchApp.fetch(responseURL); var result = JSON.parse(response.getContentText()); var result = result.daily_views; // スプレッドシート(データ)への書き込み for(var i=i_date; i<=Object.keys(result).length; i++) { var day_number = ("0" + i).slice(-2); var result_views = result[target_year + '-' + target_month + '-' + day_number]; var x = i-mod_i; // 日付 range.offset(x, 0).setValue(target_year + '-' + target_month + '-' + day_number); // データ range.offset(x, 1).setValue(result_views); } }
OK!!!!
変数の名前が綺麗じゃないなあと思います。直したい(願望)
移動平均の計算式を入力する
必要なのは5日、25日、75日の移動平均である。
75行目に入力してから最終行までコピペすればいけるはず。
function myFunction3() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1); //定義終了 sheet.getRange(75,3).setValue('=average(B71:B75)'); //移動平均5日の数式をセット }
普通にこうやって書けば数式として認識してくれた。(string扱いされるかと思った。)
あと2つも同様。
sheet.getRange(75,4).setValue('=average(B51:B75)'); sheet.getRange(75,5).setValue('=average(B1:B75)');
セルは範囲指定で書ける。
Google Apps Script Documentation - セル番地表記,範囲表記-1
sheet.getRange(75,3,1,3);
これで75行3列(つまりC75)から1行3列分の範囲(つまりC75:E75)。
コピペの方法はこれ。
[GAS][スプレッドシート]セルをコピーするには : 逆引きGoogle Apps Script
合わせ技で
function myFunction3() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1); //定義終了 sheet.getRange(75,3).setValue('=average(B71:B75)'); //移動平均5日の数式をセット sheet.getRange(75,4).setValue('=average(B51:B75)'); //25日 sheet.getRange(75,5).setValue('=average(B1:B75)'); //75日 var lastrow = sheet.getLastRow(); //データ書き込み後の最終行を取得 var rangeToCopy = sheet.getRange(75,3,1,3); //C75:E75のセル範囲 var targetToCopy = sheet.getRange(75,3,lastrow-74,3); //C75:E最終行までのセル範囲 rangeToCopy.copyTo(targetToCopy); }
動いた。
前週比を出しておく
外部参照するので固定セルに入力する。G2とH2に入力する。
どうせなら数式ではなく数値を入れてしまうほうが確実な気がする。
var today = sheet.getRange(lastrow,2).getValue(); //最新の値 var lastweek = sheet.getRange(lastrow-7,2).getValue(); //最新の7日前の値 var change1 = today - lastweek; //引き算 sheet.getRange(2,7).setValue(change1); //G2に書き込み var change2 = change1/lastweek; //前週比 sheet.getRange(2,8).setValue(change2); //H2に書き込み
動いた。
H2の書式設定はパーセント表示にしておく。
twproの取得
jsonなので似たようなもんだろう(フフン
APIはこんな感じになっている
ツイプロ (twpro) について
こういう感じのを使っている。
http://api.twpro.jp/1/search?q= + 名前のutf-8エンコード + &num=1
適当に放り込んでいく。
function myFunction4() { var name = sheet.getRange(1, 7).getValue(); //入力しておいた名前を取得 var responseURL_t = "http://api.twpro.jp/1/search?q=" + name + "&num=1"; //取得先のurlを設定(twpro) var response_t = UrlFetchApp.fetch(responseURL_t); //データを取得(twpro) var result_t = JSON.parse(response_t.getContentText()); //JSONをパース(twpro) var result_t = result_t.total; //パースしたもののうち、totalだけ使う(twpro) }
問題なし。
I2にでも書き込んでおく。
sheet.getRange(2,9).setValue(result_t); //I2に書き込み
ニコニコ動画のデータ取得
データ取得方法は色々あります。
その1 RSSフィードを使う
現状はこれ。
ニコニコ動画APIとは (ニコニコドウガエーピーアイとは) [単語記事] - ニコニコ大百科
から、
http://www.nicovideo.jp/tag/ + タグ +?rss=2.0で取得出来るrssをPHPでfile_get_contentsしてmb_ereg_replaceで件数書いてあるところだけ抜き出しています。
流用するだけなので簡単ですが、ちょっと他の方法も考えてみることにしました。
その2 ニコニコ大百科を使う
ニコニコ大百科は掲示板の上にその項目名の動画数のグラフを表示していますが、ソースを見るとjqPlotで描いてるらしく、生のデータが見れます。過去のデータも見れてご丁寧に配列になっています。
最初はこれを使う気だったのですが、ニコニコ大百科に記事がない場合この方法は使えないので諦めました。
その3 ニコニコ動画 『スナップショット検索API』を使う
なんかパッと見は難しそうだったのですが、せっかくなのでやってみようかと思いました。
出来なかったら諦めるぐらいの気持ちで。(RSS使えばいいし、という逃げ道があるので心理的に楽)
ニコニコ動画 『スナップショット検索API』 を触ってみる
とりあえずこれに辿り着いた。
ニコニコ動画 『スナップショット検索API』 に触ってみた - 唯物是真 @Scaled_Wurm
タイトルはパクった。
>JSONをPOSTする
まずこの意味がわからなくて困った。震えるほど初心者である。
ニコニコ動画 『スナップショット検索API』 ガイド
ドキュメントを見ると
【cURLでの実行例】 curl -v "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"query":"初音ミク","service":["video"],"search":["title","description","tags"],"join":["cmsid","title","view_counter"],"filters":[{"type":"range","field":"view_counter","to":10000}],"from":0,"size":3,"sort_by":"view_counter","issuer":"yourservice/applicationname"}' http://api.search.nicovideo.jp/api/snapshot/
こういう風に書いている。
つまりこういう感じで書けばいいんですかね?
GoogleAppsScript - Google Apps ScriptからHTTP POST - Qiita
ここに至るまでに結構時間がかかった。
ニコニコ動画 『スナップショット検索API』 を触ってみる(続き)
Stack Overflowにそのものがあったので使いまわすことに。
Using Google Apps Script to Post JSON Data - Stack Overflow
まずはドキュメントのサンプルを突っ込んでみる
function myFunction5() { var url = "http://api.search.nicovideo.jp/api/snapshot/"; //エンドポイント var data = { "query":"初音ミク", "service":[ "video" ], "search":[ "title", "description", "tags" ], "join":[ "cmsid", "title", "view_counter" ], "filters":[ { "type": "range", "field": "view_counter", "to": 10000 } ], "from":0, "size":3, "sort_by":"view_counter", "issuer": "your service/application name"}; //検索クエリJSON var payload = JSON.stringify(data); var headers = { "Accept":"application/json", "Content-Type":"application/json", "Authorization":"Basic _authcode_" }; var options = { "method":"POST", "headers": headers, "payload" : payload }; var response = UrlFetchApp.fetch(url, options); Logger.log(response); }
レスポンスはサンプルと同じものが返ってきました。
使うのは件数だけ。検索レスポンス仕様から、
type:statsチャンク: 検索結果に関するサービス毎の情報が返ってきます。複数あり。 service: サービス名 total: 検索ヒット件数
のtotalだけ使えばいい。つまり他のオプションはある程度適当でいい。
"filters"を外しておけば問題なし。ついでにオプションのパラメータは不要なので外しておく。
{ "query":"初音ミク", "service":[ "video" ], "search":[ "tags_exact" ], "join":[ "cmsid", "title", "view_counter" ], "issuer": "your service/application name"};
よーしこれでJSON.parseしちゃうぞーと思ったら、返り値をいじれない。
返り値が空になっているようにみえる。
何かと思えば、Logger.logだと見れるデータがデバッグモードだと見れない。
どういうこと?
>改行(\n)区切りを一つのチャンクとして、いくつかのチャンクに分かれて返ってきます。
これのおかげでobjectとして見てもらえないご様子。
じゃあどうするんだってことで・・・
・・・こうしよう!
(↑これに数時間かかった)
一旦文字列にすると扱える→jsonが改行で区切られて4つ並んでいるので、改行(\n)でsplitして2つ目を取り出したらあとは自由
れぶろぐ - [JavaScript] 正規表現で split した場合の IE の挙動
正規表現でsplitは普通にできるらしい。(replaceでの正規表現の書き方と同じ)
var response_n = UrlFetchApp.fetch(url, options); //取得(丸コピペ) var result_n1 = String(response_n); //objectにならないので一旦文字列にする var result_n2 = result_n1.split(/\n/); //改行で区切って配列にする var result_n3 = JSON.parse(result_n2[1]); //必要なjson(要素)だけパースする var result_n = result_n3.values[0].total; //必要な要素だけ取り出す
動いた。
実際これって普通どうやって扱うんですかね?適切な処理方法が別にあるような気がします。
動くからいいけどね。ゴリ押しでもなんとかなるもんだ。
書き込む場所はセルJ2
sheet.getRange(2,10).setValue(result_n); //J2に書き込み
変数名とかを修正。
function myFunction5() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1); //定義終了 var name = sheet.getRange(1, 7).getValue(); //入力しておいた名前を取得 var responseURL_n = "http://api.search.nicovideo.jp/api/snapshot/"; //エンドポイント var data = { "query":name, "service":[ "video" ], "search":[ "tags_exact" ], "join":[ "cmsid", "title", "view_counter" ], "issuer": "your service/application name"}; //検索クエリJSON var payload = JSON.stringify(data); var headers = { "Accept":"application/json", "Content-Type":"application/json" }; var options = { "method":"POST", "headers": headers, "payload" : payload }; //丸コピペなのでよくわからない var response_n = UrlFetchApp.fetch(responseURL_n, options); //取得(丸コピペ) var result_n1 = String(response_n); //objectにならないので一旦文字列にする var result_n2 = result_n1.split(/\n/); //改行で区切って配列にする var result_n3 = JSON.parse(result_n2[1]); //必要なjson(要素)だけパースする var result_n = result_n3.values[0].total; //必要な要素だけ取り出す sheet.getRange(2,10).setValue(result_n); //J2に書き込み }
これで動作したので、メインの流れに組み込む。
function myFunction() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; //URLからコピペ var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; //1番目のシートを指定 var lastrow = sheet.getLastRow(); //最終行を取得 var range = sheet.getRange(lastrow, 1); var yesterday = range.getValue(); //rangeの値(日付の文字列)を取得 var yesterday = Date.parse(yesterday); //日付形式に変換(ミリ秒) var target = yesterday + 24*60*60*1000; //24*60*60*1000で1日ずらす var target = new Date(target); //ミリ秒を日付形式に変換 var i_date = target.getDate(); //取得すべき日付 var mod_i = i_date -1; //書き込み位置を設定 var target_year = target.getYear(); //取得すべき日付の年 var target_month = target.getMonth()+1; //取得すべき日付の月 var target_month = ("0" + target_month).slice(-2); //2桁揃え var name = sheet.getRange(1, 7).getValue(); //入力しておいた名前を取得 var responseURL = "http://stats.grok.se/json/ja/" + target_year + target_month + "/" + name; //取得先のurlを設定 var response = UrlFetchApp.fetch(responseURL); //データを取得 var result = JSON.parse(response.getContentText()); //JSONをパース var result = result.daily_views; //パースしたもののうち、daily_viewsだけ使う // スプレッドシート(データ)への書き込み for(var i=i_date; i<=Object.keys(result).length; i++) { var day_number = ("0" + i).slice(-2); //2桁揃え var result_views = result[target_year + '-' + target_month + '-' + day_number]; var x = i-mod_i; // 日付 range.offset(x, 0).setValue(target_year + '-' + target_month + '-' + day_number); // データ range.offset(x, 1).setValue(result_views); } sheet.getRange(75,3).setValue('=average(B71:B75)'); //移動平均5日の数式をセット sheet.getRange(75,4).setValue('=average(B51:B75)'); //25日 sheet.getRange(75,5).setValue('=average(B1:B75)'); //75日 var lastrow = sheet.getLastRow(); //データ書き込み後の最終行を取得 var rangeToCopy = sheet.getRange(75,3,1,3); //C75:E75のセル範囲 var targetToCopy = sheet.getRange(75,3,lastrow-74,3); //C75:E最終行までのセル範囲 rangeToCopy.copyTo(targetToCopy); var today = sheet.getRange(lastrow,2).getValue(); //最新の値 var lastweek = sheet.getRange(lastrow-7,2).getValue(); //最新の7日前の値 var change1 = today - lastweek; //引き算 sheet.getRange(2,7).setValue(change1); //G2に書き込み var change2 = change1/lastweek; //前週比 sheet.getRange(2,8).setValue(change2); //H2に書き込み //twproパートここから var name = sheet.getRange(1, 7).getValue(); //入力しておいた名前を取得 var responseURL_t = "http://api.twpro.jp/1/search?q=" + name + "&num=1"; //取得先のurlを設定(twpro) var response_t = UrlFetchApp.fetch(responseURL_t); //データを取得(twpro) var result_t = JSON.parse(response_t.getContentText()); //JSONをパース(twpro) var result_t = result_t.total; //パースしたもののうち、totalだけ使う(twpro) sheet.getRange(2,9).setValue(result_t); //I2に書き込み //twproパートここまで //ニコニコパートここから var responseURL_n = "http://api.search.nicovideo.jp/api/snapshot/"; //エンドポイント var data = { "query":name, "service":[ "video" ], "search":[ "tags_exact" ], "join":[ "cmsid", "title", "view_counter" ], "issuer": "your service/application name"}; //検索クエリJSON var payload = JSON.stringify(data); var headers = { "Accept":"application/json", "Content-Type":"application/json" }; var options = { "method":"POST", "headers": headers, "payload" : payload }; //この3つは丸コピペなのでよくわからない var response_n = UrlFetchApp.fetch(responseURL_n, options); //取得(丸コピペ) var result_n1 = String(response_n); //objectにならないので一旦文字列にする var result_n2 = result_n1.split(/\n/); //改行で区切って配列にする var result_n3 = JSON.parse(result_n2[1]); //必要なjson(要素)だけパースする var result_n = result_n3.values[0].total; //必要な要素だけ取り出す sheet.getRange(2,10).setValue(result_n); //J2に書き込み //ニコニコパートここまで }
もしもデータが返ってこなかったら
while文かな?
while文の演習
Google Apps Script Documentation - Utilities Services - Class Utilities
ここにはsleepは5000ミリ秒まで、と書いてあるが、そんな事はないようだ。普通にそれより大きい数を指定してもおk
var responseURL = "http://stats.grok.se/json/ja/" + target_year + target_month + "/" + name; //取得先のurlを設定 var response = UrlFetchApp.fetch(responseURL); //データを取得 while(response == ''){ Utilities.sleep(30000); var response = UrlFetchApp.fetch(responseURL); }; //返ってきたデータが空だったら30秒後にリトライ
ループを抜けることはできているようです。ただしエラーで役に立つかは謎。
twproとニコニコ動画も同じようにしておく。
過去のデータを削除する
このままデータの取得を繰り返すと無限にデータが増大して重くなるので歯止めをかけておく。
1行目を削除してからデータを1つ追加すればデータが増えることはない。
その際移動平均の計算式がずれるので配慮しておく。
Google Apps Scriptリファレンス: 行を削除する
[GAS][スプレッドシート]セルの値をクリアするには : 逆引きGoogle Apps Script
1行目を削除→C列〜E列の値をクリア(移動平均の計算式を消す)→データ取得→書き込み→移動平均の計算式の設定
というイメージ
function myFunction10() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; var lastrow = sheet.getLastRow(); var range = sheet.getRange(lastrow, 1); //定義終了 ss.deleteRow(1); //1行目を削除 }
1行目削除したら名前を入力してあるのが消えるじゃねーか!
何も考えずにやったらこれだよ。
名前の入力場所をセルF2に変更
1行目を削除したら、1行目に移動した2行目のセルを元の場所にコピペする
sheet.deleteRow(1); //1行目を削除 var rangeToCopy = sheet.getRange(1,6,1,5); //2行目になければならないもの var targetToCopy = sheet.getRange(2,6,1,5); //2行目の場所 rangeToCopy.copyTo(targetToCopy); //貼り付け rangeToCopy.clear(); //1行目に移動してしまったものを消しておく。 sheet.getRange('C:E').clear(); //C列〜E列に入っている移動平均の計算式を消しておく(あとで入力)
動いた。
これも取り込む。
一旦終了
現在の状態がこちら
function myFunction() { var SPREADSHEET_ID = '1kyJS7B6JAJzC_tXR2chDWvX8R7o1--C_-96IDFCWqu4'; //URLからコピペ var ss = SpreadsheetApp.openById(SPREADSHEET_ID); var sheet = ss.getSheets()[0]; //1番目のシートを指定 //1行目を削除する〜ここから sheet.deleteRow(1); //1行目を削除 var rangeToCopy = sheet.getRange(1,6,1,5); //2行目になければならないもの var targetToCopy = sheet.getRange(2,6,1,5); //2行目の場所 rangeToCopy.copyTo(targetToCopy); //貼り付け rangeToCopy.clear(); //1行目に移動してしまったものを消しておく。 sheet.getRange('C:E').clear(); //C列〜E列に入っている移動平均の計算式を消しておく(あとで入力) //1行目を削除する〜ここまで var lastrow = sheet.getLastRow(); //最終行を取得 var range = sheet.getRange(lastrow, 1); var yesterday = range.getValue(); //rangeの値(日付の文字列)を取得 var yesterday = Date.parse(yesterday); //日付形式に変換(ミリ秒) var target = yesterday + 24*60*60*1000; //24*60*60*1000で1日ずらす var target = new Date(target); //ミリ秒を日付形式に変換 var i_date = target.getDate(); //取得すべき日付 var mod_i = i_date -1; //書き込み位置を設定 var target_year = target.getYear(); //取得すべき日付の年 var target_month = target.getMonth()+1; //取得すべき日付の月 var target_month = ("0" + target_month).slice(-2); //2桁揃え var name = sheet.getRange(2,6).getValue(); //入力しておいた名前を取得 var responseURL = "http://stats.grok.se/json/ja/" + target_year + target_month + "/" + name; //取得先のurlを設定 var response = UrlFetchApp.fetch(responseURL); //データを取得 while(response == ''){ Utilities.sleep(30000); var response = UrlFetchApp.fetch(responseURL); }; //返ってきたデータが空だったら30秒後にリトライ var result = JSON.parse(response.getContentText()); //JSONをパース var result = result.daily_views; //パースしたもののうち、daily_viewsだけ使う // スプレッドシート(データ)への書き込み for(var i=i_date; i<=Object.keys(result).length; i++) { var day_number = ("0" + i).slice(-2); //2桁揃え var result_views = result[target_year + '-' + target_month + '-' + day_number]; var x = i-mod_i; // 日付 range.offset(x, 0).setValue(target_year + '-' + target_month + '-' + day_number); // データ range.offset(x, 1).setValue(result_views); } sheet.getRange(75,3).setValue('=average(B71:B75)'); //移動平均5日の数式をセット sheet.getRange(75,4).setValue('=average(B51:B75)'); //25日 sheet.getRange(75,5).setValue('=average(B1:B75)'); //75日 var lastrow = sheet.getLastRow(); //データ書き込み後の最終行を取得 var rangeToCopy = sheet.getRange(75,3,1,3); //C75:E75のセル範囲 var targetToCopy = sheet.getRange(75,3,lastrow-74,3); //C75:E最終行までのセル範囲 rangeToCopy.copyTo(targetToCopy); var today = sheet.getRange(lastrow,2).getValue(); //最新の値 var lastweek = sheet.getRange(lastrow-7,2).getValue(); //最新の7日前の値 var change1 = today - lastweek; //引き算 sheet.getRange(2,7).setValue(change1); //G2に書き込み var change2 = change1/lastweek; //前週比 sheet.getRange(2,8).setValue(change2); //H2に書き込み //twproパートここから var responseURL_t = "http://api.twpro.jp/1/search?q=" + name + "&num=1"; //取得先のurlを設定(twpro) var response_t = UrlFetchApp.fetch(responseURL_t); //データを取得(twpro) while(response_t == ''){ Utilities.sleep(30000); var response_t = UrlFetchApp.fetch(responseURL); }; //返ってきたデータが空だったら30秒後にリトライ var result_t = JSON.parse(response_t.getContentText()); //JSONをパース(twpro) var result_t = result_t.total; //パースしたもののうち、totalだけ使う(twpro) sheet.getRange(2,9).setValue(result_t); //I2に書き込み //twproパートここまで //ニコニコパートここから var responseURL_n = "http://api.search.nicovideo.jp/api/snapshot/"; //エンドポイント var data = { "query":name, "service":[ "video" ], "search":[ "tags_exact" ], "join":[ "cmsid", "title", "view_counter" ], "issuer": "your service/application name"}; //検索クエリJSON var payload = JSON.stringify(data); var headers = { "Accept":"application/json", "Content-Type":"application/json" }; var options = { "method":"POST", "headers": headers, "payload" : payload }; //この3つは丸コピペなのでよくわからない var response_n = UrlFetchApp.fetch(responseURL_n, options); //取得(丸コピペ) while(response_n == ''){ Utilities.sleep(30000); var response_n = UrlFetchApp.fetch(responseURL); }; //返ってきたデータが空だったら30秒後にリトライ var result_n1 = String(response_n); //objectにならないので一旦文字列にする var result_n2 = result_n1.split(/\n/); //改行で区切って配列にする var result_n3 = JSON.parse(result_n2[1]); //必要なjson(要素)だけパースする var result_n = result_n3.values[0].total; //必要な要素だけ取り出す sheet.getRange(2,10).setValue(result_n); //J2に書き込み //ニコニコパートここまで }
大丈夫みたいです。
もし巡回対象を増やすなら、一人1シートにして、全体をfor文でくくって var sheet = ss.getSheets()[i];とかにしてシート数分ループすれば、と考えています。