Python_FlaskでLine Chat BOT（スクレイピング＋API）

#概要
AIチャットBOT ＋スクレイピング　＝　POST ＋　API　＋BS４の学習の体験に役立てる記事となることを願います。
最終的な目的として、Lineの１つのBotによりいろいろなサービスと連携でき統合していきたいと思います。
（秘書みたいなものを作りたい。）
##成果物
https://liff.line.me/1645278921-kWRPP32q?accountId=621otkwb&openerPlatform=native&openerKey=talkroom%3Amessage#mst_challenge=XC5NTvj9TrdRKQK5uqwVADAMrvCYbugYb9F4RvYD2jI
##環境
Python：Flask
Heroku
line-bot-sdk
BeautifulSoup4
pya3rt(リクルートのAIチャット)
requests
##構成
```:構成
project
├── main.py
├── requirements.txt
├── Procfile
└── runtime.txt
```
##手順
###1.準備リクルートAIchatBotのAPIの取得
Talk APIのAPI KEYが必要です。
https://a3rt.recruit-tech.co.jp/product/talkAPI/
###2.LINEの準備
https://note.com/pro_buncho/n/n37ff0614dd36

LINE公式アカウントを作成し、対応します。
###3.スクレイピングのコード作成
```Python:Python
import requests
import json
from bs4 import BeautifulSoup

url = 'https://tenki.jp/forecast/9/46/8610/43100/'
res = requests.get(url)

soup = BeautifulSoup(res.text, "html.parser")
print(soup)



found = soup.find_all('p',class_='weather-telop')
found2 = soup.find_all('h3',class_='left-style')

textA = found2[0].text + found[0].text +'\n'+found2[1].text + found[1].text
textA = '熊本の天気\n'+textA
print(textA)
```
テスト動作を別途作成しテストします。

###4.AIchatのテスト
```Python:Python
import pya3rt
apikey = "＃＃＃＃＃＃＃＃＃" #自分のAPIキーを設定する
client = pya3rt.TalkClient(apikey)

if __name__ == '__main__':
  words = input("INPUT MESSAGE >")
  #CTRL＋Cで終了
  while words!="":
    response = client.talk(words)
    print("Bot >"+((response['results'])[0])['reply'])
    words = input("INPUT MESSAGE >")
    words =response['results']
```

###main.pyへスクレイピンとAIチャットのAPIを取り込んだLineBOTをコーディング
```Python:Python
from flask import Flask, request, abort
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import os
import requests
import pprint
from bs4 import BeautifulSoup

#AI　chatbotモジュール
import pya3rt

app = Flask(__name__)

#環境変数取得
# LINE Developersで設定されているアクセストークンとChannel Secretをを取得し、設定します。
#セキュリティ上heroku側で環境変数を設定すると良いです。
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

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

#Webhookからのリクエストをチェックします。
@app.route("/callback", methods=['POST'])
def callback():
    # リクエストヘッダーから署名検証のための値を取得します。
    signature = request.headers['X-Line-Signature']

    # リクエストボディを取得します。
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body# 署名を検証し、問題なければhandleに定義されている関数を呼び出す。
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:# 署名検証で失敗した場合、例外を出す。
        abort(400)
        # handleの処理を終えればOK
    return 'OK'

#LINEでMessageEvent（普通のメッセージを送信された場合）が起こった場合に、def以下の関数を実行します。
#reply_messageの第一引数のevent.reply_tokenは、イベントの応答に用いるトークンです。 
#第二引数には、linebot.modelsに定義されている返信用のTextSendMessageオブジェクトを渡しています。

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):

    push_text = event.message.text

　　 #熊本天気という特定文字に対して下記処理を行います。ワイルドカードを使えば抽出する形になるでしょう。
    if push_text == "熊本天気":       
        url = 'https://tenki.jp/forecast/9/46/8610/43100/'
        res = requests.get(url)

        soup = BeautifulSoup(res.text, "html.parser")
        #print(soup)

        found = soup.find_all('p',class_='weather-telop')
        found2 = soup.find_all('h3',class_='left-style')

        
        textA = found2[0].text + found[0].text
        #textA = '熊本の天気を気象庁からスクレイピングしてきました。\n'+textA

        reply_text =  textA

        line_bot_api.reply_message(event.reply_token,[TextSendMessage('熊本の天気を気象庁からスクレイピングしてきました。'),TextSendMessage(textA),TextSendMessage(found2[1].text + found[1].text)])

    elif push_text == "自己紹介":
        reply_text = "初めまして。\n私にはAIchatがAPI連携で搭載されています。\n色んな会話をして下さい。"   


    elif push_text == "犬はかわいい":        
        reply_text = "はい、 その通りです。\n動画を撮り、家族で共有すべきだと思います。\nコロナのせいで、皆にあいにくいいま動画コンテンツは利用するべきです。"   
        A = []
        A.append(reply_text)
        reply_text = "お犬様は正義！"   
        A.append(reply_text)
        line_bot_api.reply_message(event.reply_token,[TextSendMessage(A[0]),TextSendMessage(A[1])])
        
    elif push_text == "転職したい":
        reply_text = "Let's　Action"   
        
    else:
　　     ai_message = talk_ai(push_text)
        reply_text = ai_message
　　　　　#特定もじいがいはAiからのメッセージにて対応させます。   

    line_bot_api.reply_message(event.reply_token,TextSendMessage(text=reply_text))


#上部でtalk_ai使用時に下記関数が使われます。
def talk_ai(word):
    apikey = "###########"
    client = pya3rt.TalkClient(apikey)
    reply_message = client.talk(word)
    return reply_message['results'][0]['reply']

# ポート番号の設定
if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    app.run(host="0.0.0.0", port=port)
```


##参考
https://qiita.com/hiro0236/items/84581c5e4481185d4a5c

他のスタンプや、写真が来た時などの処理振り分けを行えば、写真判別や写真をサーバーへ格納などもできそうです。