【问题标题】:Loop function from a certain row till the last row从某一行到最后一行的循环函数
【发布时间】:2021-02-24 22:10:33
【问题描述】:

我在 A 列中有一个 url 列表,我正在从包含公式(模板行)的行中复制和粘贴公式,以提取数据。 然后代码执行 SpreadsheetApp.flush();然后复制该特定行的结果并将其作为值粘贴到同一行。

我为此编写的代码如下。

function scraper(){
  copypasteFormulas();
  copypasteResultValues();
}

function copypasteFormulas() {

 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");


 var sourceRange = sheet.getRange('B2:T2'); //Copy formulas from template row
 var sourceFormulas = sourceRange.getFormulasR1C1();

 var targetRange = sheet.getRange('B5:T5'); //Paste formulas 
  targetRange.setFormulasR1C1(sourceFormulas);

}

function copypasteResultValues() {

 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");

 SpreadsheetApp.flush(); //Delay between paste of formula and copypaste of values onto it's self

 var copyFromRange = 'Sheet1!B5:T5'; // Copies result range
 var copyToRangeStart = 'Sheet1!B5'; // Pastes results into itself as values
 var source = sheet.getRange(copyFromRange);
  source.copyTo(sheet.getRange(copyToRangeStart), {contentsOnly: true});

}

但是我希望这个循环遍历每一行直到最后一行,然后从 B5:T5 重新开始到行的末尾。

例如,以下内容保持不变,因为这是复制公式的地方。

 var sourceRange = sheet.getRange('B2:T2'); //Copy formulas from template row
 var sourceFormulas = sourceRange.getFormulasR1C1();

其余的需要随着每一行的填写而改变

 var targetRange = sheet.getRange('B5:T5'); //Paste formulas 
  targetRange.setFormulasR1C1(sourceFormulas);

 var copyFromRange = 'Scraper!B5:T5'; // Copies result range
 var copyToRangeStart = 'Scraper!B5'; // Pastes results into itself as values

我不知道该怎么做。

****** 更新 ******

我设法将以下代码放在一起,从某一行循环到最后一行。

function iterativeCopyPaste() {
  // Get array of values in the search Range
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Scraper");
 var rangeData = sheet.getDataRange();
 var lastColumn = rangeData.getLastColumn();
 var lastRow = rangeData.getLastRow();
 var searchRange = sheet.getRange(2,2, lastRow-1, lastColumn-1);
 var rangeValues = searchRange.getValues(); // Loop through array and if condition met, add relevant
  
 var sourceRange = sheet.getRange(2,2,1,19); //Copy formulas from template row
 var sourceFormulas = sourceRange.getFormulasR1C1();
 
// Copy paste formulas and copy paste result to values iteration
 for ( j = 5 ; j < lastRow - 1; j++){
      var i = 2;
      if(rangeValues[j][i] === ""){
        var targetRange = sheet.getRange(j, i, 1, 19); //row range to which the formulas are pasted
        targetRange.setFormulasR1C1(sourceFormulas);
        SpreadsheetApp.flush();
    };
      var source = sheet.getRange(j, i, 1, 19); // result range to copy
       SpreadsheetApp.flush();
        source.copyTo(sheet.getRange(j, i, 1, 19), {contentsOnly: true}); // Pastes results into itself as values
       SpreadsheetApp.flush();
  };

};

但是它在最后一行之前停止了两行,所以我不得不在 A 列的列表末尾添加两个虚拟行,以便 url 循环通过。

复制到行中的公式使用 importxml 来提取数据,有时它们会卡在“加载”上,这是我使用的公式之一,如下所示。

=if(iserror(IMPORTXML($A2,"//h1[contains(@class,'ch-title')]")),"Loading",IMPORTXML($A2,"//h1[contains(@class,'ch-title')]"))

只有当sheet.getRange(j, i, 1, 19) 中的所有单元格都没有显示为正在加载时,迭代才会继续进行。

编辑:看来,如果我使用一个

SpreadsheetApp.flush();
Utilities.sleep(100000);

//粘贴公式的行范围下,它似乎会缓慢地浏览所有加载所有数据的 URL,然后将其作为值复制和粘贴。到目前为止,它似乎运作良好。

【问题讨论】:

  • B5:T7 不是一行(它是 3 行的范围)。所以我不确定你在行尾迭代每一行是什么意思。你介意澄清一下吗?
  • 对不起,我弄错了,不是 B5:T7 而是 B5:T5。我所说的函数逐行运行的意思是,例如,它首先从 B5:T5 运行,然后从 B6:T6 运行,依此类推,直到 A 列中的最后一行 url。我希望这会有所帮助。
  • 您的方法存在两个问题。 1) sleep 函数的最大允许值为300000 毫秒,因此您不能拥有14400000。 2) 300000 毫秒等于 5 分钟,但您只能运行脚本 30 分钟。也就是说,如果您将该代码放入迭代中,则只能运行 6 行。您可以使用 SpreadsheetApp.flush() 代替它应该更新工作表中的待处理更改,并且不会花费太多时间。
  • 如果flush 工作正常,那么我猜你可以设置一个循环,但这取决于更新公式需要多长时间。
  • 公式使用 importxml,所以我给了它大约 1.5-2 分钟的更新时间,以获取必要的数据,然后将其作为值复制并粘贴到自身上。所以这样 importxml 就没有大小写限制。那么这是否意味着 300000 毫秒是每次使用的限制,或者说它使用的总次数应该等于 300000 毫秒

标签: google-apps-script google-sheets


【解决方案1】:

这是我整理的最终代码,可以满足我的需求。 并将时间触发器设置为每 30 分钟运行一次,以防超时。

   function iterativeCopyPaste() {
  // Get array of values in the search Range
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Scraper");
  var rangeData = sheet.getDataRange();
  var lastColumn = rangeData.getLastColumn();
  var lastRow = rangeData.getLastRow();
  var searchRange = sheet.getRange(2,2, lastRow-1, lastColumn-1);
 var rangeValues = searchRange.getValues(); // Loop through array and if condition met, add relevant
 
 var sourceRange = sheet.getRange(2,2,1,10); //Copy formulas from template row
 var sourceFormulas = sourceRange.getFormulasR1C1();
 var counter = 0;
 

// Copy paste formulas and copy paste result to values iteration
for ( j = 5 ; j < lastRow - 1; j++){
        var i = 2;
    counter++;
    var targetRange = sheet.getRange(j, i, 1, 10); //row range to which the formulas are pasted
        if(targetRange.isBlank()){
        //var targetRange = sheet.getRange(j, i, 1, 10); //row range to which the formulas are pasted
        targetRange.setFormulasR1C1(sourceFormulas);
        
        SpreadsheetApp.flush();
        Utilities.sleep(100000); // Delay before the copy and paste of result values
    };
      var source = sheet.getRange(j, i, 1, 19); // result range to copy
      SpreadsheetApp.flush();
        source.copyTo(sheet.getRange(j, i, 1, 19), {contentsOnly: true}); // Pastes results into itself as values
        SpreadsheetApp.flush();
        if (counter === 4) {    // Delay after every 5 rows
            Utilities.sleep(240000);
          SpreadsheetApp.flush();
          counter = 0;
        };
};

};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-23
    • 2023-03-25
    • 1970-01-01
    • 2019-12-16
    相关资源
    最近更新 更多