發表於 聊天機器人 BOTPython教學

【Python】 Line Bot 開發 -3 Flask 與 Line Bot 的異國戀情!

前情提要:

在上一篇裡介紹了常用的 Line Bot Events
那在這一篇裡面我將要跟你們一起一步一步地建立最基本的
Flask server 和 如何用 Flask server 與 Line Bot api 做結合

在接下來的內容中大致有兩大重點:

  • Flask server
  • Flask server 與 Line Bot api 做結合

就讓我們開始動手做吧!!

Getting Your Hands Drity!

Line Bot 系列文章:

因為我發現wordpress好像步行列出同系列的文章
所以這邊幫大家把這系列的都列出來了,這樣大家比較好找~

基本款 Flask Server:

還記得之前有談到 Line Bot接收到指令後會從他的Line server那邊POST一個請求到你設定的Webhook取得之後要做的事,那我們自己設定的Webhook其實就是一個很簡單的網址,一個可以接收他POST過來的資料然後作完處理後再回傳相對應的回應(就是一般所說的API啦XD)

那想要做出這樣的功能就要就要先做出一個簡單且且可以服務的Server

那初學者想要做出一個簡單且且可以服務的Server就要先學會用Flask

那要先學會Flask就要先看Henry Li’s Blog啦XD

廢話不多說了啦  開始做啦

安裝:

pip install flask

這樣就安裝好了呀!

CODE:

做一個Server就只有三個步驟:

  1. Import and Setting
  2. Add View
  3. run server
1. Import and Setting

這裡很簡單,需要宣告一個變數負責掌控server,那在此範例中我將命名為app

from flask import Flask

app = Flask(__name__)

接下來如果需要任何的設定都可以在app.config裡面調整,例如:

app.config["host"] = "0.0.0.0"
2. Add View

在 flask 裡面,你可以使用 app.route(routepath) 這個裝飾氣(decorator)來為你的路徑設定服務的function。

在Python裡面Decorator用的好不好對於一個大Project來說是很重要的

就我的經驗來看它可以把很多功能包裝起來要用時再用decotator來包裝就好,設計得好的話真的非常方便呢!!

@app.route("/")
def root():
    return "Root Page"
3. run server

server的設定差不多完成啦

在Flask系列的套件裡面都是差不多的啟動方法啦

app.run(host, port, ....)

總整理一下

from flask import Flask

app = Flask(__name__)

@app.route("/")
def root():
    return "Root Page"

if __name__ == "__main__":
    app.run("0.0.0.0", 5000, debug=True)

現在你只要在網址列打上 localhost:5000 就可以看到

RootpageExample

這樣我們就成功完成一個簡單的server了~~

Flask server 與 Line Bot api 做結合:

當然你一定要先安裝 Line Bot 相關的套件啦

pip install line-bot-sdk

接下來就是需要 import 和 做 setting 啦!

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')

前面的import 都跟一般的作用一樣,但 line_bot_api 和 handler 又是做什麼用的呢??

line_bot_api  負責 與 Line 本身的API做溝通(就是幫你都做好準備了啦XD)

handler          負責 處理送過來的資料

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
  
  line_bot_api.reply_message(event.reply_token,TextSendMessage(text=event.message.text))

利用 handler.add 這個 function 來包裝裝飾你自己處理 line 回傳的 json 資料

那你可能會問 json 資料長什麼樣子呢? Key 有什麼呢?

答案在這裡~ reference!

在上面的連結裡面有著所有的 官方 line bot api response

至於上面的 MessageEvent 就是 當收到的是文字訊息時,就會啟動

那準備好處理 Event 總要有一個自己的api去接收json吧!!

那就是~

@app.route("/callback", methods=['POST'])

def callback():

    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)
    # handle webhook body

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    return 'OK'

handler.handle(body, signature): 會幫你判斷要用剛剛設定的哪個 event 來作回應

InvalidSignatureError: Line sdk 會檢查你的資料是否正確(用你的CHANNEL_ACCESS_TOKEN)

其實到這邊為止就已經設定好了所有的事件等等的了!

接下來就是做個總整理就可以run啦~

底下範例出處

from flask import Flask, request, abort
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)

line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')

@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))


if __name__ == "__main__":
    app.run()

