【问题标题】:Periodically refresh IMPORTXML() spreadsheet function定期刷新 IMPORTXML() 电子表格函数
【发布时间】:2016-02-25 16:09:00
【问题描述】:

我有一张大表,其中包含大约 30 个 importxml 函数,这些函数从通常每天更新两次的网站获取数据。

我想及时(每 8 小时)运行importxml 函数,以便我的 Google 电子表格将数据保存在另一个工作表中。保存已经生效,但是更新不行!

我在Google Spreadsheet row update 中读到它可能每 2 小时运行一次,但我不相信这是真的,因为自从我将它添加到我的工作表后,当电子表格未打开时,没有任何更改或更新。

我如何在我的 Google 电子表格中以简单的方式“触发”importxml 函数,因为其中有很多 importxml 函数?

【问题讨论】:

    标签: google-apps-script google-sheets google-sheets-formula google-sheets-importxml gs-installable-triggers


    【解决方案1】:

    我对 Mogsdad 的回答做了一些调整:

    • 修复了releaseLock() 调用位置
    • 向导入函数中的 url 更新(或添加)查询字符串参数(而不是存储、删除、等待 5 秒,然后恢复所有相关公式)
    • 在电子表格中的特定工作表上工作
    • 显示上次更新时间

    ...

    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())
    }
    

    【讨论】:

    • 您的脚本运行良好。但我遇到了问题。如果我使用=IMPORTXML("https://en.wikipedia.org/wiki/Moon_landing", "//a/@href"),脚本会更新数据。但是如果我将url 存储在一个单元格中,比如B2 并使用=IMPORTXML(B2, "//a/@href"),那么脚本将无法刷新。你能帮忙吗?
    • 在我的情况下,只有在我将 ?update= 添加到 url 后才开始工作。
    • 这对我来说非常有用。我唯一的问题是,如果该 URL 中已经包含参数,那么我与 importXML 一起使用的 URL 会返回错误。我有一个带参数的 URL 和一个不带参数的 URL,并且在末尾附加“?update=XXX”参数会丢弃带有其他参数的 URL。为了解决这个问题,我在没有参数的情况下向我的 URL 添加了一个虚拟参数,并将“?update=XXX”的添加更改为“&update=XXX”,一切都很好。如果代码检查预先存在的参数并使用适当的“?”附加“更新”,那将是最有用的。或“&”,但我还没有花时间解决它。
    • 感谢@MAKDesignLabs。我有同样的问题。我的提要 URL 已经有参数,因此运行更新时出现错误“无法解析导入的 XML 内容。”。但是在第 27 行将 ?update 更改为 &amp;update 为我解决了这个问题。所以我同意 - 如果脚本检查现有参数然后使用&amp; 而不是?,那就太好了。除此之外,它运作良好。
    【解决方案2】:

    Google Spreadsheet row update 问题及其答案涉及“旧表格”,其行为与 2015 版 Google 表格不同。 “新工作表”不会自动刷新内容;现在只评估更改以响应编辑。

    虽然表格本身不再提供此功能,但我们可以使用脚本来刷新“导入”公式(IMPORTXML、IMPORTDATA、IMPORTHTML 和 IMPORTANGE)。

    实用程序脚本

    对于IMPORT公式的定期刷新,将此函数设置为time-driven trigger。

    注意事项:

    • 在刷新期间其他脚本或用户对电子表格所做的导入函数公式更改可能会被覆盖。
    • 重叠刷新可能会使您的电子表格不稳定。为了缓解这种情况,实用程序脚本使用ScriptLock。这可能与脚本中该锁的其他用途发生冲突。

     

    /**
     * Go through all sheets in a spreadsheet, identify and remove all spreadsheet
     * import functions, then replace them a while later. This causes a "refresh"
     * of the "import" functions. For periodic refresh of these formulas, set this
     * function up as a time-based trigger.
     *
     * Caution: Formula changes made to the spreadsheet by other scripts or users
     * during the refresh period COULD BE OVERWRITTEN.
     *
     * From: https://stackoverflow.com/a/33875957/1677912
     */
    function RefreshImports() {
      var lock = LockService.getScriptLock();
      if (!lock.tryLock(5000)) return;             // Wait up to 5s for previous refresh to end.
      // At this point, we are holding the lock.
    
      var id = "YOUR-SHEET-ID";
      var ss = SpreadsheetApp.openById(id);
      var sheets = ss.getSheets();
    
      for (var sheetNum=0; sheetNum<sheets.length; sheetNum++) {
        var sheet = sheets[sheetNum];
        var dataRange = sheet.getDataRange();
        var formulas = dataRange.getFormulas();
        var tempFormulas = [];
        for (var row=0; row<formulas.length; row++) {
          for (col=0; col<formulas[0].length; col++) {
            // Blank all formulas containing any "import" function
            // See https://regex101.com/r/bE7fJ6/2
            var re = /.*[^a-z0-9]import(?:xml|data|feed|html|range)\(.*/gi;
            if (formulas[row][col].search(re) !== -1 ) {
              tempFormulas.push({row:row+1,
                                 col:col+1,
                                 formula:formulas[row][col]});
              sheet.getRange(row+1, col+1).setFormula("");
            }
          }
        }
    
        // After a pause, replace the import functions
        Utilities.sleep(5000);
        for (var i=0; i<tempFormulas.length; i++) {
          var cell = tempFormulas[i];
          sheet.getRange( cell.row, cell.col ).setFormula(cell.formula)
        }
    
        // Done refresh; release the lock.
        lock.releaseLock();
      }
    }
    

    【讨论】:

    • 感谢您的脚本。我立即尝试了它,但它删除了工作表内的所有非导入功能和数据。有什么建议为什么会出现这种情况?感谢您的回复!
    • 我相信你的 releaseLock() 调用是在 for 循环内
    【解决方案3】:

    回答您的问题以获得简单的“触发器”以强制重新加载函数:

    向您正在加载的 url 添加一个额外的未使用参数,同时为该参数的值引用一个单元格。 一旦你改变了那个单元格的内容,函数就会重新加载。

    示例:

    importxml("http://www.example.com/?noop=" & $A$1,"...")
    

    很遗憾,您不能将日期计算函数放入引用的单元格中,这会引发错误,这是不允许的。

    【讨论】:

      【解决方案4】:

      您还可以将每个 XML 公式作为注释放在相应的单元格中,并记录一个宏以将其复制并粘贴到同一单元格中。稍后使用脚本和触发器功能来安排这个宏。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多