Google apps script 定期刷新IMPORTXML()电子表格函数
我有一个很大的表格,里面有大约30个importxml函数,这些函数从通常每天更新两次的网站获取数据 我想为我的谷歌电子表格及时(每8小时)运行Google apps script 定期刷新IMPORTXML()电子表格函数,google-apps-script,google-sheets,google-sheets-formula,google-sheets-importxml,gs-installable-triggers,Google Apps Script,Google Sheets,Google Sheets Formula,Google Sheets Importxml,Gs Installable Triggers,我有一个很大的表格,里面有大约30个importxml函数,这些函数从通常每天更新两次的网站获取数据 我想为我的谷歌电子表格及时(每8小时)运行importxml功能,将数据保存在另一张表格中。保存已起作用,但更新不起作用 我读到它可能每2小时运行一次,但我不相信这是真的,因为自从我将它添加到我的工作表中,当电子表格未打开时,没有任何更改或更新 如何在我的谷歌电子表格中以简单的方式“触发”导入XML的功能,因为我有很多导入XML的功能?问题和答案都是“旧表单”,它们的行为与2015年版的谷歌表单
importxml
功能,将数据保存在另一张表格中。保存已起作用,但更新不起作用
我读到它可能每2小时运行一次,但我不相信这是真的,因为自从我将它添加到我的工作表中,当电子表格未打开时,没有任何更改或更新
如何在我的谷歌电子表格中以简单的方式“触发”导入XML的功能,因为我有很多导入XML的功能?问题和答案都是“旧表单”,它们的行为与2015年版的谷歌表单不同。没有使用“新工作表”自动刷新内容;现在仅对修改进行评估以响应编辑
虽然工作表不再以本机方式提供此功能,但我们可以使用脚本刷新“导入”公式(IMPORTXML
、IMPORTDATA
、IMPORTHTML
和importage
)
实用程序脚本
要定期刷新导入公式,请将此函数设置为
注意事项:
- 其他脚本或用户在刷新期间对电子表格所做的导入函数公式更改可能会被覆盖
- 重复刷新可能会使电子表格不稳定。为了缓解这种情况,实用程序脚本使用了一个。这可能与脚本中该锁的其他用法冲突
/**
*浏览电子表格中的所有表格,识别并删除所有电子表格
*导入函数,然后稍后替换它们。这会导致“刷新”
*“导入”功能的定义。要定期刷新这些公式,请设置
*作为基于时间的触发器运行。
*
*警告:其他脚本或用户对电子表格所做的公式更改
*刷新期间可能会被覆盖。
*
*发件人:https://stackoverflow.com/a/33875957/1677912
*/
函数RefreshImports(){
var lock=LockService.getScriptLock();
如果(!lock.tryLock(5000))返回;//请最多等待5秒,以结束上一次刷新。
//在这一点上,我们持有的锁。
var id=“YOUR-SHEET-id”;
var ss=电子表格应用程序openById(id);
var sheets=ss.getSheets();
对于(var sheetNum=0;sheetNum),要回答您的问题,以获得一个简单的“触发器”,强制重新加载函数:
在为该参数的值引用单元格时,向正在加载的url添加其他未使用的参数。
一旦更改了该单元格的内容,函数将重新加载
例如:
importxml("http://www.example.com/?noop=" & $A$1,"...")
不幸的是,您无法将日期计算函数放入引用的单元格,这会引发一个错误,这是不允许的。我对Mogsdad的答案做了一些调整:
- 修复了
releaseLock()
调用位置
- 在导入函数中向url更新(或添加)querystring参数(而不是存储、删除、等待5秒钟,然后恢复所有相关公式)
- 在电子表格中的特定工作表上工作
- 显示上次更新的时间
函数RefreshImports(){
var lock=LockService.getScriptLock();
如果(!lock.tryLock(5000))返回;//请最多等待5秒,以结束上一次刷新。
var id=“[您的电子表格id]”;
var ss=电子表格应用程序openById(id);
var sheet=ss.getSheetByName(“[sheet NAME]”);
var dataRange=sheet.getDataRange();
var formulas=dataRange.getFormulas();
var-content=“”;
var now=新日期();
var time=now.getTime();
var re=/.[^a-z0-9]导入(?:xml |数据|提要| html |范围)\(.*/gi;
变量re2=/(\?|&)(更新=[0-9]*)/gi;
变量re3=/(“,)/gi;
对于(var row=0;row,您还可以将每个XML公式作为注释放在相应的单元格中,并记录一个宏以将其复制并粘贴到同一单元格中。稍后使用脚本,然后使用触发器功能计划此宏。
Thx用于您的scrip。我立即尝试了它,但它删除了工作表中的所有非导入函数和数据。有什么建议吗?感谢您的回复!我相信您的releaseLock()调用在循环中,因为您的脚本工作得很好。但我面临一个问题。如果我使用=IMPORTXML(“https://en.wikipedia.org/wiki/Moon_landing“,”//a//@href“
脚本会更新数据。但是如果我将url
存储在单元格中,请说B2
并使用=IMPORTXML(B2,“//a//@href”)
,然后脚本无法刷新。您能帮助我吗?在我的情况下,只有在我将?update=
添加到url后才开始工作。这对我来说非常有效。我唯一的问题是,如果导入XML使用的url中已经有参数,则返回的url不正确。我有一个带有参数的url和一个不带参数的url,并附加““update=XXX”参数的结尾是将URL与其他参数分开。为了避免这个问题,我在我的URL中添加了一个不带参数的伪参数,并将“?update=XXX”的添加更改为“&update=XXX”,一切正常。如果代码检查了预先存在的参数,并在“update”后面添加了相应的“?”或“,这将非常有用&,但我还没有花时间解决。谢谢@MAKDesignLabs。我也遇到了同样的问题。我的源URL已经有参数,因此运行更新时出现错误“无法解析导入的XML内容”但是在第27行将?update
更改为&update
为我解决了这个问题。因此,我同意-如果脚本检查现有参数,然后使用&
而不是?
,这将非常好。除此之外,它运行良好。
function RefreshImports() {
var lock = LockService.getScriptLock();
if (!lock.tryLock(5000)) return; // Wait up to 5s for previous refresh to end.
var id = "[YOUR SPREADSHEET ID]";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheetByName("[SHEET NAME]");
var dataRange = sheet.getDataRange();
var formulas = dataRange.getFormulas();
var content = "";
var now = new Date();
var time = now.getTime();
var re = /.*[^a-z0-9]import(?:xml|data|feed|html|range)\(.*/gi;
var re2 = /((\?|&)(update=[0-9]*))/gi;
var re3 = /(",)/gi;
for (var row=0; row<formulas.length; row++) {
for (var col=0; col<formulas[0].length; col++) {
content = formulas[row][col];
if (content != "") {
var match = content.search(re);
if (match !== -1 ) {
// import function is used in this cell
var updatedContent = content.toString().replace(re2,"$2update=" + time);
if (updatedContent == content) {
// No querystring exists yet in url
updatedContent = content.toString().replace(re3,"?update=" + time + "$1");
}
// Update url in formula with querystring param
sheet.getRange(row+1, col+1).setFormula(updatedContent);
}
}
}
}
// Done refresh; release the lock.
lock.releaseLock();
// Show last updated time on sheet somewhere
sheet.getRange(7,2).setValue("Rates were last updated at " + now.toLocaleTimeString())
}