目標

  1. 新增互動功能,例如:推薦景點、美食等
  2. 結合前一章學到各種message回覆形式

推薦景點

這裡我選擇玩全台灣作為景點資訊的提供網站,使用爬蟲方式將全台灣各縣市各景點的資訊爬下來。如scraping.py

import requests
import pandas as pd
import json
from bs4 import BeautifulSoup

def generate_city_json(city = 'keelung'):
    # 抓目標網站html內容
    url = f"https://okgo.tw/buty/{city}.html"
    r = requests.get(url)
    web_content = r.text
    print(web_content) # 可以印出來看看, 會跟從網頁右鍵查看原始碼看到的一樣
    
    # 利用BS4套件解析html結構,讓我們容易查找
    soup = BeautifulSoup(web_content, 'lxml')
    area_set = soup.find_all('ul', class_ ="dot")
    
    # 每個縣市景點,由每一區多個地點組成,每個景點包含名字、連結、簡述
    d = {'name': [], 'link': [], 'description': []}
    for area in area_set:
        d['name'].extend([ele.text.replace('\r\n', '').strip() for ele in area.find_all('span', class_ = 'tooltip')])
        d['link'].extend(['https://okgo.tw/' + ele.attrs['href'].split('/')[1] for ele in area.find_all('a') ])
        d['description'].extend([ele.text.replace('\r\n', '').strip() for ele in area.find_all('p')])

    # 先轉成dataframe在轉成json
    df = pd.DataFrame(d)
    with open(f'{city}.json', 'w', encoding='utf-8') as f:
        f.write(df.to_json())
    
    # 測試反轉換回dataframe是否成功
    with open(f'{city}.json', 'r', encoding='utf-8') as f:
        con = f.read()
        df_new = pd.DataFrame(json.loads(con))
    print(df_new)


if __name__ == "__main__":

    # generate_city_json('keelung')
    for city in ['taipei', 'taoyuan', 'hsinchu', 'miaoli', 'taichung', 'changhua', 'nantou', 'yunlin', 'chiayi', 'tainan', 'kaohsiung', 'pingtung', 'yilan', 'hualien', 'taitung', 'penghu', 'kinmen', 'matsu']:
        generate_city_json(city)

最後爬下來的資料我們整理成dataframe形式:

並且以json檔方式儲存起來,後續只要讀取檔案即可取得各景點資訊和連結了。

Template & QuickReply message

接下來,當使用者輸入「推薦XX景點」XX這裡以基隆為例,可以隨機產生基隆4個景點作為訊息回覆。

我們透過讀取前面爬蟲存下的json檔,包含景點的名稱、連結、簡述,用Buttons template message包裝起來。由於Buttons template限制4個連結物件所以我們採隨機取4個該縣市景點。

def handle_message(event):
    message = event.message.text
    if '推薦基隆景點' in message:
        buttons_template_message = generate_views('基隆景點', 'keelung.json')
        line_bot_api.reply_message(event.reply_token, buttons_template_message)

def generate_views(place, path = 'keelung.json'):
    with open(os.path.join('.', 'viewpoint', path), 'r', encoding='utf-8') as f:
        con = f.read()
        df_new = pd.DataFrame(json.loads(con))
    selected_index = random.sample(range(len(df_new)), 4)
    buttons_template_message = TemplateSendMessage(
        alt_text='Buttons template',
        template=ButtonsTemplate(
            title=place,
            text=df_new.iloc[selected_index[0], 2][:60],
            actions=[
                URIAction(
                    label=df_new.iloc[selected_index[0], 0],
                    uri=df_new.iloc[selected_index[0], 1]
                ),
                URIAction(
                    label=df_new.iloc[selected_index[1], 0],
                    uri=df_new.iloc[selected_index[1], 1]
                ),
                URIAction(
                    label=df_new.iloc[selected_index[2], 0],
                    uri=df_new.iloc[selected_index[2], 1]
                ),
                URIAction(
                    label=df_new.iloc[selected_index[3], 0],
                    uri=df_new.iloc[selected_index[3], 1]
                )
            ]
        )
    )
    return buttons_template_message

這裡實際使用情境痛點:

  1. 使用者不知道有哪些縣市可以選擇
  2. 使用者不知道要輸入什麼關鍵字才可以開啟推薦景點功能

因此,我們可以設計,當使用者輸入「嗨」、「Hi」等打招呼時,機器人會回覆輔助文字讓使用者知道有什麼功能可以使用:

接著,當使用者輸入「推薦景點」,這裡用一段輔助文字搭配QuickReply message,讓使用者從給定的一些選項當中選擇回覆訊息,實際使用狀況如下圖:

def handle_message(event):
    message = event.message.text
    if '推薦景點' in message:
        text_message = TextSendMessage(text='嗨囉你好,\n請選擇一個縣市或直接輸入「推薦XX景點」XX為縣市,\n將隨機跑出該縣市景點。',
                               quick_reply=QuickReply(items=[
                                   # 這裡line限制最多可以放13個項目
                                   QuickReplyButton(action=MessageAction(label="基隆", text="推薦基隆景點")),
                                   QuickReplyButton(action=MessageAction(label="台北", text="推薦台北景點")),
                                   QuickReplyButton(action=MessageAction(label="桃園", text="推薦桃園景點")),
                                   QuickReplyButton(action=MessageAction(label="新竹", text="推薦新竹景點")),
                                   QuickReplyButton(action=MessageAction(label="苗栗", text="推薦苗栗景點")),
                                   QuickReplyButton(action=MessageAction(label="台中", text="推薦台中景點")),
                                   QuickReplyButton(action=MessageAction(label="彰化", text="推薦彰化景點")),
                                   QuickReplyButton(action=MessageAction(label="南投", text="推薦南投景點")),
                                   QuickReplyButton(action=MessageAction(label="雲林", text="推薦雲林景點")),
                                   QuickReplyButton(action=MessageAction(label="嘉義", text="推薦嘉義景點")),
                                   QuickReplyButton(action=MessageAction(label="台南", text="推薦台南景點")),
                                   QuickReplyButton(action=MessageAction(label="高雄", text="推薦高雄景點")),
                                   QuickReplyButton(action=MessageAction(label="屏東", text="推薦屏東景點"))
                               ]))
        line_bot_api.reply_message(event.reply_token, text_message)    

在上圖中,你可以往右滑動看到更多選項,並且選擇其中一個,例如:點選「屏東」,就會顯示出隨機4個景點。

最後,如果你想玩玩看這項功能,歡迎加入好友,掃QR code。

參考資料