【问题标题】:Export Google Spreadsheet to .XLSX every time an edit is made每次进行编辑时将 Google 电子表格导出到 .XLSX
【发布时间】:2013-10-16 08:44:17
【问题描述】:

我想要一个 Google 脚本,它可以在进行编辑时自动将电子表格导出到 .XLSX,从而覆盖任何以前的版本。使用this answer作为模板,我创建了如下代码:

function onEdit() {
  var s = SpreadsheetApp.getActiveSheet();
  var r = s.getActiveCell();
  if( r.getColumn() != 1 ) { //checks the column
    var row = r.getRow();
    var time = new Date();
    time = Utilities.formatDate(time, "GMT-08:00 ", "MM/dd/yy, hh:mm:ss");
    SpreadsheetApp.getActiveSheet().getRange('A' + row.toString()).setValue(time); 

    var id = 'MY_SPREADSHEET_KEY'
    var url = 'https://docs.google.com/feeds/';
    var doc = UrlFetchApp.fetch(url+'download/spreadsheets/Export?key='+id+'&exportFormat=xls',
                                googleOAuth_('docs',url)).getBlob()
    DocsList.createFile(doc).rename('newfile.xls')
  };
 };

function googleOAuth_(name,scope) {
  var oAuthConfig = UrlFetchApp.addOAuthService(name);
  oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
  oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
  oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
  oAuthConfig.setConsumerKey('anonymous');
  oAuthConfig.setConsumerSecret('anonymous');
  return {oAuthServiceName:name, oAuthUseToken:"always"};
}

但是,它似乎没有导出。或者,如果它正在导出,我不确定这是在哪里发生的。

有什么想法吗?

【问题讨论】:

  • 标题和第一段写的是 XLSX,但代码使用的是 XLS。由于接受的答案代码导出到 XLS 看起来应该编辑问题。另一方面,DocList 和 oAuthConfig 已被弃用。见Apps Script Sunset Schedule

标签: google-apps-script google-sheets export-to-excel


【解决方案1】:

由于 Google API 的更改,Serge 的某些脚本不再可用,我发布了我的脚本,它基本上将当前电子表格导出到 xlsx(请注意不支持导出到 xls)并将其保存到名为Exports 的文件夹中。在执行此操作之前,它会删除之前的 xlsx 文件并仅保留最新的文件,这样您就无需计算时间或更改任何单元格:

function exportAsxlsx() {
  var spreadsheet   = SpreadsheetApp.getActiveSpreadsheet();
  var spreadsheetId = spreadsheet.getId()
  var file          = Drive.Files.get(spreadsheetId);
  var url           = file.exportLinks[MimeType.MICROSOFT_EXCEL];
  var token         = ScriptApp.getOAuthToken();
  var response      = UrlFetchApp.fetch(url, {
    headers: {
      'Authorization': 'Bearer ' +  token
    }
  });

  var blobs   = response.getBlob();
  var folder = DriveApp.getFoldersByName('Exports');
  if(folder.hasNext()) {
    var existingPlan1 = DriveApp.getFilesByName('newfile.xlsx');
    if(existingPlan1.hasNext()){
      var existingPlan2 = existingPlan1.next();
      var existingPlanID = existingPlan2.getId();
      Drive.Files.remove(existingPlanID);
    }
  } else {
    folder = DriveApp.createFolder('Exports');
  }
  folder = DriveApp.getFoldersByName('Exports').next();
  folder.createFile(blobs).setName('newfile.xlsx')
}

如果没有,它还会创建特定文件夹。您可以使用这些命令并查看这些类是如何工作的。请注意,您需要通过将 Resources -> Advanced Google Services -> Drive API 切换为 on 和 Google Developers Console 来启用 D​​rive API(请参阅详细说明 here)。我还设置了一个简单的触发器,在每次编辑时调用这个函数。这可以通过:Resources -> Current project's triggers -> Add a new trigger 来完成。您不需要添加任何库。

