본문 바로가기
PC/Software

Google Apps Script 를 이용한 텔레그램 봇

by 천경지위 2022. 6. 7.

텔레그램 봇을 활용하면 여러가지 상황에 응용이 가능합니다. 

메시지 주고 받는 기본기능부터 다양한 기능들을 추가함으로써 다양한 업무에 활용이 가능할것으로 기대됩니다. 

 

#1. 텔레그램 봇 (Telegram Bot) 생성

 

텔레그램 접속한 상태에서 @BotFather를 찾아 채팅상대를 추가 합니다. 

 

간단한 안내 메시지를 보시고 /start 명령을 입력 BotFather를 시작합니다. 

 

여러가지 명령어를 안내해줍니다만.... 

새로운 봇 생성 명령 /newbot 을 입력 하여, 봇 생성을 진행합니다.

Alright, a new bot. How are we going to call it? Please choose a name for your bot.  새로운 봇의 이름을 입력해달라는 메시지가 나오면 적당한 이름을 입력하시면 됩니다. 추후에 수정 가능하므로 적당한 이름을 입력해주시면 됩니다. 

 

Good. Now let's choose a username for your bot. It must end in `bot`. Like this, for example: TetrisBot or tetris_bot. tetris_bot과 같이 끝에 bot으로 끝나는 봇 이름(아이디)를 입력해달라는 메시지가 나오면 다른사람들이 사용하지 않는 이름을 영문으로만 입력하시면 됩니다.  나중에 채팅 봇을 추가할때 사용하는 이름이며, 변경이 불가능하므로 잘 선택하여 입력하시면 봇 생성이 완료 됩니다. 

 

여기까지 정상적으로 진행하셨으면 Done! Congratulations on your new bot. 메시지를 시작으로 간단한 설명과 함께 봇 고유 token 이 

5494213205:AAFTNvh4oaOf16Smhce0WreoZv0aWJuf1Ys 

이런식으로 발급되었다고 안내를 해줍니다. 

token을 아래 소스의 #1 token 입력부분에 입력합니다.

 

 

#2. Google Drive 에 접속 Google 스프레드 시트 생성 https://drive.google.com/ 에 접속  좌측 메뉴 상단에 새로만들기 버튼을 누르면 Google 스프레드 시트를 바로 생성할수 있는 메뉴가 보이므로 눌러서 생성하면  https://docs.google.com/spreadsheets/d/1D3H3-NdOtB4BhVXQtaRMyIfcPtEDBLL-rDwewxPeLc4/edit#gid=0  과 같은 주소가 나오며 스프레드 시트가 생성 됩니다.화면 아래쪽에 시트1 의 기본 탭과 함께 + 시트를 추가할수 있는 버튼을 눌러 시트를 추가하면 시트2가 바로 추가되며 옆에 조그만한 삼각형을 눌러 메뉴가 나오면 이름바꾸기를 눌러 tbots 라는 이름으로 변경해줍니다. (대소문자 띄어쓰기 주의 소스와 동일한 이름이어야 동작합니다.) 그리고 A컬럼은 비워주시고 B컬럼은 검색될 단어 C컬럼에는 검색된 단어를 입력하면 답변으로 올 내용을 주욱 입력해주시면 됩니다. 주소창에서 /d/~~~색상이 다른 부분이 해당 시트의 고유 id~~~~/edit  고유아이디 부분만 아래 소스의 #2 아이디 입력하는 부분에 입력합니다.

 

 

#3. Google Drive 에 접속 Google Apps Script 생성 

https://drive.google.com/ 에서  좌측 메뉴 상단에 새로만들기 버튼을 눌러 이번엔 Google Apps Script 를 생성합니다. 

Code.gs 기본 파일이 생성되어 있으며 function myFunction()이 기본으로 되어 있으나 function myFunction() { } 를 모두 지워주신후 아래의 텔레그램 봇 소스를 복사해 붙여 넣어 주세요 ... 

 

우측 상단에 배포 버튼을 눌러 새배포를 선택하면 배포를 할수 있는 창이 뜹니다.  톱니모양을 눌러 웹앱을 선택합니다.

 

설명은 적당히 알아볼수 있는 내용을 넣어주시면 됩니다. 배포할때마다 입력해야 하므로 배포판 기능추가된것등을 간단하게 입력해주시면 해당 배포판을 추후에 확인할때 유용합니다.  액세스 권한이 있는 사용자를 모든 사용자로 선택합니다. 

