【问题标题】:Error: "Reference does not exist" when using a custom function错误:使用自定义函数时“引用不存在”
【发布时间】:2020-07-15 09:32:38
【问题描述】:

我正在尝试抓取网页并将值放入缓存中,以免达到每日 urlFetch 限制。

这是我正在使用的代码,它可以在没有缓存和属性服务的情况下工作,但在我尝试添加该元素时却不行。

function scrapercache(url) {
  var url = "https://www.gurufocus.com/term/fscore/nyse:ABBV/Piotroski-F-Score";
  var result = [];
    var description;
    var options = {
        'muteHttpExceptions': true,
        'followRedirects': false,
    };
Logger.log('line 16 OK');
  
var cache = CacheService.getScriptCache();
var properties = PropertiesService.getScriptProperties();
Logger.log('line 21 OK');
 
  let res = cache.get(url);
//  if(res){
 // return JSON.parse(res)
//}
Logger.log(res);
Logger.log('line 24 OK');

  if (res) {
    // trim url to prevent (rare) errors
    url.toString().trim();
    var r = UrlFetchApp.fetch(url, options);
    Logger.log(r);
    Logger.log('line 34 OK');
    
    var c = r.getResponseCode();
    Logger.log(c);
    Logger.log('line 38 OK');

    // check for meta refresh if 200 ok
    if (c == 200) {
      var html = r.getContentText();
      cache.put(url, "cached", 21600);
      properties.setProperty(url, html);
      Logger.log('line 46 OK');

      var $ = Cheerio.load(html); // make sure this lib is added to your project!
      Logger.log('line 49 OK');

      // meta description
      if ($('meta[name=description]').attr("content")) {
        description = $('meta[name=description]').attr("content").trim();
        var trim_des = description.substr(0, 40);
        Logger.log('line 55 OK');
      }
    }
  
    result.push([trim_des]);   
    Logger.log('line 60 OK');
  }

  return result;
  Logger.log('line 64 OK');
}

我这样调用函数:

=scrapercache("https://www.gurufocus.com/term/fscore/nyse:ABBV/Piotroski-F-Score")

& 我收到以下错误消息

错误:引用不存在

编辑:我添加了日志行以查看脚本是否正确处理 & 看起来只有在 28 点之前还可以

【问题讨论】:

  • 哪一行会报错?见minimal reproducible example
  • 您在哪里看到错误?请截图
  • @OlegValter:好的,我知道我需要添加一行代码来记录所以我添加了几个 Logger.log('line OK') 来查看是否正在处理,它看起来像是在第 28 行停止。我更新了问题中的代码+截图
  • @OlegValter,别担心,我在睡觉,我在亚洲。我用 Logger.log(res) 添加了 res 的日志;并且从日志中看起来该值为空: [20-07-16 07:10:32:070 HKT] null 因此 var cache = CacheService.getScriptCache(); 可能存在问题谢谢

标签: google-apps-script google-sheets cheerio referenceerror


【解决方案1】:

您没有将结果放入缓存中,而是将字符串“缓存”放在那里。考虑:

let cached = cache.get(url)
if(cached){
  return JSON.parse(cached)
}

let results =  ["blah","blah"] // stuff we got with cheerio
cache.put(url, JSON.stringify(results), 120)
return results

【讨论】:

  • OP 的代码不应该首先到达Logger.log('line 37 OK'); 吗?我担心如果到达Logger.log('line 28 OK'); 调用,但不是前者,还有什么可能是导致UrlFetchApp 的原因(真的很好奇)?
  • @oleg 如果它在缓存中,它就不会到达那里。
  • @Gabriel - 请不要介意关闭说明,这是关于引导用户进行问答,以解决您描述的问题,并不是我们像您期望的那样“关闭”某些东西支持票。您只需要确保: A. 如果已缓存,您实际上会返回 res。目前,成功时您只需返回一个空数组,这会导致错误(这就是问题重复的原因,顺便说一句)。 B. 按照 pguardiario 的建议将 html 放入缓存,而不是 cached 字符串。
  • 我建议缓存解析结果,因为 html 可能太大
  • 在我的回答下查看我的评论^
【解决方案2】:

错误:“引用不存在”

此错误消息通常通过调用电子表格单元格中的自定义函数返回,该函数不返回值official docs明确提到了,但是没有提供错误信息,所以混淆是可以理解的。

空数组不是有效的返回值(因为没有要返回的元素)。使用以下自定义函数很容易重现该错误:

/**
 * @customfunction
 */
function testReferenceError() {
  const list = [];

  return list;
}

当在单元格中调用时,会导致“期望的”错误:

适用于您的案例

在您的情况下,当 cache 中有缓存数据时,if 语句子句的计算结果为 false(取反时的 truthy 值计算为 false)。当它这样做时,result 中没有任何内容得到 pushed,并且在 finally 中返回一个空数组(有关后果的解释,请参见上文)。考虑这个模拟:

const cache = {
  get() {
    return "cached";
  }
};

let res = cache.get("mock_url");

//ternary operator here acts the same as "if...else":
console.log( !res ? "will enter if block" : "will enter else block" );

最后注意return:如果将return语句放入finally块中,expect it to overridereturntrycatch中的语句。考虑一下这个例子,看看你的程序是如何结构的:

const final = (add = false) => {
  const list = [];
  
  try {
    add && list.push(1);
   
    return [1,2]; //this return is skipped
  }
  catch(error) {
    list.push(error);
  }
  finally {
    return list;
  }
  
};

console.log( final() );

另外,问题已经has an answer here

【讨论】:

  • 谢谢大家。我尝试更新脚本删除 try catch finally 并将条件更改为 if (res) 但现在我在日志中收到另一个错误。我更新了帖子问题中的脚本和屏幕截图。再次抱歉,我不太擅长编码。我检查了另一个答案,但我看不出它对我有什么帮助:(谢谢
  • @Gabriel - 你很接近,但你做得过火了 - 为什么要获取数据如果它在缓存中,你不想正确返回它吗离开?无需更改 !res。另外 - 提醒我,为什么你需要 PropertiesService 缓存?
  • 如果我在 if 中放回 !res。当我运行脚本并检查日志时,我得到: [20-07-16 18:06:04:988 HKT] 第 16 行 OK [20-07-16 18:06:04:994 HKT] 第 21 行 OK [20-07-16 18:06:05:038 HKT] false [20-07-16 18:06:05:040 HKT] line 24 OK 所以它没有进入 if 语句。那我应该改变什么?谢谢
  • @Gabriel - 这是意料之中的,别担心。您有一个 "cached" 字符串保存到缓存中(来自您之前的尝试)。看看remove 或removeAll,清除缓存,然后在没有它的情况下重新运行脚本。旁注:Logger.log('line 64 OK'); 永远不会被记录,return 之后的所有内容都会丢失
  • 为了清除缓存,我在第 24 行尝试了 cache.removeAll('cached');cache.removeAll(); 但收到错误消息 Parameters don't match the method signature 我删除了第 67 行的日志
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多