通过VK API,Tampermonkey和Telegram机器人将音乐团体智能添加到Google Sheets

如何在多个程序的支持下组织Google表格中的音乐存储?


给定:Google,VK,Telegram中的帐户。
任务:创建音乐组的存储库,以方便补充。
工具:Google Apps脚本(GAS),VK API,Tampermonkey,Telegram Bot API。

创建Google表格


创建一个新的Google表格。

我们创建一个固定的标头(由于这个原因,所有枚举像元的周期将不是从0开始,而是从1开始)。

原则上,我们的模板已准备就绪。

唯一的是,我没有通过名称绑定到列(我不想使用循环),因此在整个脚本中,我将引用硬连接的列号。

单击“工具-脚本编辑器”。



2创建一个脚本:Kod.gsBot.gs

代码
access_token = '1111111111' // VK token
ss = SpreadsheetApp.getActiveSpreadsheet() // 
sheet = ss.getSheets()[getNumSheet('')] // 
data = sheet.getDataRange().getValues() //  
numRows = sheet.getLastRow()+1 //  
faveTag = '.' //    

//   get 
function doGet(e) {
try {
    var link = e.parameters['link']
    /*
      A - 
      B - English
      C - 
      D - 
      E - 
      F - 
      G - 
    */
    var n = searchExists(link)
    if (n != false) return ContentService.createTextOutput(' '+n+'  !')
    //   API VK https://vk.com/dev/groups.getById
    var html = UrlFetchApp.fetch('https://api.vk.com/method/groups.getById.json?group_id='+link+'&fields=city,description&access_token='+access_token+'&v=5.107')
    //   json   response
    var json = JSON.parse(html).response[0]
    addInTableFromArray(json, link)
    sort()
    return ContentService.createTextOutput('')
  } catch (e) {
     return ContentService.createTextOutput('   doGet! '+e)
  }
}

//  /     
function searchGenre(txt) {
  var t = txt.match(/(?:(?:[||||]|genre|[|||]?)[\s:-]+){1}([a-z-\/-]+)/i)
  if(txt != '' && t) return t[1]
}

//     
function isRus(txt) {
  return txt.search(/[^A-Za-z0-9\/.:_]+/i)
}

// 
function sort(){
  //         
  var tableRange = "A2:G"+numRows
  var editedCell = sheet.getActiveCell()
  var range = sheet.getRange(tableRange)
  //     .    0,   1
  range.sort([{ 
    column : 4,
    ascending: true
  },{
    column: 1,
    ascending: true
  },{
    column: 2,
    ascending: true
  }])
}

//   
function searchExists(t) {
  for (var i = 1; i < data.length; i++) {
    if (t == data[i][2] || 'club'+t == data[i][2]){
      return data[i][0]+data[i][1]
    }
  }
  return false
}

//      
function addInfo(isBot = false) {
  var arr = []
  var j = 0
  var part = 1000 // - ,      . -      UrlFetchApp.fetch
  arr[j] = new Array()
  for (var i = 1; i < data.length; i++) {
    var txt = data[i][2].replace('https://vk.com/','').replace('vk.com/','').replace('^club','')
    if (txt != '' && data[i][0] == '' && data[i][1] == '' && data[i][3] == '' && data[i][4] == '' && data[i][5] == '' && data[i][6] == ''){
      arr[j].push(txt)
      if (arr[j].toString().length > part){
        j++
        arr[j] = new Array()
      }
    }
  }
  if (arr[0].length == 0){
    if (isBot) return false
    else{
      SpreadsheetApp.getUi().alert(' ,   ')
      return false
    }
  }
  //   
  for (var t = 0; t < Math.ceil(arr.toString().length/part); t++) {
    var html = UrlFetchApp.fetch('https://api.vk.com/method/groups.getById.json?group_ids='+arr[t].toString()+'&fields=city,description&access_token='+access_token+'&v=5.107')
    var json = JSON.parse(html).response
    if(json){
      for (var i = 0; i < json.length; i++) {
        var id = json[i].id
        var link = json[i].screen_name
        var name = json[i].name
        var description = (json[i].description)?json[i].description:''
        var city = (json[i].city)?json[i].city.title:''
        var rus = (isRus(name) != -1)?"A":"B"    
        //         arr
        for (var j = 1; j < data.length; j++) {
          var nameCell = data[j][2].replace('https://vk.com/','').replace('vk.com/','').replace('^club','')
          if (nameCell == link || nameCell == id){
            var num = j+1
            break
          }
        }
        sheet.getRange(rus+num).setValue(name.replace('=',''))
        sheet.getRange("C"+num).setValue('=HYPERLINK("https://vk.com/'+link+'";"'+link+'")')
        sheet.getRange("D"+num).setValue(city)
        sheet.getRange("E"+num).setValue(searchGenre(description))
        sheet.getRange("F"+num).setValue(description)
      }
    }
  }
  sort()
  return true
}

