什么是一个合适的谷歌脚本来复制动态更新范围并粘贴在档案表中



我是谷歌应用程序脚本的新手,除了基本的HTML之外,我对任何类型的脚本都一无所知。然而,由于这个论坛,谷歌应用程序的脚本并没有带来太大的挑战。

我是一名数据分析师,一直在研究低成本/开源的方法,以模仿网站出版商在大数据方面的一些基本优势。我的探索把我带到了谷歌脚本。自从一周前我知道这件事以来,我已经能写一些了。

目标挑战是:

  1. 我有一个电子表格,它使用IMPORTHTML函数动态拉取大约1000行。当源每天刷新时,范围会自动刷新,因此前一天的数据会丢失。这需要将数据备份到归档表中,这样我就可以分析所选时间范围内的历史数据。

  2. 我想自动复制这些行,并将它们粘贴在归档表的顶部,就在范围标题的下方,这样我就不必按日期对归档进行排序,这可能是数据分析所必需的。我还需要检查是否有重复的行并将其删除——以防万一。

首先,我编写了一个脚本,将复制的行附加到存档范围的最后一行下面。然而,按日期排序变得很有必要,因为我必须按特定的日期范围过滤数据,比如14天或7天,以便进行高级分析。所以我添加了一个用于排序的片段和另一个用于删除重复的片段。它运行良好,但排序需要很长时间。考虑到每天都有成千上万的新行被添加,这将继续需要更长的时间。我需要一个更聪明的解决方案。

因此,我开始编写一个脚本,该脚本将(1)检测源范围内的行数(2)在存档工作表的标题下插入尽可能多的行,(3)将复制的范围粘贴到新插入的行中。

我写完了,而且写得很快;显然不需要排序。然而,我想知道,是否有办法让它更快、更智能、经得起未来考验。请在下面找到代码。如有任何建议,我们将不胜感激。

function myFunction() {
//1. Get data from source sheet of a spreadsheet whose id is known, we will also need the data range's last row number
var firstStep = SpreadsheetApp.openById("ID of Source Spreadsheet");
var ss = firstStep.getSheetByName("Sheet1");
ss.activate();
var myRange = ss.getRange(4, 2, ss.getLastRow() - 3, ss.getLastColumn());
var myData = myRange.getValues();
//'3' subtracted from last row data collector above as first three rows contain static data or blank row in my source sheet. Applied same technique at line 17 below as well. This totally depends on how you position the source range in the source sheet. For exaple, for a range starting at 1,1 on any sheet, no such subtraction woud be required.
var lastRow = myRange.getLastRow() - 3;
//2. Open archive spreadsheet, select the destination sheet, insert exact number of rows of source range and then paste copied range. 
var secondStep = SpreadsheetApp.openById("ID of archive spreadsheet");
var newSS = secondStep.getSheetByName("dump1");
newSS.activate();
//2.a  Insert Rows as in #lastrow in the new sheet, just below the header at Row 1
newSS.insertRowsBefore(2, lastRow)
//2.b Paste values
newSS.getRange(2, 1, myData.length, myData[0].length).setValues(myData);
//2.c Paste last row number of the copied range in another cell of the same sheet, optional step, just to be sure that last row determination process is right. You may remove this step if you like.  
newSS.getRange(1, 15).setValue(lastRow);
/*   
//3.a Optional: Script to remove duplicate rows in archive sheet. Will increase the script-run duration considerably. 

var data = newSS.getDataRange().getValues();
var newData = new Array();
for(i in data){
var row = data[i];
var duplicate = false;
for(j in newData){
if(row.join() == newData[j].join()){
duplicate = true;
}
}
if(!duplicate){
newData.push(row);
} 
}
newSS.clearContents();
newSS.getRange(1, 1, newData.length, newData[0].length).setValues(newData);

*/
}

你能在谷歌应用程序中完成的任何事情脚本本身都比从谷歌服务器或外部服务器(如对电子表格、文档、网站等的请求)获取数据的调用要快得多。如果你能找到方法最大限度地减少脚本对这些服务的调用,你的脚本就会运行得更快。

要加快脚本的速度,请使用一个命令将所有数据读取到数组中,对数组中的数据执行任何操作,并使用一个指令将数据写入。

这里有一个例子:

var cell = sheet.getRange('a1');
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
xcoord = xmin;
colors[y] = new Array(100);
for (var x = 0; x < 100; x++) {
colors[y][x] = getColor_(xcoord, ycoord);
xcoord += xincrement;
}
ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);

你必须使用谷歌的最佳实践,谷歌列表中的亮点是:

  • 减少API调用次数
  • 进行API调用时,请批处理请求
  • 使用缓存服务中内置的应用程序脚本
  • 不要使用UIApp;使用HTML服务

以下是一份文档列表,列出了可以帮助您提高脚本性能的最佳实践:https://developers.google.com/apps-script/best_practices#minimize-呼叫其他服务

最新更新