###### tags: `Python勉強会` # 【51期】Python勉強会 第9回 :::info **<第9回Web会議日程>** 2024年07月18日(木) 19:00から ::: ## 第8回 解説 ### ・課題 **現在、以下のようにLINEで入力した場合、2行目を検索キーワードとして、 HotpepperのグルメサーチAPIにリクエストを送信し、おすすめのお店を一軒紹介します** ![image](https://hackmd.io/_uploads/Hy1MSkREC.png) **同様の入力をした場合に、お店の名前に加え、 付加情報をLINEに返すよう処理を追加してください** ![image](https://hackmd.io/_uploads/HJYNlQPSC.png) ### ・回答例 「<span style="color:blue">hotpepper_function.py</span>」  ※一部抜粋 ```python= def shop_search(from_text): #《1.HotpepperAPIにリクエストを送信》 # 入力内容を改行コードで区切ってリスト型に格納 str = from_text.split('\n') # str 値チェック logger.info('str:{}'.format(str)) # リストの要素数が2つの場合 if( len(str) == 2 ): # ~省略~ # レスポンスを辞書型に変換 response_dict = response.json() # response_dict 値チェック logger.info('response_dict:{}'.format(json.dumps(response_dict,indent=2,ensure_ascii=False))) # JSONデータの中からお店の名前を取得 shopname = response_dict['results']['shop'][0]['name'] # 第8回課題 shopname = response_dict['results']['shop'][0]['name'] genrename = response_dict['results']['shop'][0]['genre']['name'] mobile_access = response_dict['results']['shop'][0]['mobile_access'] catch = response_dict['results']['shop'][0]['catch'] to_text = [shopname,genrename,mobile_access,catch] else: to_text = '2行目に検索キーワードを入力してください' return to_text ``` ### ・解説 「<span style="color:blue">hotpepper_function.py</span>」 #### ① LINEに応答する付加情報を取得 「response_dict」から任意の情報を5つまで取得し、 それぞれ変数に代入する ```python shopname = response_dict['results']['shop'][0]['name'] genrename = response_dict['results']['shop'][0]['genre']['name'] mobile_access = response_dict['results']['shop'][0]['mobile_access'] catch = response_dict['results']['shop'][0]['catch'] ``` #### ②「to_text」にリスト型で代入 1で取得したそれぞれの要素を [ ] で括り、 リスト型として、「to_text」に代入する ```python to_text = [shopname,genrename,mobile_access,catch] ``` ### ・回答例 「<span style="color:blue">lambda_function.py</span>」  ※一部抜粋 ```python= # ~省略~ def lambda_handler(event, context): # ~省略~   # 第8回課題 # to_textが文字列だった場合 if type(to_text) is str: params['messages'].append({}) params['messages'][0]['type'] = 'text' params['messages'][0]['text'] = to_text # to_textが文字列以外の場合(リスト) else: # enumerateでインデックスと要素を抽出してループ処理 for no,item in enumerate(to_text): params['messages'].append({}) params['messages'][no]['type'] = 'text' params['messages'][no]['text'] = item # ~省略~ ``` ### ・解説 「<span style="color:blue">lambda_function.py</span>」 #### ①「to_text」のデータ型 「to_text」が文字列だった場合の分岐を作成し、これまで通り、 リスト型「messages」内に、type、textのキーを持つ辞書を1つ定義する ```python if type(to_text) is str: params['messages'].append({}) params['messages'][0]['type'] = 'text' params['messages'][0]['text'] = to_text ``` ![](https://hackmd.io/_uploads/SyNV70XF3.png) #### ②「messages」への要素の追加 「to_text」が文字列ではない場合、リスト型のため、 リストのインデックスと要素をまとめて取り出せるenumerateを利用して for文で、「messages」への要素の追加をループ処理させる ```python else: # enumerateでインデックスと要素を抽出してループ処理 for no,item in enumerate(to_text): params['messages'].append({}) params['messages'][no]['type'] = 'text' params['messages'][no]['text'] = item ``` ![](https://hackmd.io/_uploads/B1bHXRXY3.png) :::warning **<enumerate>** **`list.enumerate()`** ・リストに含まれている要素にインデックスを0から割り振り、「(インデックス, 要素)」というタプルにまとめた特殊なオブジェクトを返す ::: ------ ## 第8回 チャレンジ課題  ※余力のある方向け ### ■ 課題 **以下の入力をした場合に、お店の名前、付加情報に加え、お店の画像 をLINEに返すよう処理を追加してください** ![image](https://hackmd.io/_uploads/BkA8HJA4R.png) --- ### ・回答例 「<span style="color:blue">hotpepper_function.py</span>」  ※一部抜粋 ```python= def shop_search(from_text): # ~省略~ shopname = response_dict['results']['shop'][0]['name'] genrename = response_dict['results']['shop'][0]['genre']['name'] mobile_access = response_dict['results']['shop'][0]['mobile_access'] catch = response_dict['results']['shop'][0]['catch'] photo = response_dict['results']['shop'][0]['photo']['pc']['l'] to_text = [shopname,genrename,mobile_access,catch,photo] # ~省略~ ``` ### ・解説 「<span style="color:blue">hotpepper_function.py</span>」 「response_dict」から 「店舗トップ写真(大)画像URL」 を取得し、「to_text」に代入する ```python photo = response_dict['results']['shop'][0]['photo']['pc']['l'] to_text = [shopname,genrename,mobile_access,catch,photo] ``` ### ・回答例 「<span style="color:blue">lambda_function.py</span>」 ```python= # ~省略~ def lambda_handler(event, context): # ~省略~   # 第8回課題 # to_textが文字列だった場合 if type(to_text) is str: params['messages'].append({}) params['messages'][0]['type'] = 'text' params['messages'][0]['text'] = to_text # to_textが文字列以外の場合(リスト) else: # enumerateでインデックスと要素を抽出してループ処理 for no,item in enumerate(to_text): # 抽出した要素が画像の場合(「jpg」で終わる)の処理 if item.endswith('.jpg'): params['messages'].append({}) params['messages'][no]['type'] = 'image' params['messages'][no]['originalContentUrl'] = item params['messages'][no]['previewImageUrl'] = item # 画像以外の処理 else: params['messages'].append({}) params['messages'][no]['type'] = 'text' params['messages'][no]['text'] = item # ~省略~ ``` ### ・解説 「<span style="color:blue">lambda_function.py</span>」 to_textが文字列以外の場合のfor文内で、if文で分岐を作成し、画像の(「jpg」で終わる)場合、 リスト型「messages」内に、type、originalContentUrl、previewImageUrlの キーを持つ辞書を定義する 画像ではなければ、type、textのキーを持つ辞書を定義する ```python if item.endswith('.jpg'): params['messages'].append({}) params['messages'][no]['type'] = 'image' params['messages'][no]['originalContentUrl'] = item params['messages'][no]['previewImageUrl'] = item else: params['messages'].append({}) params['messages'][no]['type'] = 'text' params['messages'][no]['text'] = item ``` ------ ## 第9回 課題 **以下のように、LINEに位置情報を送信した場合、** **HotpepperAPIを利用し、画像やその他の情報と合わせて おすすめのお店を1軒紹介するよう処理を追加してください** ![](https://hackmd.io/_uploads/BJatXRrh3.png) ----- ### ・課題の概要 これまでは、LINEに**文字列**を入力しその内容に合わせて、 Lambda内で処理を実行させ、LINEに応答を返していました。 今回は、LINEに**位置情報**を入力し、緯度経度の情報をもとに HotpepperAPIにリクエストを送信し、おすすめの店舗の情報を 返すよう処理を修正していただきます。 ----- ### ・「<span style="color:blue">lambda_function.py</span>」への修正 #### ①位置情報が入力された場合の処理 LINEで入力された内容は、その他の情報と合わせて変数「event」に格納されています。 その中から、以下の処理で、画像内の緑下線の入力メッセージを取得して「from_text」に格納して利用していました。 ```python from_text = json.loads(event['body'])['events'][0]['message']['text'] ``` ■文字列が入力された場合の「event」の一部 ![](https://hackmd.io/_uploads/rJea0Rr2h.png) 位置情報が入力された場合は、以下の画像のようになります。 ■位置情報が入力された場合の「event」の一部 ![](https://hackmd.io/_uploads/BkJE7J8n3.png) 青下線の「type」が**location**に変わり、 緑下線の「latitude」「longitude」に緯度経度の情報が格納されています。 そのため、青下線の「type」が**text**だった場合は、 これまで通り、LINEで入力された文字列をfrom_textに代入し、 入力内容に沿ってto_textを定義する処理を実行し、 そうでない場合(青下線の「type」が**location**)の場合、 「latitude」「longitude」から緯度経度を取得するよう、処理を分岐してください ■「type」の判別 ```python json.loads(event['body'])['events'][0]['message']['type'] == 'text' ``` ■緯度経度取得処理 ```python latitude = json.loads(event['body'])['events'][0]['message']['latitude'] longitude = json.loads(event['body'])['events'][0]['message']['longitude'] ``` #### ② 「hotpepper_function.py」呼び出し処理 hotpepper_functionのshop_search関数の引数は、「from_text」一つだけのため、 ①で追加した分岐内で、「latitude」「longitude」の 2つの引数を引数とするshop_search_map関数を呼び出し、 結果を「to_text」に代入してください ----- ### ・「<span style="color:blue">hotpepper_function.py</span>」への修正 hotpepper_function.py内に、「latitude」「longitude」を 引数とするshop_search_map関数を追加してください。 これまでのshop_search関数は、引数「keyword」をHotpepperAPIへの リクエストパラメータ「hp_param」に定義し、 キーワードでおすすめ店舗を検索していました。 追加するshop_search_map関数では、緯度経度でおすすめ店舗の検索を行うため、 引数「keyword」ではなく、「latitude」「longitude」を 「hp_param」に定義し、HotpepperAPIにリクエストを送信し、 レスポンスを「to_text」に代入し、lambda_functionに返してください。 ■緯度経度検索用パラメータ定義 ```python # HotpepperAPIへのリクエストパラメータ準備 hp_pram = { 'key':HP_API_KEY, 'lat':latitude, 'lng':longitude, 'order':4, 'count':1, 'format':'json' } ``` 改行コードで区切る処理や、要素数を確認する処理は不要です。 また、HotpepperAPIにリスエストを送信し、 レスポンスから情報を取得する処理は、そのまま利用して問題ございません。 --- ### ・LINEでの位置情報の送信方法 位置情報は、以下のリンクを参考に、送信してください。 PC版のLINEでは送信できないため、携帯から送信してください。 ▼位置情報 送信方法 https://guide.line.me/ja/services/location-information.html :::danger デフォルトでは、現在地にピンが立っているため、 任意の場所にピンの位置を変更してください :::