배포를 눌러 배포를 진행 합니다.  권한을 요청하는 화면이 나오면 액세스 승인을 눌러 계속 진행 합니다.  권한이 있는지 확인하기 위해 해당 구글 아이디 로그인을 진행하며 로그인 하면 Google에서 확인하지 않은 앱이라고 경고창이 뜨면 좌측 하단 고급을 눌러 위험이 발생할지 이해하고 개발자를 신뢰할수 있는 경우에만 계속하라는 경고 문구가 나오며 아래쪽에 (안전하지 않음)을 눌러 계속 진행합니다. 프로젝트에 접근하려한다고 스프레드 시트를 외부에서 수정/생성/삭제 할수 있다는 경고가 나옵니다. 허용을 눌러 진행합니다.  약간 시간이 소요 되며 웹 앱 주소가 뜹니다. https://script.google.com/macros/s/AKfycbx2UfoXXbkUrD6BDcEONipbewrENGvQm8sZtf5m22EYr4OBnerSlFVhQWs2EpRoYR6o/exec  웹앱 주소를 복사해서 아래 소스 #3 whookUrl 입력하는 부분에 복사해서 넣어줍니다.

소스에서  //saveMessage(content); 주석처리된 로그저장을  saveMessage(content); 주석처리를 제거하여 동작하도록 해줍니다. 

저장 해주시고 상단 메뉴에서 setWebHook 을 선택후 실행을 눌러 해당 함수를 수동으로 실행해주시면  실행 로그가 뜨면서 실행이 완료 됩니다.

 

 

const token = '#1에서 생성된 token';
const tbotUrl = 'https://api.telegram.org/bot' + token;
const whookUrl = '#3에서 생성된 배포 주소';
const sheetLogId = '#2에서 생성된 스프레드 시트 웹주소에서 id부분';
const adminChatId = '#4에서 확인한 chat_id';
 
//딱히 필요는 없으나 배포할때 확인용입니다.
function doGet() {
  return HtmlService.createHtmlOutput('Hello');
}
 
// 텔레그램에서 입력하면 처리하는 부분입니다.
function doPost(e) {
 
  let content  = JSON.parse(e.postData.contents);
// content 로그 저장 필요시 초기에 chatId 확인해야 해서 필요합니다만 봇 완성후는 여러가지 명령어 세팅등으로 보다 편한 대체방법이 많겠습니다.
// saveMessage(content);
 
// 관리자일때만 reply 메시지 전송 
  if (content.message.chat.id == adminChatId && content.message.reply_to_message != undefined) {
     let payload = {
        method: 'sendMessage',
        chat_id : content.message.reply_to_message.forward_from.id,
        text : 'reply : '+content.message.text
     }
     send(payload);
     return HtmlService.createHtmlOutput();
  }
 
  // 메시지를 띄어쓰기에따라 분할 처리하기위한부분이므로 불필요하신분들은 3줄 제거하면서 변수만 맞춰주시면 됩니다.
  var temp3 = content.message.text.split(' ');
  var temp2 = temp3[0].split('/');
  var temp1 = temp2[0] ? temp2[0] : temp2[1];
 
// 스프레드 지정된 시트 불러오기
  let file = SpreadsheetApp.openById(sheetLogId);
  var sheet = file.getSheetByName("tbots");
  var textFinder = sheet.createTextFinder(temp1).matchEntireCell(true);
//  range 지정이 안되어 있어서 sheet 전체에서 검색됨
// .matchEntireCell(true); // 셀전체가 일치할때 셀일부만 검색 가능 하려면 제거, 
// .matchCase(true); // 대소문자 구분
// .matchFormulaText(ture)  // 수식을 검색해야 할때
// .ignoreDiacritics(ture) // 부호를 검색해야 할때
 
  var temp4 = textFinder.findNext();    
 
  if (temp4 == null ) {
// 검색결과가 없을때 관리자에게 전송
              payload = {
                method: 'forwardMessage',
                chat_id : adminChatId,
                from_chat_id : content.message.from.id,
                message_id : content.message.message_id
              };
              send(payload);
  } else {
// 검색결과가 있을때 C컬럼 내용을 유저에게 전송
    var temp5 = temp4.getRow();
    var search_row = temp5;
    payload = {
      'chat_id' : content.message.chat.id,
      'text': 'test1:'+search_row+' | '+sheet.setActiveSelection('C' + search_row).getValue()
    }
    sendMessage(payload);
  }
 
  return HtmlService.createHtmlOutput();
       
}
 
