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

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

新規登録して質問してみよう
ただいま回答率
85.37%
Google API

Googleは多種多様なAPIを提供していて、その多くはウェブ開発者向けのAPIです。それらのAPIは消費者に人気なGoogleのサービス(Google Maps, Google Earth, AdSense, Adwords, Google Apps,YouTube等)に基づいています。

Google Apps Script

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

Q&A

解決済

2回答

38799閲覧

【GAS】複数スプレッドシートをエクセルに変換し定期的に自動ダウンロード

tetu

総合スコア44

Google API

Googleは多種多様なAPIを提供していて、その多くはウェブ開発者向けのAPIです。それらのAPIは消費者に人気なGoogleのサービス(Google Maps, Google Earth, AdSense, Adwords, Google Apps,YouTube等)に基づいています。

Google Apps Script

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

1グッド

11クリップ

投稿2015/09/16 07:53

編集2015/09/16 07:54

【やりたいこと】
Google Driveに複数あるスプレッドシートを、**”定期的かつ自動で”**エクセルに変換してPCに保管(バックアップ)したい。

【詳細】
Google Drive上に5つフォルダがあり、各フォルダ内には複数のスプレッドシートがあります。この複数あるスプレッドシートを月に1回、エクセルに変換したうえでPCにダウンロードして保管(バックアップ)したいと考えております。本件、手動で行えばできることは承知していますが、GASで(自動で)実現できないものか思案しております。

何か良い方法がありましたらご教示いただければ幸いです。
宜しくお願いいたします。

FdaNpo👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんばんは。

時間が経ってしまっていますが、GASで目的の機能を調べてある程度の形になりましたので投稿させて頂きます。

「ダウンロードして保管」の部分は、ローカルPCに転送と考えると難しいように思えましたので、メール添付を代替案として実装しています。

以下コードで、targetFolderIdsへ5つのフォルダのID、mailtoへ送り先メールアドレスを記述して頂ければ、動作確認を頂けます。

フォルダは名前で取得する事もできますが、例えば違う階層で同じ名前のフォルダが存在するなどあると、意図しないフォルダも拾ってしまう可能性があるためIDを使って確実にする方が良いかと思いました。

フォルダ名がユニークである事が担保できるなら**getFolderByName()**を使っても良いと思います。

Google

