GA4 の Analytics Data API を使ってみた2
前回の続きで、Data API を使ったの改善版です。
追加でやったのは、
Dimension を複数設定する
Metric を複数設定する
ソートできるようにする
の3つです。早速ですが、スクリプトの内容は以下の通りです。
実行方法
※ 普段 GAS も JS も触っていないので、文法的には怪しい箇所が多数あります。自己責任でご参照ください。
/**
* Runs a report of a Google Analytics 4 property ID. Creates a sheet with the
* report.
*/
function main() {
const SHEET_ID = 'hoge';
const REPORT_CONFIG_SHEET = 'ReportConfig';
// config シートから必要な情報を取得する。
const spreadsheet = SpreadsheetApp.openById(SHEET_ID);
const configs = getConfig(spreadsheet, REPORT_CONFIG_SHEET);
for (let i =0; i < configs.length; i++){
getData(spreadsheet, configs[i]);
}
}
function convertDate(date) {
try {
const dateType = Object.prototype.toString.call(date);
if (dateType == '[object Date]') {
return Utilities.formatDate(date, 'JST', 'yyyy-MM-dd');
} else {
return date;
}
} catch(e) {
console.log('Failed convert date parameters with error: %s', e.error);
}
}
/**
* カンマ区切りの文字列を array に変換します。
* @param {string} params
* @return {array}
*/
function getArray(params) {
let arrayParams = params.split(',');
for (let i = 0; i < arrayParams.length; i++) {
arrayParams[i] = arrayParams[i].trim();
}
return arrayParams;
}
/**
* ソートのデータを変換します。
* @param {string} params
* @return {array}
*/
function getOrderBy(params) {
let orderByParams = [];
const arrayParams = params.split(',');
for (let i = 0; i < arrayParams.length; i++) {
const arrayParam = arrayParams[i].trim();
const orderByParam = arrayParam.split(' ');
if (orderByParam.length == 2 && orderByParam[1] == 'desc') {
orderByParams.push({
'dimensionName': orderByParam[0],
'isDesc': true,
})
} else {
orderByParams.push({
'dimensionName': orderByParam[0],
'isDesc': false,
})
}
}
return orderByParams;
}
function getConfig(spreadsheet, reportConfigSheet) {
try {
const sheet = spreadsheet.getSheetByName(reportConfigSheet);
const lastRow = sheet.getLastRow();
let rowNum = 2;
let params = [];
while (rowNum <= lastRow) {
const range = sheet.getRange(Utilities.formatString('A%s:G%s', rowNum, rowNum));
let values = range.getValues();
values[0][2] = convertDate(values[0][2]);
values[0][3] = convertDate(values[0][3]);
values[0][4] = getArray(values[0][4]);
values[0][5] = getArray(values[0][5]);
values[0][6] = getOrderBy(values[0][6]);
params.push({
'propertyId': values[0][0],
'sheetName': values[0][1],
'startDate': values[0][2],
'endDate': values[0][3],
'metric': values[0][4],
'dimension': values[0][5],
'orderBy': values[0][6],
});
rowNum ++;
}
return params;
} catch(e) {
console.log('Failed reading parameters with error: %s', e.error);
}
}
function getData(spreadsheet, config) {
try {
let metrics = [];
for (let i = 0; i < config.metric.length; i++) {
const metric = AnalyticsData.newMetric();
metric.name = config.metric[i];
metrics.push(metric);
}
let dimensions = [];
for (let i = 0; i < config.dimension.length; i++) {
const dimension = AnalyticsData.newDimension();
dimension.name = config.dimension[i];
dimensions.push(dimension);
}
const dateRange = AnalyticsData.newDateRange();
dateRange.startDate = config.startDate;
dateRange.endDate = config.endDate;
let orderBys = [];
for (let i = 0; i < config.orderBy.length; i++) {
const orderBy = AnalyticsData.newOrderBy();
const dimensionOrderBy = AnalyticsData.newDimensionOrderBy();
dimensionOrderBy.dimensionName = config.orderBy[i].dimensionName;
orderBy.dimension = dimensionOrderBy;
orderBy.desc = config.orderBy[i].isDesc;
orderBys.push(orderBy);
}
const request = AnalyticsData.newRunReportRequest();
request.dimensions = dimensions;
request.metrics = metrics;
request.dateRanges = dateRange;
request.orderBys = orderBys;
const report = AnalyticsData.Properties.runReport(request,
'properties/' + config.propertyId);
if (!report.rows) {
console.log('No rows returned.');
return;
}
const sheets = spreadsheet.getSheets();
var existFlg = 0;
for (let i = 0; i < sheets.length; i++) {
if (config.sheetName == sheets[i].getName()) {
existFlg = 1;
}
}
if (existFlg == 0) {
spreadsheet.insertSheet(config.sheetName);
}
const sheet = spreadsheet.getSheetByName(config.sheetName);
sheet.clear();
// Append the headers.
const dimensionHeaders = report.dimensionHeaders.map(
(dimensionHeader) => {
return dimensionHeader.name;
});
const metricHeaders = report.metricHeaders.map(
(metricHeader) => {
return metricHeader.name;
});
const headers = [...dimensionHeaders, ...metricHeaders];
sheet.appendRow(headers);
// Append the results.
const rows = report.rows.map((row) => {
const dimensionValues = row.dimensionValues.map(
(dimensionValue) => {
return dimensionValue.value;
});
const metricValues = row.metricValues.map(
(metricValues) => {
return metricValues.value;
});
return [...dimensionValues, ...metricValues];
});
sheet.getRange(2, 1, report.rows.length, headers.length)
.setValues(rows);
console.log('Report spreadsheet created: %s',
spreadsheet.getUrl());
} catch (e) {
// TODO (Developer) - Handle exception
console.log('Failed with error: %s', e.error);
}
}
内容として、やや難しかったのは
let metrics = [];
for (let i = 0; i < config.metric.length; i++) {
const metric = AnalyticsData.newMetric();
metric.name = config.metric[i];
metrics.push(metric);
}
で metric や dimension、orderBy で複数の項目を入れる時には、array にどんどん条件を格納していくというとこでした。
AnalyticsData.newMetric.name に項目を array にして項目を追加してもエラーになるので、かなり混乱しました。JS 的には普通の表現なのかもしれませんが。
ReportConfig は OrderBy の1列追加します。ここにソートをかけたい内容を入れます。
Metric、Dimension もカンマ(,)区切りで複数入れます。
PropertyID: GA4 の値を取得する property ID
SheetName: 出力先のシート名
StartDate: データを取得する開始日
EndData: データを取得する終了日
Metric: 取得したい指標
Dimension: 取得したい次元
OrderBy: Dimension でソートする次元
これで、最低限必要なデータは取れそうです。
いくつか触ってみて修正が必要な箇所が出てきたら、また追記します。