【问题标题】:Is there a way to print multiple tabs of a spreadsheet (but not all of them) as a single pdf?有没有办法将电子表格的多个选项卡(但不是全部)打印为单个 pdf?
【发布时间】:2020-02-05 03:45:32
【问题描述】:

我进行了一些研究,但还没有找到任何方法来做到这一点。尝试按照 Andrew Roberts 的解释在这里 http://www.andrewroberts.net/2017/03/apps-script-create-pdf-multi-sheet-google-sheet/ 将电子表格(或特定选项卡)转换为 pdf:

    function convertSpreadsheetToPdf(email, spreadsheetId, sheetName, pdfName) {

     var spreadsheet = spreadsheetId ? SpreadsheetApp.openById(spreadsheetId) : 
     SpreadsheetApp.getActiveSpreadsheet();
     spreadsheetId = spreadsheetId ? spreadsheetId : spreadsheet.getId()  
     var sheetId = sheetName ? spreadsheet.getSheetByName(sheetName).getSheetId() : null;  
     var pdfName = pdfName ? pdfName : spreadsheet.getName();
     var parents = DriveApp.getFileById(spreadsheetId).getParents();
     var folder = parents.hasNext() ? parents.next() : DriveApp.getRootFolder();
     var url_base = spreadsheet.getUrl().replace(/edit$/,'');

     var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf

      // Print either the entire Spreadsheet or the specified sheet if optSheetId is provided
      + (sheetId ? ('&gid=' + sheetId) : ('&id=' + spreadsheetId)) 
      // following parameters are optional...
      + '&size=A4'      // paper size
      + '&portrait=false'    // orientation, false for landscape
      + '&fitw=true'        // fit to width, false for actual size
      + '&sheetnames=false&printtitle=false&pagenumbers=false'  //hide optional headers and footers
      + '&gridlines=false'  // hide gridlines
      + '&fzr=false';       // do not repeat row headers (frozen rows) on each page

  var options = {
    headers: {
      'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken(),
    }
  }

  var response = UrlFetchApp.fetch(url_base + url_ext, options);
  var blob = response.getBlob().setName(pdfName + '.pdf');
  folder.createFile(blob);

  if (email) {

    var mailOptions = {
      attachments:blob
    }

    MailApp.sendEmail(
      email, 
      "Here is a file named " + pdfName, 
      "Please let me know if you have any questions or comments.", 
      mailOptions);
  }

查看 cmets,他建议添加以下代码,我将其放入另一个函数中:

  function printtwopdfs() {

  var sheetNames = ["Table1,"Table2"]

  sheetNames.forEach(function(sheetName) {
  convertSpreadsheetToPdf(TEST_EMAIL, "xxxxxx", sheetName, 
  "pdfteste")
  })}

但我得到的是 每张 单独打印为一个 pdf 的工作表。

隐藏除我想要的选项卡之外的所有选项卡并打印整个电子表格对我来说不是一个选项,因为它有太多选项卡(大约 15 个)。除此之外,我不太可能将选定的工作表复制到新的电子表格中,因为该功能需要很长时间才能运行,除非我能很快地做到这一点。关于如何进行的任何想法?

【问题讨论】:

  • 我能问一下你的目标吗? 1.关于Hidding all tabs except the ones I want and printing the spreadsheet as a whole isn't an option for me, since it has too many tabs (about 15).,标签页多的时候,你有什么问题? 2.关于take too long to run,请问这个处理时间? 3. 可以问一下你想要脚本的处理时间吗?
  • @Tanaike 我在一家资产管理公司工作,由于某些内部原因,我们正在从 excel 迁移到 Google 表格,并且必须从我的电子表格中打印许多投资者报告,但并非此电子表格的所有选项卡都需要要打印。 1. 隐藏所有选项卡然后打印电子表格可能不合适,因为我仍然需要使用相同的功能通过电子邮件发送报告(PDF 格式)。据我所知,我必须实现一个循环结构,并且由于它有太多选项卡,所以运行时间太长;
  • 2.遍历所有选项卡的循环大约需要 1 分钟以上; 3. 我想在 20 秒或更短的时间内运行这样的功能,有没有可能?
  • 感谢您的回复。根据您的问题和回复,我提出了一个修改后的脚本作为答案。你能确认一下吗?如果我误解了您的问题并且这不是您想要的方向,我深表歉意。

标签: google-apps-script pdf-generation


【解决方案1】:
  • 您希望通过从 Google 电子表格中选择工作表来创建 PDF 文件。
    • Google 电子表格有 15 张。
    • 例如,您要选择 2 张“Table1”和“Table2”,并希望将它们创建为一个 PDF 文件。然后,PDF 文件将作为电子邮件发送。
  • 您想降低实现上述目标的过程成本。
    • 您希望在 20 秒内完成运行脚本。
  • 您希望使用 Google Apps 脚本实现此目的。

从您的问题和回复中,我可以理解如上。如果我的理解是正确的,这个答案怎么样?请认为这只是几个可能的答案之一。

在这种情况下,我认为隐藏您想要使用的工作表以外的工作表可能是合适的。为此,在这里,我想建议使用 Sheets API 中的电子表格.batchUpdate 方法隐藏工作表。因为我认为在这种情况下,Sheets API 的处理成本可以低于电子表格服务。

流程:

修改后的脚本流程如下。

  1. 隐藏要创建为 PDF 文件的工作表以外的工作表。
  2. 从电子表格创建 PDF 文件。
  3. 显示所有工作表。

修改脚本:

在运行脚本之前,please enable Sheets API at Advanced Google services。请设置sheetNamesemailspreadsheetId的变量。并运行printtwopdfs()的函数。

function convertSpreadsheetToPdf(email, spreadsheetId, pdfName) {
  var spreadsheet = spreadsheetId ? SpreadsheetApp.openById(spreadsheetId) : SpreadsheetApp.getActiveSpreadsheet();
  var spreadsheetId = spreadsheetId ? spreadsheetId : spreadsheet.getId();
  var pdfName = pdfName ? pdfName : spreadsheet.getName();
  var parents = DriveApp.getFileById(spreadsheetId).getParents();
  var folder = parents.hasNext() ? parents.next() : DriveApp.getRootFolder();
  var url_base = spreadsheet.getUrl().replace(/edit$/,'');
  var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf
  + '&id=' + spreadsheetId
  + '&size=A4'      // paper size
  + '&portrait=false'    // orientation, false for landscape
  + '&fitw=true'        // fit to width, false for actual size
  + '&sheetnames=false&printtitle=false&pagenumbers=false'  //hide optional headers and footers
  + '&gridlines=false'  // hide gridlines
  + '&fzr=false';       // do not repeat row headers (frozen rows) on each page
  var options = {headers: {'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken()}}
  var response = UrlFetchApp.fetch(url_base + url_ext, options);
  var blob = response.getBlob().setName(pdfName + '.pdf');
  folder.createFile(blob);
  if (email) {
    var mailOptions = {attachments:blob}
    MailApp.sendEmail(email, "Here is a file named " + pdfName, "Please let me know if you have any questions or comments.", mailOptions);
  }
}

// Please run this function.
function printtwopdfs() {
  var sheetNames = ["Table1", "Table2"];
  var email = "###";  // Please set email address.
  var spreadsheetId = "###";  // Please set Spreadsheet ID.

  // Hide sheets.
  var allSheets = SpreadsheetApp.openById(spreadsheetId).getSheets();
  var hiddenResource = allSheets.map(function(s) {
    var obj = {updateSheetProperties: {properties: {sheetId: s.getSheetId(), hidden: true}, fields: "hidden"}};
    if (sheetNames.indexOf(s.getSheetName()) != -1) obj.updateSheetProperties.properties.hidden = false;
    return obj;
  });
  Sheets.Spreadsheets.batchUpdate({requests: hiddenResource}, spreadsheetId);

  // Create PDF file.
  convertSpreadsheetToPdf(email, spreadsheetId, "pdfteste");

  // Show all sheets.
  var showResource = allSheets.map(function(s) {return {updateSheetProperties: {properties: {sheetId: s.getSheetId(), hidden: false}, fields: "hidden"}}});
  Sheets.Spreadsheets.batchUpdate({requests: showResource}, spreadsheetId);
}

注意:

  • 在我的环境中,当上述脚本用于包含 20 张在单元格中具有值的工作表的 Google 电子表格时,获得了大约 5 秒的处理时间。但是我不确定这是否可以用于您的实际情况。对此我深表歉意。

参考资料:

【讨论】:

  • 这正是我一直在寻找的,你完全理解。现在我可以隐藏/显示所有被忽略的工作表,并很快将我想要的工作表打印为 pdf,非常感谢!
  • 对不起,我的错。我刚刚选择了您的答案作为已接受的答案。
  • @Ken 感谢您的回复。我能理解它。也谢谢你。
  • 这个“有效”但给我带来了很多麻烦。所以我决定不使用它。首先,我不喜欢我必须使用高级 Google 服务——这似乎是不必要的复杂程度。我想单独使用谷歌脚本来做到这一点。其次,它似乎在“MailApp.sendEmail(email,...”这一行失败了,但是当我用“MailApp.sendEmail(email, “see attach pdf”, “Thanks, mailOptions);”简化它时,它似乎工作。最后,它似乎卡在“var showResource = allSheets.map ...”这一行太复杂了,我无法理清。电子邮件通过了,但没有进入我的收件箱。
【解决方案2】:

如果我理解正确的话:

  • 您希望在单个 PDF 中打印部分但不是所有工作表。
  • 您可以通过隐藏不需要的工作表并打印完整的电子表格来做到这一点(仅打印未隐藏的工作表)。
  • 每次要打印 PDF 时隐藏和显示不需要的工作表是很不舒服的,尤其是在工作表很多时。

如果以上正确,那么您可以使用脚本首先隐藏不需要的工作表,然后打印 PDF,最后再次显示这些不需要的工作表。可以通过以下方式完成(查看内联 cmets 了解更多详细信息):

function convertSpreadsheetToPdf(email, spreadsheetId, sheetsToPrint) {
  var ss = SpreadsheetApp.openById(spreadsheetId);
  // Get the names of all sheets in the spreadsheet:
  var allSheets = ss.getSheets().map(function(sheet) {
    return sheet.getName();
  });
  // Get the names of the sheets to ignore:
  var sheetsToHide = allSheets.filter(function(sheetName) {
    return sheetsToPrint.indexOf(sheetName) === -1;
  });
  // Hide the sheets to ignore:
  sheetsToHide.forEach(function(sheetName) {
    var sheet = ss.getSheetByName(sheetName);
    sheet.hideSheet();
  })
  var pdfName = ss.getName();
  var parents = DriveApp.getFileById(spreadsheetId).getParents();
  var folder = parents.hasNext() ? parents.next() : DriveApp.getRootFolder();
  var url_base = ss.getUrl().replace(/edit$/,'');  
  var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf  
  // Print either the entire Spreadsheet (only unhidden sheets):
  + '&id=' + spreadsheetId 
  // following parameters are optional...
  + '&size=A4'      // paper size
  + '&portrait=false'    // orientation, false for landscape
  + '&fitw=true'        // fit to width, false for actual size
  + '&sheetnames=false&printtitle=false&pagenumbers=false'  //hide optional headers and footers
  + '&gridlines=false'  // hide gridlines
  + '&fzr=false';       // do not repeat row headers (frozen rows) on each page
  var options = {
    headers: {
      'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken(),
    }
  }
  var response = UrlFetchApp.fetch(url_base + url_ext, options);
  var blob = response.getBlob().setName(pdfName + '.pdf');
  folder.createFile(blob);
  if (email) {
    var mailOptions = {
      attachments:blob
    }

    MailApp.sendEmail(
      email, 
      "Here is a file named " + pdfName, 
      "Please let me know if you have any questions or comments.", 
      mailOptions);
  }
  // Show the ignored sheets:
  sheetsToHide.forEach(function(sheetName) {
    var sheet = ss.getSheetByName(sheetName);
    sheet.showSheet();
  })    
}

此函数接受emailspreadsheetId 和一个由要打印的工作表名称组成的数组作为参数。可能的调用可能是这样的:

convertSpreadsheetToPdf("your-email@your-domain", "your-spreadsheet-id", ["Sheet1","Sheet2","Sheet5"])

为了处理这个问题,我已经稍微简化了这段代码(PDF 的名称始终是电子表格的名称,并且您始终必须提供电子表格 ID),但可以随时恢复这些更改。

参考:

希望对你有帮助。

【讨论】:

  • 非常感谢@iamblichus,但恐怕这需要很长时间才能运行(超过 1 分钟),我需要在 20 秒或更短的时间内完成。还有其他想法吗?
  • @Ken 这真的很奇怪。我大约需要 4 秒,而我的示例电子表格大约有 15 张。你有几张床单?您能分享一份您正在处理的电子表格的副本(不含敏感信息),以便我复制吗?
猜你喜欢
  • 1970-01-01
  • 2022-06-12
  • 1970-01-01
  • 2020-03-25
  • 1970-01-01
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多