//     
function getVkFave(isBot = false) {
  var idTag
  var getTags = UrlFetchApp.fetch('https://api.vk.com/method/fave.getTags.json?access_token='+access_token+'&v=5.107')
  var res = JSON.parse(getTags).response
  var iTag = res.items
  for (var i = 0; i < iTag.length; i++) {
    if (iTag[i].name == faveTag) idTag = iTag[i].id
  }
  
  // 
  if (!isBot){
    var ui = SpreadsheetApp.getUi()
    var resp = ui.alert('     "'+faveTag+'"     . ?', ui.ButtonSet.YES_NO)
  }
  var inside = function (){
    var getPages = UrlFetchApp.fetch('https://api.vk.com/method/fave.getPages.json?tag_id='+idTag+'&fields=city,description&access_token='+access_token+'&v=5.107')
    var iPage = JSON.parse(getPages).response.items
    //    .   ,   
    for (var j = 0; j < iPage.length; j++) {
      var gr = iPage[j].group
      addInTableFromArray(gr)
      numRows++
        UrlFetchApp.fetch('https://api.vk.com/method/fave.removePage?group_id='+gr.id+'&access_token='+access_token+'&v=5.107')
        Utilities.sleep(1000) // 
    }
    sort()
  }
  if (isBot) { // ,      ui
    inside()
  }else if(resp == ui.Button.YES) {
    inside()
  }
}

//    
function addInTableFromArray(arr, linkIn) {
  if (linkIn){
    var link = linkIn
  }else{
    var link = arr.screen_name
    if (searchExists(link) != false) return false
  }
  var name = arr.name // 
  var description = (arr.description)?arr.description:'' //
  var city = (arr.city)?arr.city.title:'' // 
  //      ,      "English"
  var rus = (isRus(name) != -1)?"A":"B"
  //    
  sheet.getRange(rus+numRows).setValue(name.replace('=',''))
  sheet.getRange("C"+numRows).setValue('=HYPERLINK("https://vk.com/'+link+'";"'+link+'")')
  sheet.getRange("D"+numRows).setValue(city)
  sheet.getRange("E"+numRows).setValue(searchGenre(description))
  sheet.getRange("F"+numRows).setValue(description)
}
//  . .
function checkActualLink(){
  for (var i = 1; i < data.length; i++) {
    try {
      var num = i+1
      UrlFetchApp.fetch("https://vk.com/"+data[i][2])
      sheet.getRange('C'+num).setBackgroundColor('')
    }catch(err) {
      var num = i+1
      sheet.getRange('C'+num).setBackgroundColor('red')
    }
  }
}
//  URL  .     
function getStatusUrl(url){
   var options = {
     'muteHttpExceptions': true,
     'followRedirects': false
   }
   var response = UrlFetchApp.fetch(url.trim(), options)
   return response.getResponseCode()
}
//    
function getNumSheet(nameList){
  var s = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(nameList)
  if (s != null) {
    return s.getIndex()-1
  }else{
    return false
  }
}
// 
function escapeHtml(text) {
  return text
      .replace(/&/g, "")
      .replace(/</g, "")
      .replace(/>/g, "");
}
// 
function onOpen() {
  SpreadsheetApp.getUi()
  .createMenu(' ')
  .addItem('', 'sort')
  .addItem('   ', 'getVkFave')
  .addItem(' ', 'addInfo')
  .addToUi();
}

//   
function ll(t){
  return Logger.log(t)
}


