[Go] Telegram Bot 入門篇

程式語言:Go
Package:github.com/go-telegram-bot-api/telegram-bot-api
官方介紹
官方 API
telegram-bot-api GitHub

功能:Telegram Bot,可透過此介面實現資料的查詢與匯集

申請流程

  1. 私訊 @BotFather 並輸入 /newbot
  2. 輸入 bot 顯示的名稱(後續還可更改)、bot 的 username (必須為 bot 結尾)
  3. 得到 Token (例:12345:ABC_d-6)
  4. 私訊剛建立的 bot:@xxxBot

API Request

  • 格式
    • https://api.telegram.org/bot<Token>/<Method Name>
    • 例如
      • 得到機器人資訊
        • https://api.telegram.org/bot12345:ABC_d-6/getMe
      • 得到接收的訊息
        • https://api.telegram.org/bot12345:ABC_d-6/getUpdates
  • 支援 HTTPS GET 及 POST,四種方式
    • URL query string
      • https://api.telegram.org/bot12345:ABC_d-6/sendMessage?chat_id=109780439&text=Hello+World
    • application/json
    • application/x-www-form-urlencoded
      • 無法上傳檔案
    • multipart/form-data
      • 用來上傳檔案 
  • Response
    • JSON 格式
      • 成功
        • ok = True
        • result = 回覆內容
      • 失敗
        • ok = False
        • error_code
        • description = 錯誤描述
  • Method
    • 無視大小寫
      • getMe 等同 GeTmE
    • 必須使用 UTF-8 編碼
  • 輔助工具

用戶聊天訊息

  • 保存時間
    • 只有 24 小時
  • 兩種獲得方式 ,兩者無法並行使用
    • 設定 Webhook
      • 有新訊息時,Telegram 將會主動告知
      • 需要 HTTPS (TLS 1.0) 伺服器
        並且將埠開在 443, 8443, 80, 8080 其一 (就算 port 80 也要求 TLS)
      • setWebhook 設定伺服器
        • https://api.telegram.org/bot<token>/setWebhook?url=<server> 
        • 留白表示刪除
          • https://api.telegram.org/bot<token>/setWebhook?url=
      • getWebhookInfo 得知設定
        • https://api.telegram.org/bot<token>/getWebhookInfo 
      • deleteWebhook 刪除設定
        • https://api.telegram.org/bot<token>/deleteWebhook
    • 主動詢問
      • getUpdates 請求,將會回傳一個 JSON 陣列
        • https://api.telegram.org/bot<token>/getUpdates
  • 接收模式
    • 隱私模式 Privacy Mode (預設)
      • 由 / 開頭的指令
      • 對機器人 Reply 的訊息
      • 系統訊息 (e.g., 新成員)
      • 自己是管理員的頻道
    • 關閉可收到全部訊息
      1. 私訊 @BotFather
      2. 輸入 /setprivacy 指令
      3. 選擇 Bot
      4. 點擊 Disable

程式碼