到這裡大家應該都了解怎麼用自己設計的server與Line Bot API做串接了吧了吧~(?

如果有問題的話也歡迎留言在下方告訴我喔

# ——————————————————————————————————————–

# 距離上一篇好像有點久遠了QAQ,開學後一直很忙都沒什麼上來繼續寫教學

# 最近有些專題部分有點忙到一個段落(??)有空時間就上來繼續發文章吧~~

# 有任何指教或是問題的都可以在下方跟我討論喔!

# ——————————————————————————————————————–

最後一篇沒有意外的話(我沒有加新文章的話)就是要跟大家講解一下幾個常見的Paas伺服器的架設方法了!

到目前為止我們的 Line Bot 都還在本機上面吧!

如果不能放到伺服器上面的話要怎麼跟朋友炫耀你的小機器人呢XD 你說對吧XDDDD

下一篇的重點就是架設伺服器並將你的https webhook設定到line bot中

接著就可以看著他根據你設定的功能對你做回應啦~~~~(灑花~

那我們就下一篇再見吧~掰掰~

# ================================================================

# 2018/03/03 補充
# 看到留言來補充 push 的用法
((還記得在第一篇時我有說到不是每種line bot 都可以用push 的功能嗎?
要照著我說的那樣申請才能使用主動push的功能喔!
其實寫法並不難只要一行就OK了~~

但是 BUT HOWEVER

你一定要指名你要傳給誰喔!!

因為我在這邊採到雷過QAQ

先來show一下寫法吧~

python
line_bot_api.push_message( id, TextSendMessage(text="XD"))

id: 這邊的id 並不是我們line互加好友的那個id喔!

這邊是指line伺服器那邊儲存的喔(room_id, group_id或是一般id都可以)!!

那我們要怎麼拿到呢?

可以用特定的事件來記錄reply的id(會出現在 handle_message 的 event裡面)

這樣就可以主動推波消息出去了~

# ===============================================================

# 2018/04/08 更新
# profile 用法

profile = line_bot_api.get_profile(user_id)

有一個function叫做 get_profile
會回傳一個class,可以用 profile.display_name 來顯示喔!

# ===============================================================

作者:

一位 熱愛資工領域、喜歡好笑事物、偶爾打打網球 的學生 ! For A Better Me!

【Python】 Line Bot 開發 -3 Flask 與 Line Bot 的異國戀情! 有 “ 28 則迴響 ”

    1. Hi,在03/03的回覆中有提到要拿user_id的話要用特定事件回傳的JSON拿喔~
      主動得知用戶的ID目前我是沒有看到這種方法

  1. 我在win10 pip install line-bot-sdk 會安裝不成功,出現一些錯誤訊息
    Building wheels for collected packages: future
    Running setup.py bdist_wheel for future … error
    Failed building wheel for future
    Running setup.py clean for future
    Failed cleaning build dir for future

    1. 您好:
      我貌似有再PTT上面看到類似您的發問
      那邊錯誤訊息比較完整,如果是您的問題的話我就用那邊來回答~
      有看到您是用Anaconda 所以我猜應該是有程式還在使用
      或是
      你可以嘗試看看右鍵點及cmd後使用「以系統管理員執行」因為我記得window會擋這個權限

  2. 您好,我想做個功能:
    在使用者輸入"HI~"之類的問候語,bot的回應能夠先加入使用者名稱在回應"XXX,HI~"
    關於使用者信息是可以取得加上的嗎?

    1. 痾…我失敗了Orz

      elif text =="我":
      profile = line_bot_api.get_profile(user_id)
      message = TextSendMessage(text=profile.display_name)
      line_bot_api.reply_message(
      event.reply_token,
      message)

      錯誤碼是說user_id尚未被定義

  3. 您好~感謝您提供的教學,但我將程式Run起來之後,對LineBOT發送訊息似乎都無法成功打到程式的callback,有去看Line Developer的地方發現有個欄位是設定Webhook URL,不知道是不是這邊沒設定好才沒成功的,請大大指點一二,感恩!!

  4. 您好:
    您的文章讓我受益良多,目前已能正常運行line bot。
    最近看到類似的line bot文章中提到,
    可以使用 heroku logs -tail 指令持續監看服務器的狀況,
    並可以看到 post 過來訊息的內容資料,
    如 hhttps://ithelp.ithome.com.tw/articles/10196544 中所示。
    但我在我們此處練習的架構下,使用 heroku logs -tail 指令,
    卻無法看到如該網址中所演示的 event 資料、 id 、 type 等。
    請問該如何解決這個問題?
    感謝賜教

    1. 您好:
      #抱歉前陣子出國就沒甚麼上來看留言了
      我想您的問題比較有可能跟 stdout 的問題有關
      我建議像是在這種server上面的話
      想要看輸出訊息的話都要用 logging 這個套件比較好喔!
      ex: logging.info(“訊息:{}, 類型{}".format(message, type(message)))

  5. 您好:
    我是透過https://yaoandy107.github.io/line-bot-tutorial/這個網址做出linebot的
    請問如果linebot跟heroku連結後,那要怎麼看到他們的對話紀錄,是http://localhost:5000/callback這個網址嗎?但是它一直出現Method Not Allowed,請問要怎麼解決?

    1. 哈囉!
      對話紀錄嗎….?(我不確定這是否符合Line Bot 的網路規範耶(抖
      不過我可以講一下我想到的方法 哈

      你有兩個問題:
      Q1. 要怎麼看到他們的對話紀錄
      A1. 你要記錄對話的話可以在他們reply(其中一個Event)時利用 callback(就是你的 http://localhost:5000/callback) 接它們的text
      (詳細作法可能要等我最近推甄忙完再上來回了,這也是我比較晚回你的劉炎的原因 sorry….)

      Q2. 一直出現 Method Not Allowed的原因
      A2. 原因是出在這一行 @app.route(“/callback", methods=[‘POST’]) 在這裡只有規定他的溝通方法只有 POST 所以他只能接收callback事件
      你可以改成@app.route(“/callback", methods=[‘POST’, ‘GET’])
      然後在底下加上一行
      if request.method == ‘GET’:
      return ‘you use HTTP GET’
      這樣就不會出現錯誤了喔!

  6. 您好,照著你的範例,已成功work了,(灑花…),我想新增一個功能,不過一直試不成功,馬上就想到來問你了
    我想要的功能是:
    在google文件上創建一個sheet,然後從sheet裡面去撈資料回應給line發話者相對應的回覆,
    期待你更新介紹這個功能

    1. 哈囉! 先恭喜你(灑花~~
      這是一個大回應耶XD
      我應該會做一篇文章專門回復你的問題喔!
      (要等我最近推甄結束,這也是我這段時間不常上來回覆的原因QQ sorry)
      謝謝你的支持喔!! 應該下下下禮拜過後就會常上來發文章了(有點久XD

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料