【讨论】:

    【解决方案2】:

    确实不是!可能是因为oAuth功能没有得到正确的授权,还有because the simple onEdit is not allowed做这种操作。

    您必须创建一个可安装触发器 (menu>ressource>current trigger>create)。

    试试下面这个脚本并运行authorize函数。

    我还更改了一些细节:timeZone 直接取自电子表格,id 也取自活动电子表格。

    还要注意,新创建的 XLSX 不会覆盖任何以前的文件,你会得到许多同名的文件!如果您只想保留最新版本,那么您应该自己处理,获取所有文档名称“新文件”并在创建新文件之前使用 file.setTrashed(true) 删除它们。

    这就像这两行代码一样简单:

    var oldVersions = DocsList.find('newfile.xls');
    for(var d in oldVersions){oldVersions[d].setTrashed(true)};
    

    代码:

    function myOnEdit() {
      var ss = SpreadsheetApp.getActiveSpreadsheet();
      var s = ss.getActiveSheet();
      var r = s.getActiveCell();
      if( r.getColumn() != 1 ) { //checks the column
        var row = r.getRow();
        var time = new Date();
        time = Utilities.formatDate(time, ss.getSpreadsheetTimeZone(), "MM/dd/yy, hh:mm:ss");
        var id = ss.getId();
        s.getRange('A' + row.toString()).setValue(time); 
        var url = 'https://docs.google.com/feeds/';
        var doc = UrlFetchApp.fetch(url+'download/spreadsheets/Export?key='+id+'&exportFormat=xls',
                                    googleOAuth_('docs',url)).getBlob()
        DocsList.createFile(doc).rename('newfile.xls')  
      }
    }
    
    function authorise(){
      // function to call to authorize googleOauth
      var id=SpreadsheetApp.getActiveSpreadsheet().getId();
      var url = 'https://docs.google.com/feeds/';
      var doc = UrlFetchApp.fetch(url+'download/spreadsheets/Export?key='+id+'&exportFormat=xls',
                                googleOAuth_('docs',url)).getBlob()
    }
    function googleOAuth_(name,scope) {
      var oAuthConfig = UrlFetchApp.addOAuthService(name);
      oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
      oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
      oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
      oAuthConfig.setConsumerKey('anonymous');
      oAuthConfig.setConsumerSecret('anonymous');
      return {oAuthServiceName:name, oAuthUseToken:"always"};
    }
    

    编辑:在您发表评论之后,这是一个仅每 30 秒保存一次的版本(如果没有进行编辑,则保存更多)。如有必要,您可以轻松地将时间值更改为另一个间隔。

    重新运行授权函数初始化scriptProperty。

    function myOnEdit() {
      var ss = SpreadsheetApp.getActiveSpreadsheet();
      var s = ss.getActiveSheet();
      var r = s.getActiveCell();
      if( r.getColumn() != 1 ) { //checks the column
        var row = r.getRow();
        var time = new Date();
        time = Utilities.formatDate(time, ss.getSpreadsheetTimeZone(), "MM/dd/yy, hh:mm:ss");
        var id = ss.getId();
        s.getRange('A' + row.toString()).setValue(time); 
        var lastSaveTime = new Date(Utilities.jsonParse(ScriptProperties.getProperty('exportTime')));
        var now = new Date().getTime();
        Logger.log(now - lastSaveTime.getTime())
        if (now - lastSaveTime.getTime() > 60000){ // delete every minute
          var oldVersions = DocsList.find('newfile.xls');
          for(var d in oldVersions){oldVersions[d].setTrashed(true)};
        }
        if (now - lastSaveTime.getTime() > 30000){ // save every 30"
          var url = 'https://docs.google.com/feeds/';
          var doc = UrlFetchApp.fetch(url+'download/spreadsheets/Export?key='+id+'&exportFormat=xls',
                                      googleOAuth_('docs',url)).getBlob()
          DocsList.createFile(doc).rename('newfile.xls')  
          ScriptProperties.setProperty('exportTime',Utilities.jsonStringify(new Date()));
        }
      }
    }
    
    function authorise(){
      // function to call to authorize googleOauth + initialize the TIMER
      ScriptProperties.setProperty('exportTime',Utilities.jsonStringify(new Date()));
      var id = SpreadsheetApp.getActiveSpreadsheet().getId();
      var url = 'https://docs.google.com/feeds/';
      var doc = UrlFetchApp.fetch(url+'download/spreadsheets/Export?key='+id+'&exportFormat=xls',
                                    googleOAuth_('docs',url)).getBlob()
    }
    
    function googleOAuth_(name,scope) {
      var oAuthConfig = UrlFetchApp.addOAuthService(name);
      oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
      oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
      oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
      oAuthConfig.setConsumerKey('anonymous');
      oAuthConfig.setConsumerSecret('anonymous');
      return {oAuthServiceName:name, oAuthUseToken:"always"};
    }
    

    【讨论】:

    • 你是某种 Google-App-Script 之神。非常感谢你。每次保存时似乎脚本运行速度很慢,所以我想我会修改它,使其每 30 秒自动保存一个 Excel 工作表,并将“列修改”功能放在单独的 OnEdit 脚本中。
    • 所以,我删除了 onEachEdit 函数的“列修改”部分,并让“保存到 .XLS”功能运行触发器,而不是每分钟运行一次。现在,当我运行授权时,我收到以下错误:Request failed for returned code 404. Truncated server response:<!DOCTYPE html><html lang="en" ><head><meta name="description" content="Web word processing, presentations and spreadsheets"><link rel="shortcut ic... (use muteHttpExceptions option to examine full response) (line 13, file "everyMinute") 有什么想法吗?
    • :-) 谢谢 :-) 这可能是个好主意,您可以在脚本中添加第二个条件,以便仅在自上次导出后 30 分钟后才保存。例如,使用 ScriptProperties 保存时间值。也请考虑接受答案。
    • 关于错误,授权码确实有错误...格式设置为html而不是xls...抱歉,两个版本都更新了
    • 效果很好。我也在尝试将您的“删除额外副本”功能添加到分钟计时器中,因此我设置了一个触发器以每分钟运行该功能。但它似乎没有工作。还有没有办法让它删除除了最新的excel文档之外的所有文件?
    猜你喜欢
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多