来自 Google Apps 脚本的 ContactsApp.getContacts() 未按预期运行

ContactsApp.getContacts() from Google Apps Script does not behave as expected

我有一个脚本可以将所有联系人从 Google 联系人获取到 Google 工作表中的传播sheet。由于6分钟执行时限内联系人太多,我使用脚本触发一段时间后继续导入。

...
var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length; ++i){
  // register trigger if time is up
  // ....
  
  var name = contacts[i].getFullName();
  sheet.appendRow([name]);
}
...

什么有效:

  1. 当达到时间限制时(我将其设置为 4 分钟),触发器会 运行 并继续导入。

什么不起作用:

  1. 执行链会在某个点随机停止,导致导入不完整。
  2. 即使联系人的大小小到可以在 4 分钟内获取,导入的联系人数量有时也与 contacts.length 不匹配。大多数时候它会匹配。
  3. 补偿(1)。我制作了一个新菜单,以继续从最后一个索引导入,该索引源自 sheet 中写入的总行数。但是,当以这种方式完成时,导入的联系人将从第一个索引开始,无论我要求脚本从哪个索引开始。

例如:

for(var i = last_row;i<contacts.length;++i){ // I've checked last_row is indeed not 0
  var name = contacts[i].getFullName();
  // append row
}

将产生与以下相同的结果:

for(var i = 0;i<contacts.length;++i){
  var name = contacts[i].getFullName();
  // append row
}

无论我要求从哪个索引开始,它总是从联系人数组的第一个索引开始,除非它是从触发器链中执行的。谁能告诉我这是怎么回事?我该如何解决这个问题?

在您的脚本中,appendRow 用于循环。在这种情况下,工艺成本变高。 Ref 我猜想这可能是您处理时间的原因。如果我对你的问题的理解是正确的,那么下面的修改怎么样?

发件人:

var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length; ++i){
  // register trigger if time is up
  // ....
  
  var name = contacts[i].getFullName();
  sheet.appendRow([name]);
}

收件人:

var contacts = ContactsApp.getContacts();
var values = contacts.map(e => [e.getFullName()]);
sheet.getRange(sheet.getLastRow() + 1, 1, values.length).setValues(values);
  • 在此修改中,将值放入一个数组,然后使用 setValues 将该数组放入 Spreadsheet。据此,我认为这个过程可能是运行一次执行。

另一种方法:

作为另一种方法,使用 People API 怎么样?当使用 People API 时,示例脚本如下。如果你使用这个脚本,please enable People API at Advanced Google services.

function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var values = [];
  var pageToken = "";
  do {
    var o1 = People.People.Connections.list("people/me", { personFields: "names", fields: "connections.names.displayName,nextPageToken", pageSize: 1000, pageToken });
    if (o1.connections.length > 0) {
      values.push(...o1.connections.map(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
    }
    pageToken = o1.nextPageToken;
  } while (pageToken);
  do {
    var o2 = People.OtherContacts.list({ readMask: "names", fields: "otherContacts.names.displayName,nextPageToken", pageSize: 1000, pageToken });
    if (o2.otherContacts.length > 0) {
      values.push(...o2.otherContacts.flatMap(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
    }
    pageToken = o2.nextPageToken;
  } while (pageToken);
  sheet.getRange(sheet.getLastRow() + 1, 1, values.length).setValues(values);
}
  • 在此示例中,值被放入活动 sheet。请根据实际情况修改。

参考文献: