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

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

ただいまの
回答率

90.12%

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 10
  • VIEW 19K+

tetu

score 42

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

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

何か良い方法がありましたらご教示いただければ幸いです。
宜しくお願いいたします。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+3

こんばんは。

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

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

以下コードで、targetFolderIdsへ5つのフォルダのID、mailtoへ送り先メールアドレスを記述して頂ければ、動作確認を頂けます。
# フォルダは名前で取得する事もできますが、例えば違う階層で同じ名前のフォルダが存在するなどあると、意図しないフォルダも拾ってしまう可能性があるためIDを使って確実にする方が良いかと思いました。
フォルダ名がユニークである事が担保できるならgetFolderByName()を使っても良いと思います。
function sendMail_Excel() {
  // フォルダ、ファイル関係
  var targetFolderIds = ["folder1", "folder2", "folder3", "folder4", "folder5"];
  var targetFolder;
  var folderName;
  var objFiles;
  var objFile;
  var fileName;
  
  // スプレッドシート関係
  var ss;
  var key;
  var sheets;
  var sheetId;
  
  // メール関係
  var mailto = "@gmail.com";
  var subject = "";
  var body = "";
  
  // その他
  var nowDate = Utilities.formatDate(new Date(), 'JST', 'yyyyMMdd');
  var fetchUrl;
  var fetchOpt = {
    "headers" : { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
    "muteHttpExceptions" : true
  };
  var xlsxName;
  var attachmentFiles = new Array();
  
  
  for (var i = 0; i < targetFolderIds.length; i++) {
    // Idから対象フォルダの取得
    targetFolder = DriveApp.getFolderById(targetFolderIds[i]);
    folderName = targetFolder.getName();
    body = body + folderName + "\n";
    
    // 対象フォルダ以下のSpreadsheetを取得
    objFiles = targetFolder.getFilesByType(MimeType.GOOGLE_SHEETS);
    
    while (objFiles.hasNext()) {
      objFile = objFiles.next();
      fileName = objFile.getName();
      body = body + " - " + fileName + "\n";
      
      // Spreadsheetのオープン
      ss = SpreadsheetApp.openByUrl(objFile.getUrl());
      key = ss.getId();
      sheets = ss.getSheets();
      
      // 各シートの処理
      for (var sheetNum = 0; sheetNum < sheets.length; sheetNum++){
        sheetId = sheets[sheetNum].getSheetId();
        xlsxName = fileName + "_" + sheets[sheetNum].getName() + "_" + nowDate + ".xlsx";
        body = body + "    [" + xlsxName + "]\n";
        
        // Excelファイルにして添付ファイルへ追加
        fetchUrl = "https://docs.google.com/spreadsheets/d/" + key + "/export?gid=" + sheetId + "&amp;format=xlsx&amp;sheetnames=true";
        attachmentFiles.push(UrlFetchApp.fetch(fetchUrl,fetchOpt).getBlob().setName(xlsxName));
      }
    }
  }
  
  // メール送信
  subject = "[GoogleDrive]定期バックアップ(" + Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd') + ")";
  MailApp.sendEmail(mailto, subject, body, {attachments:attachmentFiles});
}

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



追記 2015/09/24 18:27頃
編集 2015/09/26 20:48頃

Spreadsheet単位(Excelで言うワークブック単位)でxlsxファイルを作成し、メール添付出来るようにしたコードを追記させてもらいます。
ルールは前と同じで、「フォルダID」と「送信先メールアドレス」を指定して頂ければ動作確認する事ができると思います。
function sendMail_Excel2() {
  // フォルダ、ファイル関係
  var targetFolderIds = ["folder1", "folder2", "folder3", "folder4", "folder5"];
  var targetFolder;
  var folderName;
  var objFiles;
  var objFile;
  var fileName;
  var key;
  
  // メール関係
  var mailto = "@gmail.com";
  var subject = "[GoogleDrive]定期バックアップ(" + Utilities.formatDate(new Date(), 'JST', 'yyyy/MM/dd') + ")";
  var body = "";
  
  // その他
  var nowDate = Utilities.formatDate(new Date(), 'JST', 'yyyyMMdd');
  var fetchUrl;
  var fetchOpt = {
    "headers" : { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
    "muteHttpExceptions" : true
  };

  var xlsxName;
  var attachmentFiles = new Array();
  
  try
  {
    for (var i = 0; i < targetFolderIds.length; i++) {
      // Idから対象フォルダを取得
      targetFolder = DriveApp.getFolderById(targetFolderIds[i]);
      folderName = targetFolder.getName();
      body = body + folderName + "\n";
    
      // 対象フォルダ以下のSpreadsheetを取得
      objFiles = targetFolder.getFilesByType(MimeType.GOOGLE_SHEETS);
    
      while (objFiles.hasNext()) {
        objFile = objFiles.next();
        key = objFile.getId();
        fileName = objFile.getName();
        body = body + " - " + fileName + "\n";
      
        xlsxName = fileName + "_" + nowDate + ".xlsx";
        fetchUrl = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + key + "&amp;exportFormat=xlsx";
        attachmentFiles.push(UrlFetchApp.fetch(fetchUrl, fetchOpt).getBlob().setName(xlsxName));
      }
    }
  }
  catch(e){
    subject = "ERROR:" + subject;
    body = "エラー : " + e.message;
  }
  
  // メール送信
  MailApp.sendEmail(mailto, subject, body, {attachments:attachmentFiles});
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/12/17 16:57

    sgr-2様

    コード例をわざわざ提示いただき、本当にありがとうございます m(_ _)m

    上記のコードにfetchUrlを組み合わせ、メールに添付させることをここ数日トライしてみたのですが、うまくいきません…

    私が根本的なjavascriptの知識がないまま質問しているせいですね…m(_ _)m 反省です。

    大変図々しいお願いをして恐縮なのですが、上記のコードにfetchUrlを組み込み、メールに添付するやり方をご教示いただければ…と思います。m(_ _)m


    何卒よろしくお願いします。

    キャンセル

  • 2015/12/17 21: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;
    }

    キャンセル

  • 2015/12/22 15:39

    sgr-2様

    本当に、本当にありがとうございます m(_ _)m

    思った通りの動作ができました!! 心から感謝申し上げます m(_ _)m
    もう、感激です…

    これをいい機会に、Javascript と GAS をしっかり勉強したいと思います。

    重ねて御礼申し上げます。ありがとうございました!!

    キャンセル

+1

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/18 15:52

    stshisho様

    ご回答いただきありがとうございました。

    印象的に実現が厳しそうですが、Contentクラスあたりのキーワードで色々とググってみます。情報感謝です。

    キャンセル

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

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる