はじめに
この記事はGoogle Apps Script Advent Calendar 2018 の22日目の記事です
GoogleAppsScriptのドキュメントを眺めていたらChartServiceというものを見つけて使ってみたくなったので使ってみます
Charts Service | Apps Script | Google Developers
https://developers.google.com/apps-script/reference/charts/developers.google.com
やってることはありがちなやつだし代替手段もいくらでもありそうですが、気軽に実践できるということで!
やりたいこと
たとえばブログのPVなど、GoogleAnalytics見に行けば良いといえば良いのですが、毎日Slackで簡易レポート的なものが送られてきたら楽ですよね?
定期的に(毎日とか)に数値を見ることで変化に気づけるかも?ということでやってみます
手順
- claspでプロジェクト作成
- clasp login
- 実装
- AnalyticsServiceで数値データを取得
- ChartServiceでグラフを生成
- SlackへPost
- ScriptPropertyへTOKENを登録
- SlackのAPITOKEN
- SlackのチャンネルID
- AnalyticsのID
- 定期実行トリガーの設定
「プロジェクトの作成からコード書いて実行できるようになるまで」は今回割愛し実装からやってみます
下記の記事で扱っているので気になる方はこちらを参照してください
Google App Script(clasp)でソーシャルカウントを取得して可視化する - notebook
AnalyticsServiceで数値データを取得
Analyticsの数値は下記で確認しながら欲しいデータを選定します
Query Explorer — Google Analytics Demos & Tools
https://ga-dev-tools.appspot.com/query-explorer/ga-dev-tools.appspot.com
こんな感じのコードになりました
const from = Moment.moment().subtract(1, "days").format("YYYY-MM-DD");
const to = Moment.moment().subtract(1, "days").format("YYYY-MM-DD");
const metrics = "ga:pageViews";
const options = {
"dimensions": "ga:pageTitle",
"max-results": 5000,
};
const gaReport = Analytics.Data.Ga.get(
`ga:${PropertiesService.getScriptProperties().getProperty("GA_TABLE_ID")}`,
from,
to,
metrics,
options,
);
ChartServiceでグラフ生成
今回いじってみたかった箇所です
- DataTableを生成して、Analyticsから取得したレポートデータを逐次突っ込む
- チャートを生成する
- イメージ化する
const dataTable = Charts.newDataTable()
.addColumn(Charts.ColumnType.STRING, "Title")
.addColumn(Charts.ColumnType.NUMBER, "PV");
gaReport.rows.sort((a,b) => b[1] - a[1]).filter((_,i) => i < 10).forEach(row => {
dataTable.addRow(row);
});
const chart = Charts.newBarChart()
.setDataTable(dataTable)
.setTitle("前日PV上位10記事")
.build();
const imageFile = chart.getAs("image/png");
とくに難しいことはないですね
本当は下記を使用して前々日と比較したグラフをポストしたかったのですがよく見たら「GoogleAppsScript」じゃなく「GoogleCharts」のドキュメントだったのでさっと実装できず
Diff Charts | Charts | Google Developers
https://developers.google.com/chart/interactive/docs/gallery/diffchartdevelopers.google.com
今後の宿題にしておきます。。。
Slackへpost
SlackのファイルアップロードAPIに対してUrlFetchAppを使用してポストするだけです
後述するプロパティサービスを使ってTOKENなどを取得します
const token = PropertiesService.getScriptProperties().getProperty(
"SLACK_API_TOKEN"
);
const channelId = PropertiesService.getScriptProperties().getProperty(
"SLACK_CHANNEL_ID"
);
UrlFetchApp.fetch("https://slack.com/api/files.upload", {
method: "post",
payload: {
channels: channelId,
file: imageFile,
filename: "daily-pv-top-10.png",
token: token,
}
});
ScriptPropertyへデータを登録
APIトークンなどコード上でべた書きしたくないものをこのプロパティに登録してスクリプトから特定の操作をして取り出すことで安全にデータを取得できる仕組みです
登録はスクリプトエディターの画面からFile -> Project Properties -> Script properties
タブまで遷移すると設定できます

