上篇花了我們費盡心思終於辦理了 Heroku 入厝儀式,您已經有專屬自己的 LINE Chat Bot ,這篇我們把 Heroku 稍作改進,補完獨立管理 token 的兩種方案。
由於程式碼包含帳號資訊有其風險,雖然直接把各種 ID 、 token 貼在程式比較方便,但如果要分享時,譬如把你的大作放在 GitHUB ,建立在公開的雲端服務時,最好獨立為單獨檔案,並且審慎管理上傳。
Python 的 .py 檔案可以做為模組引入程式,以下是很好的範例,也是現階段初學/自學者較建議的方式:
在專案根目錄建立 config.py 檔案,內容如下,記得貼入你的 CHANNEL_ACCESS_TOKEN 及 CHANNEL_SECRET,貼入時成對的單引號(或雙引號)不要拿掉:
#line-bot
channel_access_token = 'YOUR_CHANNEL_ACCESS_TOKEN' 
channel_secret = 'YOUR_CHANNEL_SECRET'
將原本程式新增使用 config 模組,用法是 from config import * ,將程式以下2行內容進行替換:
#原本的
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')
替換為:
#替換的
from config import * 
line_bot_api = LineBotApi(channel_access_token)
handler = WebhookHandler(channel_secret)
最終app.py程式碼調整如下
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__)
#config模組方案
from config import * 
line_bot_api = LineBotApi(channel_access_token)
handler = WebhookHandler(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:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)
    return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    if event.source.user_id =='Udeadbeefdeadbeefdeadbeefdeadbeef':
        return 'OK'
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))
if __name__ == "__main__":
    app.run()
configparser 模組,建立 config.ini檔案(參考)實測偶有狀況但較常見(正確的?)管理方式
config.ini 檔,內容為:
[line-bot]
channel_access_token = 'YOUR_CHANNEL_ACCESS_TOKEN'
channel_secret = 'YOUR_CHANNEL_SECRET'
configparser 模組,將以下原本20、21行內容進行替換:
#原本的
line_bot_api = LineBotApi('YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')
替換為:
import configparser 
config = configparser.ConfigParser()
config.read('config.ini')
line_bot_api = LineBotApi(config.get('line-bot', 'channel_access_token')) #已存於config.ini
handler = WebhookHandler(config.get('line-bot', 'channel_secret'))
requirements.txt 新增 configparser==5.0.0 ,檔案修正如下:
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__)
#config.ini方案
import configparser 
config = configparser.ConfigParser()
config.read('config.ini')
line_bot_api = LineBotApi(config.get('line-bot', 'channel_access_token')) #已存於config.ini
handler = WebhookHandler(config.get('line-bot', '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:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)
    return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    if event.source.user_id =='Udeadbeefdeadbeefdeadbeefdeadbeef':
        return 'OK'
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))
if __name__ == "__main__":
    app.run()
import {模組} 指令有些需要注意的地方,還是花些時間介紹。!pip install --files package_name,等同在CMD下執行令。| 指令 | 功能 | 
|---|---|
pip list | 
看目前系統有安裝哪些套件 | 
pip search {package_name} | 
搜尋相關套件 | 
pip install {package_name} | 
安裝套件 | 
pip uninstall {package_name} | 
移除套件 | 
pip show --files {package_name} | 
秀套件檔案列表 | 
pip list --outdated | 
列出過期套件 | 
pip install --upgrade {package_name} | 
升級套件 | 
from {package_name} import {module_name} as {nick_name}
以下兩者相同,哪種比較好?
from requests import get
res_example = get('http://www.example.com/')
print(res_example.text[:100])
import requests as rs
res_example = rs.get('http://www.example.com/')
print(res_example.text[:100])
大部份時候建議使用import不使用from,環境會比較乾淨。
最髒的是from {package_name} import *,意思是把該模組裡啊撒布魯全都拿來用,變數容易混淆。
本篇的 config.py 作為模組,使用了 from {package_name} import * 全部引入程式中,敢這麼做是因為您自建的 channel_access_token 及 channel_secret 這兩個變數名稱都很獨特,不會與其他變數重複,較不會有弄髒程式變數的問題。
as 為簡稱,簡稱為慣例(慣例有時比官方文件更需要遵守),舉例常用的模組簡稱:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests as rs
例如 import requests as rs ,日後使用 requests.get() 等功能時,可以縮寫為 rs.get() ,真懶。.py 檔案)、引入外部模組 pip install {package_name} 的操作方式。