如何让我的 Google Apps 脚本功能适用于单元格输入?

How can I make my Google Apps Script function work on cell input?

我有。我在这里得到了一些很好的帮助,我想我快完成了,只需要再多一点帮助就可以正常工作了。

该脚本查看 Google Sheet 并获取在 A 列中输入的地名,并使用 Google 地点 API 查找有关它的请求信息(地址、phone 号码等)

我需要的最后一点帮助将能够实现单元格输入组件。上一个用户帮我说

function writeToSheet(){
  var ss = SpreadsheetApp.getActiveSheet();
  var data = COMBINED2("Food");
  var placeCid = data[4];
  var findText = ss.createTextFinder(placeCid).findAll();
  if(findText.length == 0){
    ss.getRange(ss.getLastRow()+1,1,1, data.length).setValues([data])
  }
} 

将能够使用 TextFinder 检查 url 位置是否存在于 Sheet 中。如果 TextFinder 的结果为 0,它将调用 COMBINED2() 来获取位置信息并用 writeToSheet()

填充 Sheet

他们注意到

You can use a cell input in your COMBINED2 by using ss.getRange(range).getValue()

没有编码背景,我已经能够自己将大部分内容拼接在一起,但我可以使用一些帮助来将这种功能添加到我的代码中。任何帮助或指导都会很棒。

完整代码如下:

// This location basis is used to narrow the search -- e.g. if you were
// building a sheet of bars in NYC, you would want to set it to coordinates
// in NYC.
// You can get this from the url of a Google Maps search.
const LOC_BASIS_LAT_LON = "40.74516247433546, -73.98621366765816"; // e.g. "37.7644856,-122.4472203"

function COMBINED2(text) {
  var API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx';
  var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
  var queryUrl = baseUrl + '?input=' + text + '&inputtype=textquery&key=' + API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
  var response = UrlFetchApp.fetch(queryUrl);
  var json = response.getContentText();
  var placeId = JSON.parse(json);
  var ID = placeId.candidates[0].place_id;
  var fields = 'name,formatted_address,formatted_phone_number,website,url,types,opening_hours';
  var baseUrl2 = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
  var queryUrl2 = baseUrl2 + ID + '&fields=' + fields + '&key='+ API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;

  if (ID == '') {
    return 'Give me a Google Places URL...';
  }

  var response2 = UrlFetchApp.fetch(queryUrl2);
  var json2 = response2.getContentText();
  var place = JSON.parse(json2).result;

  var weekdays = '';
  place.opening_hours.weekday_text.forEach((weekdayText) => {
    weekdays += ( weekdayText + '\r\n' );
  } );

  var data = [
    place.name,
    place.formatted_address,
    place.formatted_phone_number,
    place.website,
    place.url,
    weekdays.trim()
  ];

  return data;
}

function getColumnLastRow(range){
  var ss = SpreadsheetApp.getActiveSheet();
  var inputs = ss.getRange(range).getValues();
  return inputs.filter(String).length;
}

function writeToSheet(){
  var ss = SpreadsheetApp.getActiveSheet();
  var data = COMBINED2("Food");
  var placeCid = data[4];
  var findText = ss.createTextFinder(placeCid).findAll();
  if(findText.length == 0){
    ss.getRange(ss.getLastRow()+1,1,1, data.length).setValues([data])
  }
}

function onOpen() {
  const ui = SpreadsheetApp.getUi();  
  ui.createMenu("Custom Menu")
      .addItem("Get place info","writeToSheet")
      .addToUi();
}

更新

这是一个 link 到一个共享 Sheet 以防有人想和我一起工作。

https://docs.google.com/spreadsheets/d/1KGsk6nkin1CUgpjfHU_AdhF17T_Eh41_g4MLb1CG_Tk/edit#gid=2100307022

以下是我可能没有表达清楚的地方。

我希望能够在 A 列中输入地名

然后,我希望能够运行具有自定义菜单功能的功能。如果 TextFinder 没有找到给定地点的地点 URL,它将查找数据并将其写入 Sheet.

我想限制 API 调用的次数,并确保数据已写入 Sheet,这样就不需要每次 [=68] 都将其拉出=] 重新打开。


成品

非常感谢 Lamblichus 和我一起解决这个问题。我希望有一天这对其他人有所帮助。

这是完成的代码:

// This location basis is used to narrow the search -- e.g. if you were
// building a sheet of bars in NYC, you would want to set it to coordinates
// in NYC.
// You can get this from the url of a Google Maps search.
const LOC_BASIS_LAT_LON = "ENTER_GPS_COORDINATES_HERE"; // e.g. "37.7644856,-122.4472203"