不同傳送訊息的方法,需設定 token & chat_id
  1. package main
  2.  
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io/ioutil"
  8. "net/http"
  9. "net/url"
  10. )
  11.  
  12. type APIResponse struct {
  13. Ok bool `json:"ok"`
  14. Result json.RawMessage `json:"result"`
  15. ErrorCode int `json:"error_code"`
  16. Description string `json:"description"`
  17. }
  18.  
  19. type TeleBot struct {
  20. token string
  21. }
  22.  
  23. const (
  24. apiURL = "https://api.telegram.org/bot%s/%s"
  25. token = "your token"
  26. )
  27.  
  28. var (
  29. bot = TeleBot{token}
  30.  
  31. // 執行 sendMessage API
  32. paras = map[string]string{
  33. "chat_id": "your chatID",
  34. "text": "",
  35. }
  36. )
  37.  
  38. // get 方法
  39. func (t *TeleBot) get(method string, paras map[string]string) ([]byte, error) {
  40. paras["text"] = "get"
  41. // 建立 request
  42. urlrequest := fmt.Sprintf(apiURL, t.token, method)
  43. req, err := http.NewRequest("GET", urlrequest, nil)
  44. if err != nil {
  45. return nil, err
  46. }
  47.  
  48. // 加入參數
  49. q := req.URL.Query()
  50. for key, value := range paras {
  51. q.Add(key, value)
  52. }
  53. req.URL.RawQuery = q.Encode()
  54.  
  55. fmt.Println("Get", req.URL.String())
  56.  
  57. // 執行 request
  58. rsp, err := http.DefaultClient.Do(req)
  59. if err != nil {
  60. return nil, err
  61. }
  62. defer rsp.Body.Close()
  63.  
  64. // 讀取內容
  65. data, err := ioutil.ReadAll(rsp.Body)
  66. if err != nil {
  67. return nil, err
  68. }
  69.  
  70. return data, err
  71. }
  72.  
  73. // post x-www-form-urlencoded 方法
  74. func (t *TeleBot) postXW(method string, paras map[string]string) ([]byte, error) {
  75. paras["text"] = "post x-www-form-urlencoded"
  76. // 建立 request
  77. urlrequest := fmt.Sprintf(apiURL, t.token, method)
  78. fmt.Println("Post", urlrequest)
  79.  
  80. // 加入參數
  81. payload := url.Values{}
  82. for key, value := range paras {
  83. payload.Add(key, value)
  84. }
  85.  
  86. // 執行 request
  87. rsp, err := http.PostForm(urlrequest, payload)
  88. if err != nil {
  89. return nil, err
  90. }
  91. defer rsp.Body.Close()
  92.  
  93. // 讀取內容
  94. data, err := ioutil.ReadAll(rsp.Body)
  95. if err != nil {
  96. return nil, err
  97. }
  98.  
  99. return data, err
  100. }
  101.  
  102. // post json方法
  103. func (t *TeleBot) postJSON(method string, paras map[string]string) ([]byte, error) {
  104. paras["text"] = "post json"
  105.  
  106. // 建立 request
  107. urlrequest := fmt.Sprintf(apiURL, t.token, method)
  108. fmt.Println("Post", urlrequest)
  109.  
  110. // 建立 json
  111. payload, err := json.Marshal(paras)
  112. if err != nil {
  113. return nil, err
  114. }
  115.  
  116. // 執行 request
  117. rsp, err := http.Post(urlrequest, "application/json; charset=utf-8", bytes.NewBuffer(payload))
  118. if err != nil {
  119. return nil, err
  120. }
  121. defer rsp.Body.Close()
  122.  
  123. // 讀取內容
  124. data, err := ioutil.ReadAll(rsp.Body)
  125. if err != nil {
  126. return nil, err
  127. }
  128.  
  129. return data, err
  130. }
  131.  
  132. func (t *TeleBot) decodeJSON(data []byte, container interface{}) error {
  133. err := json.Unmarshal(data, container)
  134. if err != nil {
  135. return err
  136. }
  137.  
  138. return nil
  139. }
  140.  
  141. func showResponse(data []byte) {
  142. // 解析 response
  143. var apiResponse APIResponse
  144. err := bot.decodeJSON(data, &apiResponse)
  145. if err != nil {
  146. panic(err)
  147. }
  148.  
  149. fmt.Printf("OK:%v\n", apiResponse.Ok)
  150. }
  151.  
  152. func sendMessage_byGet() {
  153. data, err := bot.get("sendMessage", paras)
  154. if err != nil {
  155. fmt.Println(err)
  156. return
  157. }
  158.  
  159. showResponse(data)
  160. }
  161.  
  162. func sendMessage_byPostXW() {
  163. data, err := bot.postXW("sendMessage", paras)
  164. if err != nil {
  165. fmt.Println(err)
  166. return
  167. }
  168.  
  169. showResponse(data)
  170. }
  171.  
  172. func sendMessage_byPostJSON() {
  173. data, err := bot.postJSON("sendMessage", paras)
  174. if err != nil {
  175. fmt.Println(err)
  176. return
  177. }
  178.  
  179. showResponse(data)
  180. }
  181.  
  182. func main() {
  183. sendMessage_byGet()
  184. sendMessage_byPostJSON()
  185. sendMessage_byPostXW()
  186. }
  187.  