机器人
var botApi = 'https://api.telegram.org/bot1123123:AAA/' //  Telegram  
/* :
 /start -   
 /sort - 
 /getvkfave -     
 /addinfo -  
 /getall -   
*/
function doPost(e){
  var inp = JSON.parse(e.postData.contents)
  // 
  var sheet2 = ss.getSheets()[getNumSheet('')]
  sheet2.getRange('A1').setValue(inp)
  
  var inpTxt = inp.message.text
  var chatId = inp.message.chat.id
  
  var link = inpTxt.replace('https://vk.com/','').replace('vk.com/','').replace('^club','')
  //  
  // start
  if (inpTxt == '/start' || inpTxt == ' '){
    sendText(chatId, '      Google .\n'+
                    '/start -   \n'+
                    '/sort - \n'+
                    '/getvkfave -    \n'+
                    '/addinfo -  \n'+
                    '/getall -   ')
    return true
  }
  // sort
  if (inpTxt == '/sort' || inpTxt == ''){
    sort()
    sendText(chatId, '')
    return true
  }
  // getvkfave
  if (inpTxt == '/getvkfave' || inpTxt == '   '){
    getVkFave(true)
    sendText(chatId, '')
    return true
  }
  // addinfo
  if (inpTxt == '/addinfo' || inpTxt == ' '){
    if (addInfo(true)) sendText(chatId, '')
    else sendText(chatId, ' ,   ')
    return true
  }
  // getall
  if (inpTxt == '/getall' || inpTxt == '  '){
    var arr = [[],[],[],[],[],[],[],[],[],[],[' ']] // TODO 
    var repeat = ''
    var n = 0
    var j = 0
    for (var i = 1; i < data.length; i++) {
      if (j == 4){ //    
        n++
        j = 0
      }
      if (repeat != data[i][3]){
        arr[n][j] = data[i][3]
        if (data[i][3] == '') arr[n][j] = '---'
        j++
      }
      repeat = data[i][3]
    }
    var key = JSON.stringify({keyboard: 
                              arr,
                              resize_keyboard:true,
                              one_time_keyboard:true
                            });
    sendText(chatId, ' ', key)
    return true
  }
  
  // 
  if (isRus(link) != -1) {
    var name = (inpTxt == '---')?' ':inpTxt
    for (var j = 1; j < data.length; j++) {
      if (data[j][3] == inpTxt || inpTxt == '---') {
        var str = ' '+name+'\n\n'
        for (var i = 1; i < data.length; i++) {
          if ((data[j][3] == data[i][3]) || (data[i][3] == '' && inpTxt == '---')) {
            if (str.length >= 4000) { //   -    Telegram 
              sendText(chatId, str)
              str = ''
            }
            str = str + '<a href="https://vk.com/' + data[i][2] + '">' + escapeHtml(data[i][0] + data[i][1]) + '</a> \n'
          }
        }
        if (str != '') sendText(chatId, str)
        return true
      }
    }
    sendText(chatId, inpTxt + ' -   .    ')
    return true
  }
  //   
  if (getStatusUrl('https://vk.com/'+link) != 200 && getStatusUrl('https://vk.com/club'+link) != 200){
    sendText(chatId, inpTxt+' -  ')
    return true
  }
  
  var name = searchExists(link)
  if (name != false){
    sendText(chatId, ' '+name+'  ')
    return true
  }else{
    var html = UrlFetchApp.fetch('https://api.vk.com/method/groups.getById.json?group_id='+link+'&fields=city,description&access_token='+access_token+'&v=5.103')
    var json = JSON.parse(html).response[0]
    addInTableFromArray(json, link)
    sort()
    sendText(chatId, ' '+json.name+' ')
    return true
  }
}
//  
function sendText(chatId, text, key = ''){
  var payload = {
    'method': 'sendMessage',
    'chat_id': String(chatId),
    'text': text,
    'parse_mode': 'HTML',
    'reply_markup': key,
    'disable_web_page_preview': true,
    'one_time_keyboard':true
  }     
  var data = {
    "method": "post",
    "payload": payload
  }
  //    UrlFetchApp.fetch   ll(text)
  UrlFetchApp.fetch(botApi, data)
}


下面有更多详细信息。

单击“ 发布-部署为Web应用程序”



现在,我们有了一个script.google.com/macros/s/AAA/exec形式的链接,用“ link”参数代替,我们可以将VK组添加到Google Table。

浏览器中的用户脚本


输入数据的首要方式!

打开Goog​​le Chrome浏览器或Mozilla Firefox,然后安装Tampermonkey用户脚本插件。Chrome

链接Mozilla链接 最初使用Greasemonkey,但由于跨浏览器的兼容性不得不切换到Tampermonkey 谁就会有疑问,为什么用户脚本参数与开始GM_前缀,而不是TM_ -这个想法是不是我的,去的文件






