【发布时间】: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