如何让我的 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 以防有人想和我一起工作。
以下是我可能没有表达清楚的地方。
我希望能够在 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
中的单元格是否已填充。
- 如果
E
(Place URL
)中的单元格为空,则使用A
中的值作为COMBINED2
的参数并写入结果data
列 B-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;
}
我有
该脚本查看 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()
他们注意到
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 以防有人想和我一起工作。
以下是我可能没有表达清楚的地方。
我希望能够在 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
中的单元格是否已填充。 - 如果
E
(Place URL
)中的单元格为空,则使用A
中的值作为COMBINED2
的参数并写入结果data
列B-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;
}