直接使用套件 tgbotapi,需設定 token
功能:回覆同樣的訊息
  1. package main
  2.  
  3. import (
  4. "log"
  5.  
  6. "github.com/go-telegram-bot-api/telegram-bot-api"
  7. )
  8.  
  9. func main() {
  10. bot, err := tgbotapi.NewBotAPI("your token")
  11. if err != nil {
  12. log.Panic(err)
  13. }
  14.  
  15. bot.Debug = true
  16.  
  17. log.Printf("Authorized on account %s", bot.Self.UserName)
  18.  
  19. u := tgbotapi.NewUpdate(0)
  20. u.Timeout = 60
  21.  
  22. updates, err := bot.GetUpdatesChan(u)
  23.  
  24. for update := range updates {
  25. if update.Message == nil {
  26. continue
  27. }
  28.  
  29. log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
  30.  
  31. msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
  32. msg.ReplyToMessageID = update.Message.MessageID
  33.  
  34. bot.Send(msg)
  35. }
  36. }
  37.  

Webhook
使用 ngrok 測試,並設定 setWebhook
ngrok 只適用在測試,仍需架設伺服器較為穩定,例:GAE、Heroku ...等
ngrok http 5000
https://api.telegram.org/bot<token>setWebhook?url=<ngrok url>
功能:印出收到的訊息
  1. package main
  2.  
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. )
  10.  
  11. type Message struct {
  12. MessageID int `json:"message_id"`
  13. Date int `json:"date"`
  14. Text string `json:"text"` // optional
  15. }
  16.  
  17. type Update struct {
  18. UpdateID int `json:"update_id"`
  19. Message *Message `json:"message"`
  20. }
  21.  
  22. func main() {
  23. http.HandleFunc("/", fooHandler)
  24. log.Fatal(http.ListenAndServe(":5000", nil))
  25. }
  26.  
  27. func fooHandler(w http.ResponseWriter, r *http.Request) {
  28. var update Update
  29. data, _ := ioutil.ReadAll(r.Body)
  30. fmt.Println(string(data))
  31. json.Unmarshal(data, &update)
  32. fmt.Printf("%#v\n", update)
  33. fmt.Printf("%#v\n", update.Message)
  34. }
直接使用套件 tgbotapi 印出收到的訊息,需設定 token 跟 接收網址
  1. package main
  2.  
  3. import (
  4. "log"
  5. "net/http"
  6.  
  7. "github.com/go-telegram-bot-api/telegram-bot-api"
  8. )
  9.  
  10. func main() {
  11. bot, err := tgbotapi.NewBotAPI("your token")
  12. if err != nil {
  13. log.Fatal(err)
  14. }
  15.  
  16. bot.Debug = true
  17.  
  18. log.Printf("Authorized on account %s", bot.Self.UserName)
  19.  
  20. _, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert(<ngrok url>, nil))
  21. if err != nil {
  22. log.Fatal(err)
  23. }
  24. info, err := bot.GetWebhookInfo()
  25. if err != nil {
  26. log.Fatal(err)
  27. }
  28. if info.LastErrorDate != 0 {
  29. log.Printf("[Telegram callback failed]%s", info.LastErrorMessage)
  30. }
  31. updates := bot.ListenForWebhook("/")
  32. go http.ListenAndServe(":5000", nil)
  33.  
  34. for update := range updates {
  35. log.Printf("%+v\n", update)
  36. }
  37. }

參考

python-telegram-bot
Telegram.Bot.申請及Channel使用方式
從零開始的 Telegram Bot
Create a Telegram EchoBot

留言