1function sendMail_Excel() { 2 // フォルダ、ファイル関係 3 var targetFolderIds = ["folder1", "folder2", "folder3", "folder4", "folder5"]; 4 var targetFolder; 5 var folderName; 6 var objFiles; 7 var objFile; 8 var fileName; 9 10 // スプレッドシート関係 11 var ss; 12 var key; 13 var sheets; 14 var sheetId; 15 16 // メール関係 17 var mailto = "@gmail.com"; 18 var subject = ""; 19 var body = ""; 20 21 // その他 22 var nowDate = Utilities.formatDate(new Date(), 'JST', 'yyyyMMdd'); 23 var fetchUrl; 24 var fetchOpt = { 25 "headers" : { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() }, 26 "muteHttpExceptions" : true 27 }; 28 var xlsxName; 29 var attachmentFiles = new Array(); 30 31 32 for (var i = 0; i < targetFolderIds.length; i++) { 33 // Idから対象フォルダの取得 34 targetFolder = DriveApp.getFolderById(targetFolderIds[i]); 35 folderName = targetFolder.getName(); 36 body = body + folderName + "\n"; 37 38 // 対象フォルダ以下のSpreadsheetを取得 39 objFiles = targetFolder.getFilesByType(MimeType.GOOGLE_SHEETS); 40 41 while (objFiles.hasNext()) { 42 objFile = objFiles.next(); 43 fileName = objFile.getName(); 44 body = body + " - " + fileName + "\n"; 45 46 // Spreadsheetのオープン 47 ss = SpreadsheetApp.openByUrl(objFile.getUrl()); 48 key = ss.getId(); 49 sheets = ss.getSheets(); 50 51 // 各シートの処理 52 for (var sheetNum = 0; sheetNum < sheets.length; sheetNum++){ 53 sheetId = sheets[sheetNum].getSheetId(); 54 xlsxName = fileName + "_" + sheets[sheetNum].getName() + "_" + nowDate + ".xlsx"; 55 body = body + " [" + xlsxName + "]\n"; 56 57 // Excelファイルにして添付ファイルへ追加 58 fetchUrl = "https://docs.google.com/spreadsheets/d/" + key + "/export?gid=" + sheetId + "&amp;format=xlsx&amp;sheetnames=true"; 59 attachmentFiles.push(UrlFetchApp.fetch(fetchUrl,fetchOpt).getBlob().setName(xlsxName)); 60 } 61 } 62 } 63 64 // メール送信 65 subject = "[GoogleDrive]定期バックアップ(" + Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd') + ")"; 66 MailApp.sendEmail(mailto, subject, body, {attachments:attachmentFiles}); 67}

また、「定期的かつ自動で」もトリガー設定で実現可能と思います。
ドライブへのアクセスやメール送信など、承認が必要な機能がありますので、それらは一度手動で実行して許可してしまえば問題ないと思います。(月トリガーで日と時間帯を指定)


追記 2015/09/24 18:27頃

編集 2015/09/26 20:48頃

Spreadsheet単位(Excelで言うワークブック単位)でxlsxファイルを作成し、メール添付出来るようにしたコードを追記させてもらいます。
ルールは前と同じで、「フォルダID」と「送信先メールアドレス」を指定して頂ければ動作確認する事ができると思います。

Google

1function sendMail_Excel2() { 2 // フォルダ、ファイル関係 3 var targetFolderIds = ["folder1", "folder2", "folder3", "folder4", "folder5"]; 4 var targetFolder; 5 var folderName; 6 var objFiles; 7 var objFile; 8 var fileName; 9 var key; 10 11 // メール関係 12 var mailto = "@gmail.com"; 13 var subject = "[GoogleDrive]定期バックアップ(" + Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd') + ")"; 14 var body = ""; 15 16 // その他 17 var nowDate = Utilities.formatDate(new Date(), 'JST', 'yyyyMMdd'); 18 var fetchUrl; 19 var fetchOpt = { 20 "headers" : { Authorization: "Bearer " + ScriptApp.getOAuthToken() }, 21 "muteHttpExceptions" : true 22 }; 23 24 var xlsxName; 25 var attachmentFiles = new Array(); 26 27 try 28 { 29 for (var i = 0; i < targetFolderIds.length; i++) { 30 // Idから対象フォルダを取得 31 targetFolder = DriveApp.getFolderById(targetFolderIds[i]); 32 folderName = targetFolder.getName(); 33 body = body + folderName + "\n"; 34 35 // 対象フォルダ以下のSpreadsheetを取得 36 objFiles = targetFolder.getFilesByType(MimeType.GOOGLE_SHEETS); 37 38 while (objFiles.hasNext()) { 39 objFile = objFiles.next(); 40 key = objFile.getId(); 41 fileName = objFile.getName(); 42 body = body + " - " + fileName + "\n"; 43 44 xlsxName = fileName + "_" + nowDate + ".xlsx"; 45 fetchUrl = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + key + "&amp;exportFormat=xlsx"; 46 attachmentFiles.push(UrlFetchApp.fetch(fetchUrl, fetchOpt).getBlob().setName(xlsxName)); 47 } 48 } 49 } 50 catch(e){ 51 subject = "ERROR:" + subject; 52 body = "エラー : " + e.message; 53 } 54 55 // メール送信 56 MailApp.sendEmail(mailto, subject, body, {attachments:attachmentFiles}); 57}

投稿2015/09/20 11:14

編集2015/09/26 11:49
sgr-2

総合スコア294

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

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

tetu

2015/09/24 03:00

sgr-2様 ご回答いただきありがとうございました。 早速試させていただき、エクセルファイルが添付されたメールが届きました! トリガーの設定も定期的にできそうです。感謝いたします!! しかし、大変図々しいのですが(汗)、重ねて質問をさせてください。 ご提示いただいたスクリプトですと、スプレッドシート内に複数シートがある場合、エクセルファイルが複数作成されます。 できることならば、”1つのファイル(スプレッドシート)に対して1つファイル(エクセル)を作成”という形が理想的です。可能でしょうか? 図々しい質問で恐縮ですが、宜しくお願いいたします。
sgr-2

2015/09/24 09:30

こんばんは。 試してみたところ、”1つのファイル(スプレッドシート)に対して1つファイル(エクセル)を作成”が実現できましたので、回答本文の方へ追記をしました。 確認用データ等で動作を見て頂ければと思います。
sgr-2

2015/09/24 11:56

すいません。 Googleドライブ上で、エクスポートしたSpreadsheetファイルは存在しているのですが 見えなくなる現象が起こる事がありました。 もう少し確認してみます。
tetu

2015/09/25 00:10

sgr-2様 ありがとうございますm(_ _)m 宜しくお願いいたします。
sgr-2

2015/09/26 11:56

こんばんは。 だいぶ時間を頂いてしまいました。 結論ですが、私がテストしていたGoogleドライブ(アカウント)に問題があったようです。 そのアカウントで方法を変えながらいろいろ試していたのですがファイルが見えなくなる現象を回避する事ができずでした。 別のアカウントでこれを実行したところ、手動とトリガーによる実行を10回以上行ってみましたが同現象を再現できませんでした。。 アカウント固有の問題だった可能性が高いと思えます。 回答本文中、後方のコードでご確認を頂ければと思います。
tetu

2015/09/28 01:01

sgr-2様 ご丁寧にご対応をいただき大変感謝しております! こちらの環境でも問題なく実現できました。早速実務で利用させていただきます!! 今後とも宜しくお願いいたしますm(__)m
sgr-2

2015/09/28 03:32

お知らせ頂きありがとうございます。 問題なく実現できたとの事、良かったです。
FdaNpo

2015/12/09 07:41

sgr-2様 初めまして。検索でたどり着きました。 tetu様と同じような状況で四苦八苦してましたので、助かりました。 こちらの質問と回答を参考にさせていただきました。ありがとうございます。 失礼ながら重ねて質問させていただきますが、同様にGoogle Docs を wordファイルでバックアップ場合はどうしたらいいでしょうか? よろしくお願いいたします m(_ _)m
sgr-2

2015/12/10 02:15

FdaNpoさん こんにちは。 ドキュメントについて、スプレッドシートと同じような処理で良いですよね? ほぼほぼ同じになるので、差分で書きますが 分かりにくい等ありましたらお知らせください。 ----- // MSWordファイルのcontentType var content_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" // 対象フォルダに紐付くドキュメントを取得 objFiles = targetFolder.getFileByType(MimeType.GOOGLE_DOCS); docName = fileName + ".docx"; // fileNameは「objFile.getName()」の値 fetchUrl = "https://docs.google.com/document/u/0/d/" + objFile.getId() + "/export?format=docx"; attachmentFiles.push(UrlFetchApp.fetch(fetchUrl, fetchOpt).getBlob().setContentType(content_type).setName(docName)); -----
FdaNpo

2015/12/10 08:30 編集

sgr-2様 返信、大変ありがとうございます!! お陰様で一歩前進しました。 ですが試してみたら、何故か -------------- エラー : オブジェクト xxx で関数 getFileByType が見つかりません。 -------------- となってしまいます。 指定したフォルダには test.gdoc というGoogle ドキュメントは 確かにあります。。。。 こちらのテスト環境では、MimeType.GOOGLE_DOCS で該当ファイルは取得できないようです。 もし設定等の変更が必要であれば、ご教示頂きたく思います m(_ _)m
sgr-2

2015/12/10 08:08

FdaNpoさん すいません、タイプミスがありました。。 >objFiles = targetFolder.getFileByType(MimeType.GOOGLE_DOCS); こちらのメソッド「getFileByType」ですが、正しくは「getFilesByType」です。 正) objFiles = targetFolder.getFilesByType(MimeType.GOOGLE_DOCS);
FdaNpo

2015/12/10 08:34

sgr-2様 ありがとうございます!! 動作しました!! m(_ _)m 本当に助かりました。 また大変図々しいのですが、指定したフォルダの中の下層フォルダも再帰的に同時に処理できる方法がありましたら、こちらもご教示いただけますでしょうか? 図々しい質問を重ねて恐縮ですが、何卒宜しくお願いいたします。 m(_ _)m
sgr-2

2015/12/10 09:17

FdaNpoさん 例えばになりますが、フォルダの列挙であれば 以下のようなコードで実現できます。 ※CheckFolderを実行 ----- function EnumFolders(parentFolder){ var objFolders = parentFolder.getFolders(); var objFolder; while(objFolders.hasNext()){ objFolder = objFolders.next(); Logger.log(objFolder.getName()); EnumFolders(objFolder); } } function CheckFolder() { var rootFolder = DriveApp.getRootFolder(); // ルート(マイドライブ)を取得 EnumFolders(rootFolder); } ----- FdaNpoさんの利用されているGoogle Driveがどのような状況になっているか分かりませんので、具体的なところは言い難いのですが「フォルダ」(と呼んでいる物)の扱いは、場合によっては注意が必要です。 「フォルダ」ですが、感覚的には「タグ」に近いもので 例えばファイルは「複数のフォルダ」にまたがって存在する事ができます。 targetFolder.getFilesByType()などで、フォルダ内のファイルを取得した結果、他の走査対象のフォルダでも同ファイルを取得する事が起こりえます。そうすると、都度getId()でID(ユニークな値)を取得して重複が発生しないような配慮が必要になると思います。 # ネタのボリュームから見ても、新規の質問で投稿頂いた方が良かったかも知れませんね。 # 蓄積されていく情報(回答)と質問タイトルの紐付けにギャップが出てきてしまうので…
FdaNpo

2015/12/11 00:37

sgr-2様 重ねてお礼申し上げます m(_ _)m 早速試してみます!! ># ネタのボリュームから見ても、新規の質問で投稿頂いた方が良かったかも知れませんね。 ># 蓄積されていく情報(回答)と質問タイトルの紐付けにギャップが出てきてしまうので… 確かにご指摘通りでした。申し訳ございません。
sgr-2

2015/12/11 14:14

FdaNpoさん いえ、 上のコメントの内容で言えば、EnumFoldersにバックアップ対象になるドキュメントの親フォルダを渡して、attachmentFilesにdocxファイルを追加していってやれば良いと思います。 分からないや躓いた等あれば、質問やコメントを頂ければと思います。
FdaNpo

2015/12/14 07:26

sgr-2様 上記スクリプトの再帰的処理の、 var rootFolder = DriveApp.getRootFolder(); // ルート(マイドライブ)を取得 を var rootFolder = DriveApp.getFolderById("xxxx"); に設定しての動作の確認ができました。 ですが…カレントフォルダ、下層フォルダを参照しながら、各フォルダ内のスプレッドシートをエクセルに変換及びGoogle Docs をワードに変換するという風に組み合わせることが、どうしてもできません。 本当に何度も図々しいお願いをしてしまいますが、お教えいただいたサンプルコードの組み合わせ方をご教示いただけませんでしょうか? m(_ _)m よろしくお願いいたします。m(_ _)m
sgr-2

2015/12/14 09:11

FdaNpoさん こんばんは。 対象をドキュメントとスプレッドシート両方にしたいのだと思いますが、あまり深く考えなくても良くて、ドキュメントに対する処理とスプレッドシートの処理を並べて書いてしまえば良いと思います。 前にコメントで書かせてもらったEnumFoldersを採用するなら、以下のような形で確認ができると思います。 ----- function EnumFolders(parentFolder, attachmentFiles){ var objFolders = parentFolder.getFolders(); var objFolder; var objFiles; var objFile; var backupFileName; Logger.log("[" + parentFolder.getName() + "]"); // GOOGLE_DOCの処理 objFiles = parentFolder.getFilesByType(MimeType.GOOGLE_DOCS); while(objFiles.hasNext()){ objFile = objFiles.next(); backupFileName = objFile.getName() + ".docx"; attachmentFiles.push(backupFileName); } // GOOGLE_SHEETSの処理 objFiles = parentFolder.getFilesByType(MimeType.GOOGLE_SHEETS); while(objFiles.hasNext()){ objFile = objFiles.next(); backupFileName = objFile.getName() + ".xlsx"; attachmentFiles.push(backupFileName); } // 子フォルダの確認 while(objFolders.hasNext()){ objFolder = objFolders.next(); attachmentFiles = EnumFolders(objFolder, attachmentFiles); } return attachmentFiles; } function CheckFolder(){ var targetFolder = DriveApp.getFolderById("xxxx"); var attachmentFiles = new Array(); attachmentFiles = EnumFolders(targetFolder, attachmentFiles); // 以下は確認用(ログにattachmentFilesの文字列を列挙) for (var i = 0; i < attachmentFiles.length; i++){ Logger.log(attachmentFiles[i]); } } ----- 簡易的に書いているのでattachmentFilesにはファイル名(文字列)を入れていますが、実際は回答本文中のようにfetchUrlを作って、fetchして~の流れでattachmentFilesに追加していきます。
FdaNpo

2015/12/17 07:57

sgr-2様 コード例をわざわざ提示いただき、本当にありがとうございます m(_ _)m 上記のコードにfetchUrlを組み合わせ、メールに添付させることをここ数日トライしてみたのですが、うまくいきません… 私が根本的なjavascriptの知識がないまま質問しているせいですね…m(_ _)m 反省です。 大変図々しいお願いをして恐縮なのですが、上記のコードにfetchUrlを組み込み、メールに添付するやり方をご教示いただければ…と思います。m(_ _)m 何卒よろしくお願いします。
sgr-2

2015/12/17 12:09

FdaNpoさん 送信先メールアドレスや対象フォルダIDなど、動作させる際のルールは回答本文と同様ですので省略させてもらいますが、以下のような内容で目的を実現できると思います。 ----- function sendMail_Backup() { // フォルダ、ファイル関係 var targetFolderIDs = ["folder1", "folder2", "folder3"]; var targetFiles = {}; var attachmentFiles = new Array(); var objFolder; // メール関係 var mailto = "@gmail.com"; var subject = "[GoogleDrive]定期バックアップ(" + Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd') + ")"; var body = ""; try { // バックアップ対象のファイル情報を取得 for (var i = 0; i < targetFolderIDs.length; i++) { objFolder = DriveApp.getFolderById(targetFolderIDs[i]); targetFiles = getTargetFiles(objFolder, objFolder.getName(), targetFiles); } // バックアップ対象のファイル群を取得 attachmentFiles = getAttachmentFiles(targetFiles); // メール本文 for (var fileId in targetFiles){ body = body + "[" + targetFiles[fileId]["path"] + "]\n"; body = body + " file : " + targetFiles[fileId]["name"] + "(" + targetFiles[fileId]["type"] + ")\n\n"; } } catch(e){ subject = "ERROR:" + subject; body = "エラー : " + e.message; } // メール送信 MailApp.sendEmail(mailto, subject, body, {attachments:attachmentFiles}); } // 指定されたフォルダ配下のバックアップ対象ファイル情報を返す function getTargetFiles(parentFolder, path, targetFiles){ var objFolders = parentFolder.getFolders(); var objFolder; var objFiles; var objFile; var fileId; var fileName; // GOOGLE_DOCSの処理 objFiles = parentFolder.getFilesByType(MimeType.GOOGLE_DOCS); while(objFiles.hasNext()){ objFile = objFiles.next(); fileId = objFile.getId(); fileName = objFile.getName(); if (fileId in targetFiles != true){ targetFiles[fileId] = {path:path, type:"document", name:fileName}; } } // GOOGLE_SHEETSの処理 objFiles = parentFolder.getFilesByType(MimeType.GOOGLE_SHEETS); while(objFiles.hasNext()){ objFile = objFiles.next(); fileId = objFile.getId(); fileName = objFile.getName(); if (fileId in targetFiles != true){ targetFiles[fileId] = {path:path, type:"spreadsheet", name:fileName}; } } // 子フォルダの確認 while(objFolders.hasNext()){ objFolder = objFolders.next(); targetFiles = getTargetFiles(objFolder, path + "/" + objFolder.getName(), targetFiles); } return targetFiles; } // 添付するファイル群を返す function getAttachmentFiles(targetFiles){ var fetchUrl; var fetchOpt = { "headers" : { Authorization: "Bearer " + ScriptApp.getOAuthToken() }, "muteHttpExceptions" : true }; var content_MSWord = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; var attachmentFiles = new Array(); var targetFile; var backupName; for (var fileId in targetFiles){ targetFile = targetFiles[fileId]; if (targetFile["type"] == "document"){ // MSWord形式での保存名 backupName = "[" + targetFile["path"].replace(/\//g, "_") + "]" + targetFile["name"] + ".docx"; fetchUrl = "https://docs.google.com/document/u/0/d/" + fileId + "/export?format=docx"; attachmentFiles.push(UrlFetchApp.fetch(fetchUrl, fetchOpt).getBlob().setContentType(content_MSWord).setName(backupName)); } else if (targetFile["type"] == "spreadsheet"){ // MSExcel形式での保存名 backupName = "[" + targetFile["path"].replace(/\//g, "_") + "]" + targetFile["name"] + ".xlsx"; fetchUrl = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + fileId + "&amp;exportFormat=xlsx"; attachmentFiles.push(UrlFetchApp.fetch(fetchUrl, fetchOpt).getBlob().setName(backupName)); } } return attachmentFiles; }
FdaNpo

2015/12/22 06:39

sgr-2様 本当に、本当にありがとうございます m(_ _)m 思った通りの動作ができました!! 心から感謝申し上げます m(_ _)m もう、感激です… これをいい機会に、Javascript と GAS をしっかり勉強したいと思います。 重ねて御礼申し上げます。ありがとうございました!!
guest

0

tetuさんへ

ごくごく簡単で、解決には到らないと思いますが、情報だけは挙げておきますね。

この機能はスタンドアロンスクリプトとしてContentクラスのContentServiceクラス、TextOutputクラスを利用して構築、WEBアプリとして実現可能です。
https://developers.google.com/apps-script/reference/content/
https://developers.google.com/apps-script/guides/content

WEBアプリとしてはスプレッドシートからCSVダウンロード、というものを構築したことがありますが、
トリガーでの実行はいくつかの制限がありますので、実現の可否としては「?」です。
(認証が必要なサービスや外部ファイルへのアクセス制限に引っかかる可能性があるためダメかと思います。)

以上です。

投稿2015/09/17 09:26

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

tetu

2015/09/18 06:52

stshisho様 ご回答いただきありがとうございました。 印象的に実現が厳しそうですが、Contentクラスあたりのキーワードで色々とググってみます。情報感謝です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問