###### tags: `Python勉強会` # 【51期】Python勉強会 第8回 :::info **<第8回Web会議日程>** 2024年06月19日(水) 19:00から ::: ## 第7回 解説 ### ・課題 **現在、「<span style="color:blue">lambda_function.py</span>」は、以下のようにLINEで入力した場合、** **2行目をキー、3行目を値としたJSONファイルをS3に書き込みます。** ![](https://hackmd.io/_uploads/HJhh5w542.png) **上記に以下のようにLINEで入力した場合、S3のJSONファイルを読み込み、** **キーに対応する値をに応答する処理を追加してください** ![](https://hackmd.io/_uploads/BJqp9Pq4n.png) ### ・回答例 ```python= def s3_output(from_text): # 入力内容を改行コードで区切ってリスト型に格納 str = from_text.split('\n') # リストの要素数が1つより大きいの場合 if( len(str) > 1 ): # リストの2要素目(キー)がjson_dataに含まれる場合 if( str[1] in json_data ): # キーに対応する値を「to_text」に格納 to_text = json_data[str[1]] # リストの2要素目(キー)がjson_dataに含まれない場合 else: to_text = str[1] + 'は登録されていません' else: to_text = '2行目にキーを入力してください' return to_text ``` ### ・解説 「s3_output」関数実行時には、 「s3_function.py」内のjsonファイル読み込み処理実行済みのため、 変数「json_data」は以下となる ```python # json_data {'明日の予定': '仕事'} ``` 「from_text」には、LINEでの入力内容が以下の文字列として入る ```python # from_text '出力\n明日の予定' ``` このままでは処理できないため、「from_text」を改行コードで区切ってリスト型「str」に格納する ```python! str = from_text.split('\n') ``` 「str」は以下のようなリストの値となる ```python! # str ['出力', '明日の予定'] ``` リスト型「str」の2つ目の要素の値をキーとして、 辞書型「json_data」から値を取り出し、「to_text」に代入できていれば、OK ```python to_text = json_data[str[1]] ``` 上記に加え、想定外の入力があった場合の処理として、以下を追加 ・「出力」から始まる1行しか入力がなかった場合、「2行目にキーを入力してください」を返す ・2行目にs3のjsonにないキーが指定された場合、「 キー は登録されていません」を返す ------ ## 第8回 課題 ### ■ 課題の前に。。。 #### 入力内容が「入力」「出力」から始まった場合の分岐追加 ・各自の関数の最後のELIFの後に、以下の記述を追加 ```python # LINEで入力内容が「ホットペッパー」から始まった場合 elif from_text.startswith('ホットペッパー'): # hotpepper_functionモジュールのshop_search関数を呼び出す to_text = hotpepper_function.shop_search(from_text) ``` ### ■ 課題 **現在、以下のようにLINEで入力した場合、2行目を検索キーワードとして、 HotpepperのグルメサーチAPIにリクエストを送信し、おすすめのお店を一軒紹介します** ![image](https://hackmd.io/_uploads/Hy1MSkREC.png) **同様の入力をした場合に、お店の名前に加え、 付加情報をLINEに返すよう処理を追加してください** ![image](https://hackmd.io/_uploads/HJYNlQPSC.png) ----- ### ・課題の概要 今回からの課題では、**HotpepperAPI**という無料で公開されているAPIを利用します。 このAPIは、公開されているURLにリクエストを送信すると、 キーワードに応じて店舗を検索し、その情報を返してくれます。 今回の課題では、LINEの入力内容をキーワードにこのAPIにリクエストを送信し、 APIから返されたレスポンスから**掲載店名**やその他付加情報を抽出し、LINEに返すように関数を修正いただきます。 「公開されているURLにリクエストを送信する」 「レスポンスから掲載店名を取得しLINEに応答する」部分は、「hotpepper_function.py」に定義済みです。 そのため今回は、レスポンスから掲載店名以外の情報を追加で取得し、 複数のメッセージをLINEに応答できるよう修正していただきます。 ----- ### ・前回からの変更点 ![](https://hackmd.io/_uploads/HJNZpcEDh.png) ①個人のスマホからLine公式アカウントにメッセージ送信 ②Line公式からWebhookしたAPI GatewayのURLへメッセージを送信 ③API Gatewayに関連付けられたLambdaを呼び出し <span style="color:red">④HotpepperAPIにリクエスト</span> ⑤Lambdaで作り込んだ処理に沿ってメッセージを応答 ------ ### ・「<span style="color:blue">hotpepper_function.py</span>」概要 #### 1 . HotpepperAPIにリクエストを送信 * 入力内容(from_text)を改行コードで区切って変数「str」にリスト型で格納 ```python ['ホットペッパー', '池袋'] ``` * 変数「hp_pram」に、リクエストに必要な検索条件を定義し、HotpepperAPIのURLにGETリクエストを送信 ```python # HotpepperAPIへのリクエストパラメータ準備 hp_pram = { 'key':HP_API_KEY, 'keyword':keyword, 'order':4, 'count':1, 'format':'json' } ``` :::success 今回のリクエストでは、以下のパラメータを利用 詳細やその他のパラメータは[APIリファレンス](https://webservice.recruit.co.jp/doc/hotpepper/reference.html)を参照 **・key**:  APIを利用するためのキー **・keyword**:  フリーワード検索のためのキーワード  LINEでの入力内容でお店を検索する   **・order**:  検索結果の並び順を指定できる  「4」はおすすめ順 **・count**:  検索結果のデータ数を指定できる  「1」を指定しているため、1店舗だけの情報が返る **・format**:  レスポンスの形式を指定できる  Pythonで処理するため、「JSON」を指定 ::: #### 2 . レスポンスからお店の情報を取得 * お店の情報が格納されたJSON形式のレスポンスを辞書型「response_dict」に変換 * **掲載店名**を抽出し、LINEへの返答内容(to_text)を定義 :::success **掲載店名**は、レスポンス内のリスト型「shop」の0番目の要素の辞書から 「name」をキーに値を取り出す ```pyton! shop_name = response_dict['results']['shop'][0]['name'] ``` ▼値格納イメージ ![](https://hackmd.io/_uploads/HJDdZkuuh.png) ::: ----- ### ・「<span style="color:blue">hotpepper_function.py</span>」への修正 #### ① LINEに応答する付加情報を取得 「response_dict」に格納されたレスポンスから **「掲載店名」** のみを取得しておりますが、 各自お好みの情報を「掲載店名」を含め、5つまで取得してください。 ■掲載店名 取得サンプル ```python shopname = response_dict['results']['shop'][0]['name'] ``` :::success レスポンスにどんな情報が含まれているかは、 [APIリファレンス](https://webservice.recruit.co.jp/doc/hotpepper/reference.html)のグルメサーチAPI、レスポンスフィールドを参照 ::: #### ② 「to_text」にリスト型で代入 ①で取得した情報を複数要素を保持できるリスト型で、 「to_text」に代入し、lambda_functionに返して下さい ### ・「<span style="color:blue">lambda_function.py</span>」への修正 #### 1 . params['messages'] 定義時の処理修正 LINEで応答する際の「params」は以下のように定義する必要があります ![](https://hackmd.io/_uploads/SyNV70XF3.png) ■params定義 ```python! params['messages'] = []  ~省略~ params['messages'].append({}) params['messages'][0]['type'] = 'text' params['messages'][0]['text'] = to_text ``` 複数のメッセージで応答するには、「params」を以下のように、 リスト型の「messages」内に、複数の辞書型の要素を定義することで実現できます ![](https://hackmd.io/_uploads/B1bHXRXY3.png) 以下に留意し、paramsを定義する記述を修正してください #### 2 . 具体的な修正箇所 #### ①「to_text」のデータ型 hotpepper_functionからの戻り値「to_text」はリスト型ですが、 s3_functionやその他の処理では、 文字列型です。 ⇒「to_text」のデータ型によって処理を分岐してください #### ②「messages」への要素の追加 「to_text」がリスト型だった場合、 「messages」のリストに、複数の辞書型の要素を追加する必要があります ⇒「<span style="color:blue">hotpepper_function.py</span>」で取得した情報の数だけ、  「messages」のリストに要素を追加してください ------ ### ・ホットペッパーAPI :::info **<ホットペッパーAPIとは>** 【URL】ホットペッパーAPI https://webservice.recruit.co.jp/doc/hotpepper/reference.html リクルートが提供してくれている無料のAPIサービス。  ※今回はグルメサーチAPIを利用 ホットペッパーAPIを利用するには利用申請が必要となる。 [リンク](https://webservice.recruit.co.jp/register/)より新規登録し、APIキーを取得する必要がある。  ※今回は講師側で取得し、環境変数に登録済み。 **<使い方>** #### ①APIに対し、リクエストを送信する ・以下のURLに対してリクエストを送信する http://webservice.recruit.co.jp/hotpepper/gourmet/v1/ ・送信時に検索クエリをリクエストパラメータとして送信できる ・検索クエリの条件に一致するお店をホットペッパー内で検索してくれる ・どのような検索クエリを指定可能か、は  [リファレンス](https://webservice.recruit.co.jp/doc/hotpepper/reference.html)のグルメサーチAPI、検索クエリを参照   ### ②レスポンスを受け取る ・検索クエリに指定した条件に一致する店舗の情報がレスポンスとして返される ・データの形式はリクエスト時に指定でき、  JSONを選択すると、Pythonで辞書型に変換可能 ・レスポンスにどのような情報が含まれるか、は  [リファレンス](https://webservice.recruit.co.jp/doc/hotpepper/reference.html)のグルメサーチAPI、レスポンスフィールドを参照 ::: ----- ### ・Lambda レイヤー :::warning ・Lambdaレイヤーは、追加のコードまたはデータを含むことができる .zipファイルをまとめたもの。ライブラリ、カスタムランタイム、データ、または設定ファイルを含めることができる。 ・lambdaでサードパーティライブラリを使うにはLayerを使う必要があり、AWS Lambda上でもサードパーティー製のライブラリを使うことができる。 ・Lambdaは標準ライブラリしか使えず、外部モジュールを使用するにはインストールしなければならない。 また、ファイルをAWSにアップロードすると、関数で利用できる ::: #### ※今回は講師側でrequestsのレイヤーを登録済みです!! ----- ### ・requestsについて :::warning **<requestsとは>** HTTP通信用のPythonのライブラリ GET、POST、PUTなどのメソッドが用意されている 今回は、HTTPでHotpepperAPIにGETリクエストを送るために使用 外部モジュールのため、利用するにはインストールの必要がある 今回はLambdaのため、Layerとして追加 ``` pip install requests ``` <br> **<GETメソッド>** **`requests.get(リクエスト送信先URL,リクエストパラメータ)`** URLに対してGETリクエストを送ることができる リスエストの結果が、Responseオブジェクトとして返される ::: ----- ## 第8回 チャレンジ課題  ※余力のある方向け ### ■ 課題 **以下の入力をした場合に、お店の名前、付加情報に加え、お店の画像 をLINEに返すよう処理を追加してください** ![image](https://hackmd.io/_uploads/BkA8HJA4R.png) --- ### ・「<span style="color:blue">hotpepper_function.py</span>」への修正 「response_dict」に格納されたレスポンスから 「店舗トップ写真(大)画像URL」 を取得し、 「to_text」に代入し、lambda_functionに返して下さい ### ・「<span style="color:blue">lambda_function.py</span>」への修正 トップ画像はJPEG、値としては「https://XXXX.jpg」でレスポンスに登録されています。 また、辞書型の定義も、文字列の応答時とは異なり、 以下のように変更する必要があります。 ![](https://hackmd.io/_uploads/rJXGvHEYn.png) 「messages」への要素の追加時に、値が「.jpg」の場合、処理を分岐してください 「originalContentUrl」と「previewImageUrl」は同じ値で問題ないです ※もし、「.jpg」以外の拡張子で登録されていた場合、  その拡張子も「.jpg」と同じ処理に分岐してください