今回はSlackのAPI TOKEN, チャンネルID, AnalyticsのテーブルIDを登録しました
GASのコード上ではこんな感じで取り出します
const token = PropertiesService.getScriptProperties().getProperty( "SLACK_API_TOKEN" );
タイムアップで調べられなかったのですがプロパティもCLIから登録できたらうれしいですね
定期実行トリガーの設定
Edit -> Current project's triggersから別タブへ遷移し新たに設定します
今回は毎日朝に前日分のデータを受け取るようにしました

他
ちょっと詰まったとことか後で見返したとき用のメモ的なものを残しておきます
- clasp login
clasp login --no-localhost
手動でキーを入力するパターン
VMとかの中で開発しているときとかに使って手動でキーを入力してログインするためのオプション
- Analyticsレポートの有効化
毎度やりかた忘れてるのでリンクだけ残しておきます
GoogleAnalyticsのAPIとGoogleAppsScriptでGoogleAnalyticsのレポートを自動化する方法 - Bowyer Tech Blog
appscript.jsonのdependenciesに記述してpushするだけではGAS経由で実行できず
コンソールから対象プロジェクトからのAPIアクセスを許可する必要があります
実行
最終的なコードはこうなりました
- src/appscript.json
{
"timeZone": "America/New_York",
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "AnalyticsReporting",
"serviceId": "analyticsreporting",
"version": "v4"
}, {
"userSymbol": "Analytics",
"serviceId": "analytics",
"version": "v3"
}],
"libraries": [{
"userSymbol": "Moment",
"libraryId": "15hgNOjKHUG4UtyZl9clqBbl23sDvWMS8pfDJOyIapZk5RBqwL3i-rlCo",
"version": "9"
}]
},
"exceptionLogging": "STACKDRIVER"
}
- src/Code.ts
function sendReport() {
const from = Moment.moment()
.subtract(1, "days")
.format("YYYY-MM-DD");
const to = Moment.moment()
.subtract(1, "days")
.format("YYYY-MM-DD");
const metrics = "ga:pageViews";
const options = {
dimensions: "ga:pageTitle",
"max-results": 5000
};
const gaReport = Analytics.Data.Ga.get(
`ga:${PropertiesService.getScriptProperties().getProperty("GA_TABLE_ID")}`,
from,
to,
metrics,
options
);
Logger.log(gaReport);
const dataTable = Charts.newDataTable()
.addColumn(Charts.ColumnType.STRING, "Title")
.addColumn(Charts.ColumnType.NUMBER, "PV");
gaReport.rows
.sort((a, b) => b[1] - a[1])
.filter((_, i) => i < 10)
.forEach(row => {
dataTable.addRow(row);
});
const chart = Charts.newBarChart()
.setDataTable(dataTable)
.setTitle("前日PV上位10記事")
.build();
const imageFile = chart.getAs("image/png");
const token = PropertiesService.getScriptProperties().getProperty(
"SLACK_API_TOKEN"
);
const channelId = PropertiesService.getScriptProperties().getProperty(
"SLACK_CHANNEL_ID"
);
UrlFetchApp.fetch("https://slack.com/api/files.upload", {
method: "post",
payload: {
channels: channelId,
file: imageFile,
filename: "daily-pv-top-10.png",
token: token
}
});
}
実行してみるとこんな出力になります

まとめ
あれ?PV数が少n。。。っていうのは気にしない方向で。。。w
細かいところだと色変えたかったりタイトルを全部読めるようにしたかったりと色々ありますがいったんやりたかった定期的にレポートを投げるということができるようになりました
投稿が画像ポストになってしまっているのでマウス当てたらツールチップが出るとかそういう挙動はできません
なので意味合い的には速報的な使い方なのであまり凝ったグラフにする必要もなさそうですね
実装自体は表現したいチャートのドキュメント探してそれ見て実装するだけです
結構楽なのでブログのレポート以外にも色々使えると思います
今後活用していきたいと思いました