哈囉,我們又見面了,昨天我們介紹了爬蟲,爬到指定的 Youtuber 訂閱數,今天來把這功能串到 Line 的聊天機器人吧!
(這一篇還沒有要上架到 GAE,那是下一篇的事情,這篇先把 django 開在本地端就好)
在 Day23 的最後,我們創建了一個叫做 linebot
的 django 專案,裡面有 webhook
和 crawler
兩個 app,顧名思義,其中的 webhook
app,就是要跟 line
做結合的 app,而 crawler
app 就是用來取得資料並回傳給 webhook
app 的。
這時候的專案架構應該長這樣
linebot (project dir)
├ linebot (project settings)
├ webhook (app)
├ crawler (app)
└ manage.py
這篇會直接串接昨天的爬蟲,對於第一次搭建 Line Chatbot 的捧油們會有點吃力,你可以參考 手把手教你搭建聊天機器人(LineBot+Python+QnAMaker+Heroku)-02建造LineBot Backend Server 並部署至Heroku 的 EchoBot 部分,這篇也是用 Django 做的,跟我們不同的地方是,它把 server 放到 Heroku,我們是放到 GAE,但在今天的篇幅中,不會提到部屬到雲端。
Line Developer
、創建一個 Messaging API Channel
在 Line Developer 詳細的申請、創建過程,可以參考 LineBot+Python,輕鬆建立聊天機器人,這一篇它是用 Flask 框架所做的,Flask
是個輕量級的 Python Web Framework,很適合拿來搭建聊天機器人這類輕量的應用,但我們已經用了 Django 一段時間,所以就試試看用 Django
來架聊天機器人囉~
你要能進到你的 Channel 設定頁面,確認三點
channel secret
、webhook settings
、channel access token
三個欄位Use webhook
這個欄位是有開啟的Auto-reply messages
這個欄位是關閉的確認完以上三點後,就可以進行到下個環節。
到目前為止,你已經可以在 Messaging API
分頁,透過 Bot basic ID
或 QR code
,在 line 加 chatbot 好友,可是現在 chatbot 什麼功能都沒有,我們就來想辦法讓它有功能。
linebot
串到自己的 django server這句話的意思是
將使用者對 linebot 所說的話,導向你的 django server,這樣就可以在 django 端,寫下你要處理的邏輯。
在 Line Chatbot,就是透過 Webhook url
串到你的 django server 所在地,你可以把 webhook 想像成一個雙頭鉤,勾住 server 和 line 兩端,這樣就搭建起兩端溝通的橋樑了 !
Webhook url
?我一開始聽到 Webhook 的時候,就聽的霧沙沙,不能理解這是什麼鬼東東,但其實就是你 server 所在的網址,也或許是你的 server 的 IP,那麼你可能會想問,如果我的 server 架在我的電腦上,沒有固定 IP 也沒有網址,這樣該怎麼辦 ?,這時候就會想起在 Day16 所提到的 ngrok 啦 ! 它可以把你電腦的某個 port 開出來,而且最重要的是,有支援 SSL,也就是 https,因為 line 的 webhook 只支援 https。
ngrok
生成 webhook url
詳細的使用方法,參考 Day16。
$ ngrok http 8000
(代表開放出 8000
的 port)
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account rongson (Plan: Free)
Version 2.3.35
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://xxx.ngrok.io -> http://localhost:8000
Forwarding https://xxx.ngrok.io -> http://localhost:8000
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
其中 xxx 是每次重開 ngrok
都會隨機產生,而上面這段 https://xxx.ngrok.io
就是你的 webhook url
先把 https://xxx.ngrok.io
這串複製下來,再回到瀏覽器的 Line Developer 的 Channel 頁面
,Messaging API分頁
的 Webhook url
欄位,你會發現為什麼我在後面加了 /line/
的結尾,因為我們要把 line chatbot 這功能分開,成為這個 server 的一部分,這就是開 API 的藝術的部分了,雖然我這個 API 也沒有開的多好 XD
所以現在 line 會想辦法傳訊息到 https://xxx.ngrok.io/line/
, 但目前我們的 django server 還沒開好,也還沒把 line/
的 API 開出來,所以下階段就來做 django 的部分吧。
Django Server
來跟 LineBot
對接 !Line-Bot-SDK
(venv)$ pip install line-bot-sdk
補充說明,怎麼在
PyCharm IDE
隨著虛擬環境所安裝的套件變化:
也就是說,PyCharm 怎麼知道我安裝了某某套件 ?
.
答案: 在 PyCharm 的File
→Settings
→Project: xxx
→Project Interpreter
→ 點齒輪 →Add...
→Existing Environment
→ 選擇你的虛擬環境中的 Python 執行檔
/line/
的 API 開出來linebot/urls.py
from django.contrib import admin
from django.urls import path
from webhook.views import webhook_view
urlpatterns = [
# 開出 line/ 的 API
# 接著導到 `webhook` app 的 `views.py`
path('line/', webhook_view),
path('admin/', admin.site.urls),
]
經過設定之後,我們就開出了 http://xxx.ngrok.io/line/
的 API,但實際裡面還沒有功能,現在來想辦法收到從 line 過來的訊息吧。
webhook/views.py
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
from django.shortcuts import render
from django.http import JsonResponse
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponseBadRequest
from django.http import HttpResponse
from linebot.models import MessageEvent, TextMessage, TextSendMessage
from django.conf import settings
import os, time
# 呼叫 `crawler` app 的 `crawl_subscribes_of_youtuber` function
# 這部分已經在 day24 做好,參考 https://ithelp.ithome.com.tw/articles/10230271
from crawler.views import crawl_subscribes_of_youtuber
# 等等要在 `linebot/settings.py` 新增:
# ACCESS_TOKEN 和 CHANNEL_SCRET 兩個變數
line_bot_api = LineBotApi(settings.LINE_ACCESS_TOKEN)
handler = WebhookHandler(settings.CHANNEL_SECRET)
# 接收從 `linebot/urls.py` 傳過來的 request 物件
@csrf_exempt
def webhook_view(request):
# 解析 request 的 header 是否包含 Line 的簽名
signature = request.headers["X-Line-Signature"]
# 以 UTF-8 編碼來解析 request body
body_decode = request.body.decode('utf-8')
try:
# 導到 handler 來處理從 line 傳過來的訊息
handler.handle(body_decode, signature)
except InvalidSignatureError:
return HttpResponseBadRequest
return HttpResponse("OK")
# 實際處理從 line 過來的訊息的地方
@handler.add(event=MessageEvent, message=TextMessage)
def handle_message(event: MessageEvent):
# 呼叫 `crawler/views.py` 內
# 的 `crawl_subscribes_of_youtuber` function
result = crawl_subscribes_of_youtuber(event.message.text)
# 將爬蟲的結果,以 Line 純文字的訊息,回傳回去給使用者
line_bot_api.reply_message(
reply_token=event.reply_token,
messages=TextSendMessage(text=result)
)
settings.py
...
LINE_ACCESS_TOKEN = "xxxxxxxxxxx...xxxxxxx"
CHANNEL_SECRET = "yyyy...yyyy"
...
這兩個變數,可以從 Line Channel 的 Messaging API
裡的 Channel access token
找到;還有從 Line Channel 的 Basic Settings
的 Channel secret
找到。
到這邊,Django
的部分已經結束了
(venv)$ python manage.py runserver 127.0.0.1:8000
(因為我們的 ngrok 是開在 8000,所以在跑 django 的時候,還是指定 port 比較保險)
做到這邊,應該要可以通了,如果沒有,那回去確認每個環節有沒有出錯,可能出錯的環節會有
webhook
沒串起來: ngrok
沒啟動、Line Channel 的 Webhook
沒正確設定crawler
app 的 code 有錯line/
API 沒有成功導向 webhook/views.py
settings.py
): allow_hosts
、installed_app
、acesstoken
、channel secret
要把實作的細節重現,還有用稍微白話一點的語句,來解釋每一個動作,真的很花時間,還以為可以在空出更多時間做其他事,沒想到我錯了 QQ
有人可能會想問我為什麼不放到 Heroku
,其實我一開始就是放 Heroku
,可是放上去之後,爬蟲被防火牆擋住了,可能是太多人把爬蟲放到 Heroku
,直接被當成黑名單之類的,後來改放 GAE
就沒問題可以直接跑。
老話依舊,這篇文章沒有詳細到,可以讓第一次接觸的人們,直接照著我的步驟完成,其中隱藏了一些繁瑣的細節觀念,但可以給閱讀的你們實作的大方向,希望對你們有幫助,如果需要各項細節可以留言告訴我。
阿,這禮拜假日放假兩天XD
我是 RS,這是我的 不做怎麼知道系列 文章,我們 下週一見。