我们通过单击第一个带有加号的选项卡来插入vkGroupToGS脚本

vkGroupToGS
// ==UserScript==
// @name         vkGroupToGS
// @namespace    https://vk.com/*
// @version      0.1
// @author       You
// @match        https://vk.com/*
// @grant        GM_xmlhttpRequest
// ==/UserScript==
    var url_first = 'https://script.google.com/macros/s/AAA/exec'
    var url_short = document.location.href.replace("https://vk.com/", "")
    var d = document.createElement('div')
    var head = document.querySelector('.left_menu_nav_wrap')
    d.setAttribute('id', 'send_group')
    d.style.display = 'inline-block'
    d.style.position = 'relative'
    d.style.fontSize = '50pt'
    d.style.cursor = 'pointer'
    d.innerHTML = '+'
    head.parentNode.appendChild(d)
    d.onclick = function() {
    setTimeout(function() {
        GM_xmlhttpRequest({
            method: 'GET',
            url: url_first + '?link=' + url_short,
            headers: {
                'Accept': 'application/atom+xml,application/xml,text/xml'
            },
            onload: function(x) {
                console.log(x.responseText)
                if (//.test(x.responseText)) document.querySelector('#send_group').style.color = 'red'
                else document.querySelector('#send_group').style.color = 'green'
            }
        })
    }, 0)
};


“文件-保存。”


如您所见,我们的脚本在左侧的left_menu_nav_wrap块中绘制了一个加号(足以想象)


通过点击加号,GM_xmlhttpRequestvkGroupToGS执行在我们的脚本Code.gs使用谷歌表链路连接上述(url_first)。

Tampermonkey会要求我们将这两个脚本与权限相关联,对于“ script.google.com,单击“ 始终允许 ”或“ 始终允许域 ”。根据需要重复“ script.googleusercontent.com ”。


一旦请求成功飞走了,从回调GM_xmlhttpRequest和颜色的纽扣绿色在成功添加或红色如果错误再次出现。

加上Tampermonkey-在具有生育力和想象力的情况下,在Google中基于云的脚本存储(以前不是)。

返回Google表格。

在开始解析我们的Code.gs之前我想共享VK中用于开发的文档-vk.com/dev

VK令牌


获取访问密钥
,向VKontakte API发出请求

到目前为止,我仅学习了一种通过自编写应用程序获取令牌的方法。

我们来这里
平台-“ 独立应用程序 ”。
创建后,我们需要的只是一个应用程序ID(现在为7位数字),即1234567。
但是我们需要一个令牌。
关于令牌的很好的内容是在Meet VK API中编写的

如果我们不想阅读,只需您的应用程序ID插入client_id即可打开链接 我们将被重定向到带有铭文的页面:


请不要从第三方网站的地址栏中复制数据。因此,您可能无法访问自己的帐户。

没错,请谨慎使用令牌!

我们在access_token之后从地址栏中复制令牌

我将立即与您分享这个令牌,您可以查询vk.com/dev/groups.search?params%5Bq%5D=%D0%BC%D1%83%D0%B7%D1%8B%D0%BA%D0%B0¶ms %5Btype%5D =页面和参数%5Bcountry_id%5D = 1和参数%5Bcity_id%5D = 1和参数%5Bmarket%5D = 0和参数%5Boffset%5D = 0和参数%5Bcount%5D = 5&params%5Bcount%5D = 5&params%5Bcount%5D

可以安全地转换为链接api.vk.com/method/groups.search?q=%D0%BC%D1%83%D0%B7%D1%8B%D0%BA%D0%B0&type=page&country_id=1&city_id=1&future= 0&market = 0&offset = 0&count = 10&access_token = 1111111111111&v = 5.107并在任何应用程序中接收信息。



我打开了一个小的Pandora盒子,也许这不是新闻,但是通过这种方式,您可以从VK中获得很多有用的东西,使许多过程自动化并做出许多方便的事情。

当然,在一定的限制下,假设响应中的实体不超过999个,或者每秒不超过20个请求,等等。

另外,有人会对播放存储的文件感兴趣-在我们的应用程序中,选项卡“ 存储过程 ”。

它有自己的信息提取规则,这对于顺序查询非常方便,以免在代码中造成很多循环。

跟随版本!

随着它们的改变,方法的功能可能改变。现在我正在5.107版应用示例

因此,我们有了令牌,请转至...

Code.gs

doGet(e) -我们接受来自bot,VK以及来自浏览器的传入get请求。
输入参数被解析为e.parameters ['INPUT_Parameter']
链接到达,检查是否有表。如果没有,请通过groups.getById,parsim,add 请求详细信息

!注意!该脚本很简单,因此它将吞噬所有传入的链接,因此在检查脚本时甚至要小心输入123。

searchGenre-智能搜索组的样式/类型,因此在文章中加了“正则表达式”标签。

改进是可能的。

虽然它仅用于在单词“之后”通过斜杠或连字符搜索后续的单词字符串风格或流派或风格。”

isRus是除俄语字母的简单规则的规则。
排序 -排序我的默认设置为1市,2名。
searchExists -通过一个循环现有组简单的搜索。
ADDINFO -做我自己的脚本,离开了这里,作为奖励。如果您有链接列表,但没有数据,则很有必要。

将列表插入“链接”列中,在主菜单中单击“重新填充为空 ”,剩余的列将从VK中补充。

由于UrlFetchApp中字符数的限制.fetch并放置在地址栏链接的数量不得不做出的1000个字符的周期。

getVkFave-撰写文章时脑海中又出现了另一笔奖金,我本人也开始使用。

最重要的是,我们从电话进入VK应用程序,偶然发现了我们要保存的组,将其保存在预先添加了“ 音乐组标签(全局变量faveTag)的书签中

他们如何累积,转到我们的Google Table,调用菜单,然后单击“ 从VK检索书签 ”。

带有令牌的脚本爬到api.vk.com/method/fave.getTags中,进行解析,然后添加到表中,之前已警告过要从VC中删除该脚本(此处更准确地说,通过测试将所有内容从带有此标记的书签中完全删除)。

getStatusUrlcheckActualLink-产生2个脚本的实验。
底线是检查有效性和对链接的访问。

因为多年来音乐团体的积累,我面临着公共记录被删除或重命名的事实。

我建议谁使用我的方便,TODO,不仅会删除无效的链接,还会通过groups.search按名称检查VK中的存在。

checkActualLink-通过将无效颜色涂成红色来一次性检查有效性。

  • 减号-低速。
  • 另外-您可以在需要时做到。

getStatusUrl-通过脚本在单元格中调用

=getStatusUrl(CONCAT("https://vk.com/";C2))

从这里开始做基础

  • 减号-每次打开页面时对所有单元格运行。
  • — , , checkActualLink.

接下来是Google脚本的便利性:

addInTableFromArray-在表中添加一行。从周期还是一次。
getNumSheet-按名称搜索工作表编号。老实说,我在互联网上找不到比这更简单的方法了。由于添加新的工作表时,工作表号会发生变化。从这里开始做基础
escapeHtml-删除特殊字符
ll - Logger.log本身简称,减少了时间,我建议。
onOpen -Google表格中用于绘制菜单的熟悉功能。

因此,我们的Code.gs会通过Tampermonkey捕获来自VK的链接,并将组添加到Google Table。

开启懒惰


  • 我们坐在电脑旁。
  • 我们坐在电话上。

从计算机上,我们学习了如何通过VK中的“ 加号 ”和书签来添加组
通过电话,只能通过VK应用程序中的书签。

让我们看看另外两个用于分组的选项。

美国大学


移动浏览器中的用户脚本。

在某些人看来,这是过时的和不必要的,但有些人会从中脱颖而出。

到目前为止,在Internet上搜索仅发现了这样的插件
它仅在Firefox中有效(仅在android中经过测试)。

一个巨大的优点-您可以使用Tampermonkey脚本。

由于vk.comm.vk.com之间的布局存在差异,并且由于在m.vk.com中打开了默认窗口,因此没有绘制加号,而是制作了一个简单的脚本VK_event_to_list_mvk,该脚本可以在打开窗口时使用(我正在刻录在地狱的setTimeout,我知道)。

代码
// ==UserScript==
// @name         VK_event_to_list_mvk
// @namespace    https://m.vk.com/*
// @match        https://m.vk.com/*
// @grant    GM_xmlhttpRequest
// ==/UserScript==
setTimeout(function() {
    var url_first = 'https://script.google.com/macros/s/111/exec';
    var url_short = document.location.href.replace("https://m.vk.com/", "");
    GM_xmlhttpRequest({
        method: 'GET',
        url: url_first + '?link=' + url_short,
        headers: {
            'Accept': 'application/atom+xml,application/xml,text/xml'
        },
        onload: function(x) {
            alert(x.responseText);
        }
    });
}, 2000);



电报机器人


我们根据说明创建一个机器人
我们需要一个令牌,让它成为123123。

创建一个Bot.gs脚本,将123123 插入botApi变量,并用引号和api.telegram.org链接对其进行取景

接下来,我们需要将漫游器与Google表格链接。您可以在上一篇文章中了解如何通过WebHook做到这一点

我们的机器人会做什么?

我们通过以下命令分解:

  • /启动-启动机器人
  • /排序-排序
  • / getvkfave-从VK检索书签
  • / addinfo-填空
  • / getall-获取所有群组

我们看到我们是机器人的开始,我们将根据您的判断只插入一个带有描述性部分的教程。

以防万一,从主菜单中输入三个命令。

下一个奖励是/ getall,关于它的信息在下面。

可以通过/ setcommands将方便调用的命令(在消息输入行中写斜线)添加到同一@BotFather中。

格式-破折号行:

start -   
sort - 
getvkfave -    
addinfo -  
getall -   


Bot.gs

的doPost -接受来自机器人传入消息。

自然,作为一个好奇的程序员,我立即开始使用日志。也许有更简单的方法,但是我刚刚创建了一个新工作表,称为“日志”,并且在第一个单元格中捕获了传入的请求。

因此,在通过JSON.parse(e.postData.contents)解析传入消息之后,我们立即将其写入日志。

接下来,我们确定哪个团队来找我们。

如果不是团队,我们将检查有效性,即VK中是否存在一个组。

sendText-将消息发送到机器人(默认为parse_mode = HTML),文档

/ getall-我们将分别对其进行分析

不要害怕我的决定

[[],[],[],[],[],[],[],[],[],[],[' ']]

用来填充城市线,而我们将自己限制在4个城市中的8-10条线(变量j = 4)。

如果音乐组不在城市,请插入---。

只需选择城市,然后在Bot.gs中捕获俄语字母即可

我们显示链接列表,仅此而已。


请记住,通过Hotspot Shield Free VPN代理通过地址栏访问文档和测试bot 是Unlimited VPN(适用于Google Chrome)。

因此,我们学习了三种输入表格的方法:

  • 浏览器中的用户脚本
  • 移动浏览器(USI)中的用户脚本
  • 电报机器人

您需要知道和记住什么?


VK链接中的俱乐部前缀VK

组具有两种类型的标识符存储。

  1. 名称为英文,并带有有效的下划线和连字符。
  2. ID

他们可以提供所有最好的东西,依此类推。

检查很简单。

如果有一个组,例如vk.com/4soulsband,将4soulsband替换为vk.com/dev/groups.getById中的group_ids,则显示参数列表,其中一个参数是ID如果我们将club放在他的面前,瞧,我们将进入同一页面vk.com/club68130764

将VK中的群组存储限制为5000个,

这似乎很荒谬,但是我还不够。



承认不得不更新VK页面,直到我能够克服VK页面之间的过渡问题以重置Tampermonkey中的加号之苦。TODO

将Google表格用作数据库

  • 加号-可用性
  • 减号-累积超过5000行时,使用“ DB ”的速度会减慢因此,对于大型项目,最好使用常规DBMS。

分组城市的定义

VK中的分组地址可以分别在此处vk.com/dev/groups.getAddresses,想要改善对分组城市的搜索的人可以使用它。


我们有:

  1. 我们学会了使用的Google数据收集表。
  2. 了解VK API。也就是说,您已经意识到我们不能局限于音乐团体。
  3. 带有不需要部署和配置的数据库的Telegram Bot。

我的目标不是吹嘘下一个要制造的玩具,我的目标是向(但不仅是)向新手展示巨大的开放API层,这些API可以帮助使生活达到某种程度,可以从铁皮土地迁移到“乌云”。

此功能已准备就绪,可以进行改进。

掌握新知识的发展和运气。

文献资料


Google Apps脚本-电子表格服务
电报Bot API
VK API
了解如何编写用户脚本用户
脚本。
使用Google Docs
Pampering 深化站点监视我们用Google脚本编写Telegram机器人
[示例,Google Apps脚本]开发Google表格(电子表格)的附件/脚本的方法
如何使用Google电子表格来检查断开的链接

All Articles