function COMBINED2(text) {
  var API_KEY = 'ENTER_API_KEY_HERE';
  var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
  var queryUrl = baseUrl + '?input=' + text + '&inputtype=textquery&key=' + API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
  var response = UrlFetchApp.fetch(queryUrl);
  var json = response.getContentText();
  var placeId = JSON.parse(json);
  var ID = placeId.candidates[0].place_id;
  var fields = 'name,formatted_address,formatted_phone_number,website,url,types,opening_hours';
  var baseUrl2 = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
  var queryUrl2 = baseUrl2 + ID + '&fields=' + fields + '&key='+ API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;

  if (ID == '') {
    return 'Give me a Google Places URL...';
  }

  var response2 = UrlFetchApp.fetch(queryUrl2);
  var json2 = response2.getContentText();
  var place = JSON.parse(json2).result;

  var weekdays = '';
  if (place.opening_hours && place.opening_hours.weekday_text) {
    place.opening_hours.weekday_text.forEach((weekdayText) => {
      weekdays += ( weekdayText + '\r\n' );
    } );
  }

  var data = [
    place.name,
    place.formatted_address,
    place.formatted_phone_number,
    place.website,
    place.url,
    weekdays.trim()
  ];

  return data;
}

function writeToSheet() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const FIRST_ROW = 2;
  const sourceData = sheet.getRange(FIRST_ROW, 1, sheet.getLastRow()-FIRST_ROW+1, 6)
                          .getValues().filter(row => String(row[0]));
  for (let i = 0; i < sourceData.length; i++) {
    const sourceRow = sourceData[i];
    if (sourceRow[4] === "") {
      const text = sourceRow[0];
      const data = COMBINED2(text);
      sheet.getRange(FIRST_ROW+i, 2, 1, data.length).setValues([data]);
    }
  }
}

function onOpen() {
  const ui = SpreadsheetApp.getUi();  
  ui.createMenu("Custom Menu")
      .addItem("Get place info","writeToSheet")
      .addToUi();
}

通过使用事件触发功能...

function onEdit(e){
SpreadsheetApp.getActiveSheet().getRange(insert your range in A1 format).setValue("anything you want to add into the cell")
}

function onEdit(e){
  var ss = SpreadsheetApp.getActiveSheet();
  var data = COMBINED2("Food");
  var placeCid = data[4];
  var findText = ss.createTextFinder(placeCid).findAll();
  if(findText.length == 0){
    ss.getRange(ss.getLastRow()+1,1,1, data.length).setValues([data])
  }
} 

您需要明确告诉 google 应用程序脚本该函数是这样的,以便您的函数将在称为 e 的事件对象发生时执行。 您可以在 Simple Triggers

上阅读更多相关信息

预期目标:

如果我的理解正确,对于列 A 中的每个值,您想从地图 API 中检索一些相关数据并将其粘贴到列 B-F如果当前未填充列 E

问题:

  • 您只提供了从第 A 列到 COMBINED2 的最后一个值,但您想遍历第 A 列中的所有值并获取所有这些值的所需信息(只要 Place URL -列 E- 尚未填充)。
  • 如果要避免在 Place URL 未填充时调用地图 API,请使用 TextFinder after 调用地图 API 没有意义;如果这样做,您不会将呼叫限制为 API。如果您只想检查 Place URL 列是否已填充,我建议检查单元格是否为空,如果为空则调用 Maps API。

建议的工作流程:

  • 从 sheet 中检索所有值,不仅包括 A 列,还包括 E 列(出于实际目的,在下面的示例中提取了所有 6 列,因为它可以一次调用完成),使用 Range.getValues().
  • 遍历行(例如,使用 for),并针对每一行检查 E 中的单元格是否已填充。
  • 如果EPlace URL)中的单元格为空,则使用A中的值作为COMBINED2的参数并写入结果dataB-F,正如您目前所做的那样。

代码示例:

function writeToSheet() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const FIRST_ROW = 2;
  const sourceData = sheet.getRange(FIRST_ROW, 1, sheet.getLastRow()-FIRST_ROW+1, 6)
                          .getValues().filter(row => String(row[0]));
  for (let i = 0; i < sourceData.length; i++) {
    const sourceRow = sourceData[i];
    if (sourceRow[4] === "") {
      const text = sourceRow[0];
      const data = COMBINED2(text);
      sheet.getRange(FIRST_ROW+i, 2, 1, data.length).setValues([data]);
    }
  }
}

更新:

对于地点 API 中没有的名称 return opening_hours,考虑先检查它是否存在:

function COMBINED2(text) {

  // ... REST OF YOUR FUNCTION ...

  var weekdays = '';
  if (place.opening_hours && place.opening_hours.weekday_text) {
    place.opening_hours.weekday_text.forEach((weekdayText) => {
      weekdays += ( weekdayText + '\r\n' );
    } );
  }

  var data = [
    place.name,
    place.formatted_address,
    place.formatted_phone_number,
    place.website,
    place.url,
    weekdays.trim()
  ];

  return data;
}