【问题标题】:How to optimize getYoutubeViews function so as not to exceed the daily Youtube API quota?如何优化 getYoutubeViews 功能以免超过每日 Youtube API 配额?
【发布时间】:2019-12-20 15:50:18
【问题描述】:

我正在尝试在 google 电子表格中自动收集有关 Youtube 视频的统计信息。为此,我在电子表格脚本编辑器中使用带有 getYoutubeViews 函数以及 GETURL、linkURL 函数等的代码。

这里是getYoutubeViews函数示例

function getYoutubeViews(videoId){
  var url = "https://www.googleapis.com/youtube/v3/videos?part=statistics&id=" + videoId;
  url = url + "&key=mykey";
  //Utilities.sleep(Math.random(15000))
  var videoListResponse = UrlFetchApp.fetch(url);
  var json = JSON.parse(videoListResponse.getContentText());
  return json["items"][0]["statistics"]["viewCount"];
}

function GETURL(input) {
  var range = SpreadsheetApp.getActiveSheet().getRange(input);
  var url = /"(.*?)"/.exec(range.getFormulaR1C1())[1];
  return url;
}

我遇到了两个问题。

脚本在用户加载表格时开始工作。这会启动大量进程,因为表中的视频数量超过 600 条。这会导致错误:“服务在短时间内调用太多次:exec qps”。

但是用 Utilities.sleep 修复它没有意义,因为还有第二个问题。 Google 的 10,000 点 API 密钥配额在工作 3-4 小时并定期重新加载表格后结束。

我尝试最小化列表中的功能和操作,并使用 Utilities.sleep 来避免此错误:

Service invoked too many times in a short time: exec qps. 
Try Utilities.sleep(1000) between calls. (строка 0).

但这似乎无助于解决配额问题。

在我看来,我可以以某种方式将数据保存在单元格中,仅在更新数据时激活功能。我尝试将更改触发器用于这些目的,但要么我做错了,要么没有帮助。

第二个假设是可以以某种方式保存以前的数据,这样即使在脚本错误的情况下单元格中也会有一些数据。但我不知道如何做到这一点。

【问题讨论】:

  • 我认为您的问题的原因是使用一个视频 ID 检索到一个 viewCount 值。如果在你现在的情况下,通过自定义函数运行getYoutubeViews()的函数,例如,用OnOpen事件触发器运行一个脚本怎么样?在这种情况下,一个 API 调用可以检索多个 viewCount 值。这样,我认为配额的消耗会减少。

标签: javascript json google-apps-script google-sheets youtube


【解决方案1】:

一种避免使用自定义函数(每次都会发出所有请求)的方法是使用 onOpen() 触发器来添加一个菜单 [1],单击该菜单时会运行 getYoutubeViews() 函数。此函数将发出请求并在电子表格中插入响应数据(查看次数)。它将从 B 列(从第 2 行开始)获取 videoIds 并在 D 列中设置观看次数。我放置了一个“If”条件,以便只为空视图单元格发出请求(更新值)。

为了操作电子表格上的数据,我使用了 SpreadsheetApp 类 [2]

function onOpen() {
  SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
  .createMenu('Actions')
  .addItem('Add views', 'getYoutubeViews')
  .addToUi();  
}

function getYoutubeViews(){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Sheet2"); 
  var videoIdArray = sheet.getRange(2, 2, sheet.getLastRow()-1, 1).getValues();
  var views = sheet.getRange(2, 4, sheet.getLastRow()-1, 1);

  for(var i=0; i<videoIdArray.length ; i++) {
    var videoId = videoIdArray[i][0];
    var viewsCell = sheet.getRange(2 + i, 4);

    if(viewsCell.getValue() == "") {
      var url = "https://www.googleapis.com/youtube/v3/videos?part=statistics&id=" + videoId;
      url = url + "&key=AAIzaSyAUjC5AchndLg9BRIrRBYKLuKf-fFkMC9M";
      var options = {
        'muteHttpExceptions' : true,
        'headers': {
          'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
        }
      };

      var videoListResponse = UrlFetchApp.fetch(url, options);
      var json = JSON.parse(videoListResponse.getContentText());
      Logger.log(json)

      var views = json["items"][0]["statistics"]["viewCount"];
      viewsCell.setValue(views);
    }
  }
}

你不能直接用onEdit()函数运行代码,因为触发器有限制[3],其中有一个说:

他们无法访问需要授权的服务。

UrlFetchApp.fetch() 是一项需要用户授权的服务。

[1]https://developers.google.com/apps-script/guides/menus

[2]https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app

[3]https://developers.google.com/apps-script/guides/triggers/#restrictions

【讨论】:

    猜你喜欢
    • 2022-08-05
    • 2019-06-10
    • 1970-01-01
    • 2020-08-28
    • 2019-01-19
    • 1970-01-01
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多