// 웹훅주소 등록
function setWebHook() {
  let response = UrlFetchApp.fetch(tbotUrl + '/setWebhook?url=' + whookUrl);
  Logger.log('telegram response status is '+response.getResponseCode());
}
 
// 웹훅주소 등록후 확인용  실행하면 웹훅주소가 정상적으로 등록되었는지 확인할수 있습니다.
function getWebHook() {
  let response = UrlFetchApp.fetch(tbotUrl + '/getwebhookInfo');
  if (response.getResponseCode() == 200) {
    let data = JSON.parse(response.getContentText());
    Logger.log('current webhook url is '+ data.result.url);
  } else {
    Logger.log('telegram response status is '+ response.getResponseCode());
  }
}
 
// 스프레드 시트에 메시지 로그 저장 
function saveMessage(message) {
  let file = SpreadsheetApp.openById(sheetLogId);
  let sheet = file.getSheets()[0];
 sheet.appendRow([ Date(message.message.date) , message.message.chat.id , JSON.stringify(message) ]);
}
 
// 텔레그램 메시지 전송
function sendMessage(payload) {
  let options = {
    'method' : 'post',
    'contentType' : 'application/json',
    'payload' : JSON.stringify(payload)
  }
  return UrlFetchApp.fetch(tbotUrl + '/sendMessage', options);
}
 
async function send(payload) {
  let options = {
    'method' : 'post',
    'contentType' : 'application/json',
    'payload' : JSON.stringify(payload)
  }
  return Promise.race([UrlFetchApp.fetch(tbotUrl + '/', options)]);
}

 

#4. 텔레그램 Admin ID 등록 

이제 텔레그램에 접속하여 아까 #1에서 생성한 텔레그램 봇 이름(아이디)를 찾아 대화상대로 추가합니다. 

대화창에서 시작을 눌러 봇 기동을 시작 한후 적당히 아무 내용이나 입력 전송하면  #2에서 생성한 스프레드 시트의 시트1에 로그가 기록 됩니다.  (#3에서 주석처리되었던걸 // 주석처리를 삭제하여 해당 구문이 실행되도록 하셨을때만 입력됩니다.)  

로그에서 전송받은 JSON데이터를 확인하실수 있습니다. message 에 from 에 id를 찾아 보시면 숫자로된 고유번호가 지금 발송한 텔레그램 아이디의 고유번호이므로 이숫자를 위 소스 #4 adminChatid 의 chat_id 입력 부분에 입력해주신후 #3에서 했던 배포 과정을 다시해주시면 됩니다.  Apps Script 소스를 변경하신후에는 매번 배포버튼을 눌러 새 배포를 해준후에 나오는 변경된 웹 앱 URL을 복사해서 소스의  whookUrl 에 입력해준후 setWebHook 을 수동으로 실행해주어야만 변경된 소스가 적용된 주소가 텔레그램 봇과 연동되어 정상적으로 동작하게 됩니다. 

 

 

스프레드 시트의 시트1에 로그가 기록되는 양이 많아 귀찮아 지는 경우 // saveMessage(content); 다시 주석처리하여 로그 기록을 중단하실수도 있습니다. (물론 배포 - whookUrl 변경 - setWebHook 실행) 이건 소스가 변경될때마다 해줘야 하는 귀찮음은 있으나 별다른 서버를 두지 않고 텔레그램 봇을 운영할수 있다는 매력이 있습니다. 

스프레드 시트 tbots 에 입력하는 내용을 검색후 답변할 내용을 실시간으로 적용할수 있습니다.

배포만 하는경우 배포가 많이 쌓여 시스템이 느려지는 악형향이 있을수 있고, 기존 사용하지 않는 코드가 살아있어서 추후 문제가 될 경우가 생기므로  배포관리에서 사용하지 않는 배포판들은 보관처리하여  구버전의 웹앱 구동을 막아 여러가지 문제가 발생하는걸 방지하시길 권해드립니다. 

 

 

 

 

좀더 기능을 추가한다면 여러가지 업무에 도움이 될듯하며, 여러방향으로 발전할 가능성이 많을듯 합니다. ^^; 

 

댓글