Google App Script(GAS)を使うと、スプレッドシートなどのGoogleのサービスでダウンロードボタンを設置して、CSVファイルやPDFファイルをダウンロードすることができます。
ここでは、サイドバー形式でCSVとPDFのダウンロードボタンを設置してダウンロードする方法について使用しているコードの意味を含めて解説しています。
どんなことができるか?
ここで紹介するのは以下のようなプログラムです。
スプレッドシートの上部メニューに「プログラム」という項目を追加し、その中に「ファイルダウンロード」というメニューを設置します。
「ファイルダウンロード」をクリックするとサイドバーが開き、ダウンロードボタンが表示されます。
「CSV」または「PDF」をクリックすると、現在のスプレッドシートの内容をCSVやPDFファイルとして自動ダウンロードし、ダウンロードフォルダに格納するプログラムです。
ファイルを開くと以下のようになります。
▼CSVファイル
▼PDFファイル
コードの全体像
作成するのは以下の2つのファイルです。
それぞれのファイルのコードは以下になります。
function onOpen() {
const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu('プログラム');
menu.addItem('ファイルダウンロード', 'sidebarDownload');
menu.addToUi();
}
function sidebarDownload() {
const html = HtmlService.createHtmlOutputFromFile("index").setTitle("ダウンロードボタン");
SpreadsheetApp.getUi().showSidebar(html);
}
function createDataUrl(type) {
const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL, pdf: MimeType.PDF };
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
let url = null;
if (type == "csv") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
} else if (type == "pdf") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${sheet.getSheetId()}`;
}
if (url) {
const blob = UrlFetchApp.fetch(url, {
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
}).getBlob();
return {
data:
`data:${mimeTypes[type]};base64,` +
Utilities.base64Encode(blob.getBytes()),
filename: `${sheet.getSheetName()}.${type}`,
};
}
return { data: null, filename: null };
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
input {
border-radius: 50%;
line-height: 100px;
width: 100px;
height: 100px;
padding: 0 5px 0;
margin: 15px;
background: #f0e0e0;
-webkit-box-shadow: 0 5px 0 #f0e0e0;
box-shadow: 0 5px 0 #f0e0e0;
}
input:hover {
-webkit-transform: translate(0, 3px);
transform: translate(0, 3px);
-webkit-box-shadow: 0 2px 0 #f0e0e0;
box-shadow: 0 2px 0 #f0e0e0;
}
</style>
</head>
<body>
<h1 align="center">ダウンロード</h1>
<div align="center">
<input type="button" value="CSV" onclick="download('csv')" /><br>
<input type="button" value="PDF" onclick="download('pdf')" />
</div>
</body>
<script>
function download(type) {
google.script.run
.withSuccessHandler(({ data, filename }) => {
if (data && filename) {
const a = document.createElement("a");
document.body.appendChild(a);
a.download = filename;
a.href = data;
a.click();
}
})
.createDataUrl(type);
}
</script>
</html>
サイドバーの作成方法
スプレッドシートにサイドバーを表示する方法はここでは割愛します。詳細は下記をご参考ください。
作成したときに、AppScriptとHTMLファイルの中身をそれぞれ上記のファイルにしてください。
ダウンロード処理の流れ
サイドバーでHTMLファイルを表示する
続いて実際のダウンロード処理の流れについて解説します。
スプレッドシート上で「ファイルダウンロード」というメニューをクリックすると「sidebarDownload」という関数を実行します。
function sidebarDownload() {
const html = HtmlService.createHtmlOutputFromFile("index").setTitle("ダウンロードボタン");
SpreadsheetApp.getUi().showSidebar(html);
}
これでサイドバーに指定したHTMLファイルの内容を表示します。
onclickイベント
ボタンをクリックするとHTMLファイルで割り当てられているonclickイベントが発動します。
<input type="button" value="CSV" onclick="download('csv')" /><br>
<input type="button" value="PDF" onclick="download('pdf')" />
inputの属性の1つに「onclick」を設定することで、このタグに対してonclickのイベントハンドラを設置することができます。
実行する関数名と渡す引数を指定します。
onclick="実行する関数名(引数)"
例えば、以下のような記述があるとします。
<input type="button" value="CSV" onclick="download('csv')" />
この場合、CSVと書かれたinputボタンをクリックすると、downloadという関数を実行し、その関数にcsvという文字列を引数として渡します。
scriptタグ、download関数
HTML内にscriptタグを使って実行するdownload関数の処理を記述します。
<script>
function download(type) {
google.script.run
.withSuccessHandler(({ data, filename }) => {
if (data && filename) {
const a = document.createElement("a");
document.body.appendChild(a);
a.download = filename;
a.href = data;
a.click();
}
})
.createDataUrl(type);
}
</script>
function download(type)
とすることで、渡された引数の値をtypeという変数に格納します。
CSVボタンがクリックされた場合はtype="csv"
、PDFボタンがクリックされた場合はtype="pdf"
となります。
ここの処理は結構肝なので、下の方に切り出して詳細を解説します。
createDataUrl関数
download関数の処理の中で「createDataUrl関数」も実行しています。
.createDataUrl(type);
これは、AppScriptに記述してある関数です。
function createDataUrl(type) {
const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL, pdf: MimeType.PDF };
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
let url = null;
if (type == "csv") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
} else if (type == "pdf") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${sheet.getSheetId()}`;
}
if (url) {
const blob = UrlFetchApp.fetch(url, {
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
}).getBlob();
return {
data:
`data:${mimeTypes[type]};base64,` +
Utilities.base64Encode(blob.getBytes()),
filename: `${sheet.getSheetName()}.${type}`,
};
}
return { data: null, filename: null };
}
この処理を実行することで、スプレッドシートをCSVやPDFに変換してダウンロードするためのリンクを生成します。
戻り値の部分は以下になります。
return {
data:
`data:${mimeTypes[type]};base64,` +
Utilities.base64Encode(blob.getBytes()),
filename: `${sheet.getSheetName()}.${type}`,
};
オブジェクト形式でdataプロパティの値にダウンロード用のURL、filemameプロパティの値にシート名.typeというファイル名を指定しています。
この戻り値がgoogle.script.run.withSuccessHandler
に渡されます。
.withSuccessHandler(({ data, filename }) => {
if (data && filename) {
const a = document.createElement("a");
document.body.appendChild(a);
a.download = filename;
a.href = data;
a.click();
}
})
aタグにファイルダウンロードの名前としてdownload=filenameという属性を追加し、ダウンロードリンクとしてhref=dataという属性を追加しています。
最後に、clickイベントを使って自動ダウンロードを行います。
scriptタグの中身
今回の処理で肝となるscriptタグの中身についてもう少し詳しく解説していきます。
<script>
function download(type) {
google.script.run
.withSuccessHandler(({ data, filename }) => {
if (data && filename) {
const a = document.createElement("a");
document.body.appendChild(a);
a.download = filename;
a.href = data;
a.click();
}
})
.createDataUrl(type);
}
</script>
google.script.runとは何か?
onlickイベントで作動する処理の一番最初にgoogle.script.run
があります。
これはAppScriptで作成したHTMLファイルの中でAppScriptを実行できるとても便利な処理です。
App Scriptではファイルの種類として「スクリプト」と「HTML」を作成することができます。
このHTMLファイルの中で使う処理になります。
(参考)クラス google.script.run(クライアントサイド API)
withSuccessHandler
withSuccessHandlerはgoogle.script.runクラスの中で使えるメソッドです。
以下のように使用します。
google.script.run.withSuccessHandler(関数).先に実行する関数
withSuccessHandlerを使うと、後ろに指定したサーバーサイド関数が正常に返された場合に実行するコールバック関数を設定することができます。
簡単に言うと、先に用意されている関数がエラーなく実行されたら次にこの処理を行うということです。
今回使用しているコードをざっくりまとめると以下になります。
google.script.run
.withSuccessHandler(処理)
.createDataUrl(type);
つまり、先にcreateDataUrl(type)を実行し、その結果を受けてwithSuccessHandlerの処理を行うという処理になります。
(参考)クラス google.script.run: withSuccessHandler
createDataUrl(type)|CSVとPDFダウンロード用のURLを作成する
コード全体像
withSuccessHandlerで指定した関数を実行する前に実行しているのがcreateDataUrl(type)
です。
<script>
function download(type) {
google.script.run
.withSuccessHandler()
.createDataUrl(type);
}
</script>
download関数で渡された引数を渡しています。
この関数はappscriptの方に記載されています。この処理でCSVとPDFダウンロード用のURLを作成します。
function createDataUrl(type) {
const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL, pdf: MimeType.PDF };
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
let url = null;
if (type == "csv") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
} else if (type == "pdf") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${sheet.getSheetId()}`;
}
if (url) {
const blob = UrlFetchApp.fetch(url, {
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
}).getBlob();
return {
data:
`data:${mimeTypes[type]};base64,` +
Utilities.base64Encode(blob.getBytes()),
filename: `${sheet.getSheetName()}.${type}`,
};
}
return { data: null, filename: null };
}
CSVダウンロードURLの作成
スプレッドシートのURLを作成
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
まず、スプレッドシートをCSVとしてダウンロードするためのURLを生成してます。
https://docs.google.com/spreadsheets/d/${ss.getId()}
スプレッドシートのオブジェクトに対してgetIdを使用することでシートのID番号を取得しています。
gvizライブラリを使用|gvizとは何か?
/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
続いて「gviz」という表記を入れています。これは「Google Visualization API」というAPIを使用するという指示です。
後ろのtq?以降でどのように使用するかを指定しています。
tqx=out:csv&gid=${sheet.getSheetId()}`;
上記のようにtqxを使用して「out:csv」を指定するとCSVファイルをダウンロードすることができます。
PDFダウンロードURLの作成
https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${sheet.getSheetId()}
スプレッドシートをPDFに変換して保存するためのURLを作成しています。
export?format=pdf&gid=${sheet.getSheetId()}
スプレッドシートを指定したあとにexport?format=pdf
と指定し、アンパサンド(&)で対象のシートのIDを指定すれば、そのシートをPDFとしてダウンロードするためのリンクを生成します。
なお、このURLにパラメータを付け足すことでPDFの向きやマージンなどを設定することもできます。
(参考)Google スプレッドシートから PDF を生成して送信
Base64への変換(エンコード)
Base64とは何か?
上記で作成したダウンロード用のURLをクリックするだけでもダウンロードできます。
ですが、ここではより汎用性を持たせるためにダウンロードファイルをbase64にエンコードして、base64の状態でダウンロードリンクを作成しています。
function createDataUrl(type) {
const mimeTypes = { csv: MimeType.MICROSOFT_EXCEL, pdf: MimeType.PDF };
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
let url = null;
if (type == "csv") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/gviz/tq?tqx=out:csv&gid=${sheet.getSheetId()}`;
} else if (type == "pdf") {
url = `https://docs.google.com/spreadsheets/d/${ss.getId()}/export?format=pdf&gid=${sheet.getSheetId()}`;
}
if (url) {
const blob = UrlFetchApp.fetch(url, {
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
}).getBlob();
return {
data:
`data:${mimeTypes[type]};base64,` +
Utilities.base64Encode(blob.getBytes()),
filename: `${sheet.getSheetName()}.${type}`,
};
}
return { data: null, filename: null };
}
base64への変換処理
ファイルをbase64に変換する処理は以下になります。
const blob = UrlFetchApp.fetch(url, {
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
}).getBlob();
return {
data:
`data:${mimeTypes[type]};base64,` +
Utilities.base64Encode(blob.getBytes()),
filename: `${sheet.getSheetName()}.${type}`,
};
Blobをbase64にエンコードする方法(解説用)
上記の処理はURLを利用してBlobファイルを取得しているため複雑に見えますが、より簡略化すると以下のようになります。
const blob = Utilities.newBlob(データ);
Utilities.base64Encode(blob.getBytes());
GASのUtilitiesクラスのnewBlobメソッドを使うことで、引数に指定したデータをBlobとして取得することができます。
このBlobデータに対してgetBytesメソッドを使うと、バイトとして取得することができます。
これを、Utilitesクラスのbase64Encodeメソッドを使ってbase64にエンコードします。
ダウンロードURLから取得したファイルをBlobファイルに変換する
今回の場合はGoogleドライブなどに保存されたファイルを直接blobファイルとして取得するのではなく、ダウンロードURLから取得したファイルをBlobファイルに変換します。
const blob = UrlFetchApp.fetch(url, {
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
}).getBlob();
UrlFetchApp
UrlFetchAppクラスを使うと、インターネット経由でリソースを取得することができます。他のWEBサイト上のデータを取得するなどスクレイピングで使われることが多いです。
fetch
fetchメソッドはUrlFetchAppクラスで使えるメソッドです。
fetch(url, パラメーター)
第1引数でアクセスしたいURLを指定し、第2引数に付与したいパラメータを指定します。第2引数は省略可能です。
パラメータは以下のようにオブジェクト形式で記述します。
{
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
}
今回の場合は以下のように headersを指定しています。
UrlFetchApp.fetch(url, {headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` }})
「Authorization」を使って認証処理をおこないたいのでヘッダーリクエストに認証情報を渡しています。
なお、headersなどのパラメータはJavaScriptのfetchメソッドに準拠しています。
(参考)
OAuth 2.0のアクセス トークンを取得
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` }
パラメーターとして「headers」にOAuth2.0認証用のアクセストークンを渡しています。
「Bearer(ベアラー)」とは認証方法の1つでBearer認証と呼ばれ、OAuth 2.0の仕様の一部として定義されています。
ScriptApp.getOAuthToken()
で、ScriptAppクラスのgetOAuthTokenメソッドを実行しOAuth2.0認証用のアクセストークンを取得しています。
(参考)getOAuthToken()
ここまでの処理でようやくダウンロードリンクを叩いて、ファイルにアクセスすることができます。
blobファイルとして取得する|getBlob
const blob = UrlFetchApp.fetch(url, {
headers: { authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
}).getBlob();
最後にダウンロードリンクを叩いて得られたファイルをgetblobメソッドを使ってBlobとして取得しています。
base64のダウンロードリンクの作成
data:
`data:${mimeTypes[type]};base64,` +
Utilities.base64Encode(blob.getBytes()),
base64へのエンコード
Utilities.base64Encode(blob.getBytes())
Blobオブジェクトに変換したファイルをUtilitiesクラスのbase64encodeメソッドを使ってbase64にエンコードします。
base64にエンコードする際はgetBytesメソッドを使ってBlobオブジェクトをバイトデータにエンコードする必要があります。
base64ダウンロードリンクの作成
data:${mimeTypes[type]};base64,` + Utilities.base64Encode(blob.getBytes()),
base64ダウンロードURLの作成は以下のような構造になります。
data:[<mediatype>][;base64],<data>
冒頭を「data:」としてMIMEタイプ、「;bae64」、カンマで区切ってbase64形式のデータを記述します。
MIMEタイプは今回はCSVファイルの場合はExcel「MICROSOFT_EXCEL」、PDFの場合は「PDF」を指定しています。
なお、ダウンロードURLのdata:はデータURLと呼ばれ、小さなファイルをインラインで埋め込むためのスキームです。
(参考)Mmdn: データURL
以上でbase64形式のダウンロードURLの作成が完了です。
ファイル名の指定
createDataUrl関数の最後の処理としてファイル名を指定します。
filename: `${sheet.getSheetName()}.${type}`
やっていることはとても簡単です。sheet.getSheetName()
で現在のシートの名前を取得しています。
そこに、引数で渡された値を拡張子としてつけています。
ボタンクリックでファイルをダウンロードする処理
AppScriptを使って、ファイルダウンロード用のURLとファイル名の生成ができたので、最後にボタンクリックでファイルをダウンロードする処理を記述します。
これが、index.htmlの中のwithSuccessHandler
メソッドで指定した処理になります。
google.script.run
.withSuccessHandler(({ data, filename }) => {
if (data && filename) {
const a = document.createElement("a");
document.body.appendChild(a);
a.download = filename;
a.href = data;
a.click();
}
})
document.createElement
document.createElementはタグを生成するJavaScriptのメソッドです。
document.createElement(タグ名[, オプション]);
第1引数でタグ名を文字列で指定することで、指定したタグを生成します。なお、ここで生成されたものをエレメントと呼びます。
document.createElement("a");
↓ aタグを生成します。
<a></a>
(参考)Mmdn: Document.createElement()
appendChild
親ノード.appendChild(エレメント)
appendChildは指定した親ノードの中に、指定したエレメントを挿入するメソッドです。
以下のようにすることで、bodyタグの中に先ほど作成したエレメント(aタグ)を挿入することができます。
document.body.appendChild(a)
↓
<body>
<a></a>
</body>
(参考)
エレメント.属性名=値
エレメント.属性名=値
エレメントに対して「.属性名=値」とすると、指定した属性と値を追加することができます。
aタグのhref属性
aタグにhref属性を付与すると、指定したURLがリンク先となります。
const a = document.createElement("a");
document.body.appendChild(a);
a.href = data;
↓
<body>
<a href="data:MIMEtype;base64,dabafgrag~"></a>
</body>
aタグのdownload属性
aタグにdownload属性を付与すると、hrefで指定したダウンロードURLをクリックしたときに、download属性の値がファイル名となります。
以下の場合aタグのエレメントにdownload属性を付与し、値は変数filenameになります。
a.download = filename;
↓
<body>
<a download="シート名.csv" href="data:MIMEtype;base64,dabafgrag~"></a>
</body>
これでダウンロード用のaタグが完成します。
clickメソッド
最後に、clickメソッドを実行して、aタグをクリックしています。
a.click();
これで、指定したダウンロードURLをクリックして、ファイルを指定したファイル名でダウンロードすることができます。
(参考)Mmdn: click()
以上で完成です。
お疲れさまでした^^