プログラミング初心者が Python で Slack bot 作成 [ 実践編 ]

## はじめに

前回の [プログラミング初心者が Python で Slack bot 作成 [ 準備編 ]
](https://qiita.com/fruity/items/6f8972acb592631a43a0) の続きとなります。

## 開発環境

### 環境
- Python
- Docker
- Make

### ツール

- Atom Editor
- iTerm 2


## 実践

まずは [開発環境](https://github.com/furuuchitakahiro/pysandbox) をクローンします。
 
続いてクローンしたリポジトリの src ディレクトリに `weather.py` ( ファイル名はご自由に ) を新規作成します。 

今回使うライブラリは標準のものだけです ( Lambda では基本的に標準のもの以外使えません ) 。

```python:weather.py
import json # 追記
import urllib # 追記
```

`import json` これを使うことで Python で JSON を扱うことができます。
`import urllib` これは Python で HTTP リクエストを出すために必要なものです ( 今回は GET リクエストと POST リクエストを使います ) 。

まずは Yahoo デベロッパーネットワークで作成したリクエスト URL を変数 `REQUEST_URL` に入れます。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL' # 追記
```

次に Slack で取得した Web hook URL を変数 `WEB_HOOK_URL` に入れます。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL' # 追記
```

では実際に Yahoo 気象情報 API から情報を取得してみましょう！

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL) # 追記
    with urllib.request.urlopen(reqg) as res: # 追記
        response = res.read() # 追記
```

1 行目は `REQUEST_URL` へリクエスト ( GET ) し、結果を変数 `reqg` に入れています。
噛み砕いて説明すると、

&emsp; __使うもの__ &emsp;&emsp; __使う機能__ &emsp;&emsp;&emsp; __オブジェクト__&emsp;&emsp;&emsp;&emsp;&emsp; __どこの__
&emsp;&emsp; urllib &emsp;&emsp;&emsp; .request &emsp;&emsp;&emsp;&emsp; .Request &emsp;&emsp;&emsp;&emsp; (REQUEST_URL)

こうなります。

2 行目は 1 行目で取得したものを開いて変数 `res` の中に入れています。

3 行目は変数 `response` の中に 2 行目で展開した変数 `res` を読み込んだものを入れています。

これで変数 `response` にリクエストのレスポンスが入りました。
では `response` の中身を見てみましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

print(response) # 追記
```

実行してみましょう。

`$ python weather.py`

すると、

```
{
  "ResultInfo": {
    "Count": 1,
    "Total": 1,
    "Start": 1,
    "Status": 200,
    "Latency": 0.003538,
    "Description": "",
    "Copyright": "(C) Yahoo Japan Corporation."
  },
  "Feature": [
    {
      "Id": "201903252255_139.707831_35.774614",
      "Name":"\xe5\x9c\xb0\xe7\x82\xb9(139.707831,35.774614)\xe3\x81\xae2019\xe5\xb9\xb403\xe6\x9c\x8826\xe6\x97\xa5 14\xe6\x99\x8220\xe5\x88\x86\xe3\x81\x8b\xe3\x82\x8960\xe5\x88\x86\xe9\x96\x93\xe3\x81\xae\xe5\xa4\xa9\xe6\xb0\x97\xe6\x83\x85\xe5\xa0\xb1",
      "Geometry": {
        "Type": "point",
        "Coordinates": "139.707831,35.774614"
      },
      "Property": {
        "WeatherAreaCode": 4410,
        "WeatherList": {
          "Weather": [
            {
              "Type": "observation",
              "Date": "201903252255",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252305",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252315",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252325",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252335",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252345",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252355",
              "Rainfall": 0
            }
          ]
        }
      }
    }
  ]
}

```
name の部分が読めませんね ( 見やすくするため整形しています )。

原因はこれが __HTTPResponse オブジェクト__ だからです。
なので文字列に変換する必要があります。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode() # 追記

print(response)
```

もう1度確認してみましょう。

`$ python weather.py`

すると

```
{
  "ResultInfo": {
    "Count": 1,
    "Total": 1,
    "Start": 1,
    "Status": 200,
    "Latency": 0.003538,
    "Description": "",
    "Copyright": "(C) Yahoo Japan Corporation."
  },
  "Feature": [
    {
      "Id": "201903252255_139.707831_35.774614",
      "Name": "地点(139.707831,35.774614)の2019年03月25日 22時55分から60分間の天気情報",
      "Geometry": {
        "Type": "point",
        "Coordinates": "139.707831,35.774614"
      },
      "Property": {
        "WeatherAreaCode": 4410,
        "WeatherList": {
          "Weather": [
            {
              "Type": "observation",
              "Date": "201903252255",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252305",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252315",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252325",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252335",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252345",
              "Rainfall": 0
            },
            {
              "Type": "forecast",
              "Date": "201903252355",
              "Rainfall": 0
            }
          ]
        }
      }
    }
  ]
}
```

これで読めるようになりました。
確認が終わったので`ptint(response)`は削除しましょう。

続いて変数 `response` の中身を JSON に変換しましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode()

d = json.loads(response) # 追記
```

変数 `response ` が JSON に変換されたものが変数 `d` に 入りました。
これを噛み砕いて説明すると、

__変数__ &emsp;&emsp;&emsp; __代入__ &emsp;&emsp;&emsp; __json として__ &emsp;&emsp;&emsp; __読み込む__ &emsp;&emsp;&emsp; __何を__
&emsp; d &emsp;&emsp;&emsp;&emsp;  = &emsp;&emsp;&emsp;&emsp;&emsp; json  &emsp;&emsp;&emsp;&emsp;&emsp; .loads &emsp;&emsp;&emsp;  (response)

となります。

この JSON の中にはたくさんのデータが入っていますが、今回必要なのは降水強度のデータのみです。
では降水強度のみ抜き出してみましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode()

d = json.loads(response)

rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall'] # 追記
```

これは変数 `d` の中身 ( JSON ) の __Feature__ の __0__ 番目 ( dict ( 辞書 )では 0, 1, 2, 3, ... と数えます ) の __Property__ の __WeatherList__ の __Weather__ の __0__ 番目の __Rainfall__ の値を変数 `rainfall` に代入する、という意味になります。
実際に確認してみましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode()

d = json.loads(response)

rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']

print(rainfall) # 追記

```

`$ python weather.py`

すると、

```
0.0
```

これで無事、現在の降水強度のみを取得することができました！
確認が終わったので`print(rainfall)`は削除してください。

では次に Slack に通知する文を書きましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode()

d = json.loads(response)

rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']

payload_d = {
    'text': '現在の赤羽駅の降水強度は {} mm/h です。'.format(rainfall)
} # 追記

```

今回は __{ }__ で括ったものを代入しています。
これは、変数 `payload_d` に __dict__ として代入する、という意味です。
中身は __text__ をキーに __'現在の赤羽駅の降水強度は {} mm/h です。'__ を値として、{} 内に、変数 __rainfall__ の中身を表示、という意味になります。

説明ではわかりにくいですね...。
では実際に payload の中身を確認してみましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode()

d = json.loads(response)

rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']

payload_d = {
    'text': '現在の赤羽駅の降水強度は {} mm/h です。'.format(rainfall)
}

print(payload_d) # 追記

```

`$ python weather.py`

```
{'text': '現在の赤羽駅の降水強度は 0.0 mm/h です。'}
```

このように {} 内に変数 `rainfall` の中身が代入されます。
確認が終わったので`print(payload_d)`を削除してください。

ではこれを JSON に変換しましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode()

d = json.loads(response)

rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']

payload_d = {
    'text': '現在の赤羽駅の降水強度は {} mm/h です。'.format(rainfall)
}

data = json.dumps(payload_d).encode('utf-8') # 追記

```

これを細かく説明するとこうなります。

__変数__ &emsp;&emsp; __代入__ &emsp;&emsp;&emsp;&emsp; __JSON として__ &emsp; __変換__ &emsp;&emsp;&emsp;&emsp; __何を__ &emsp;&emsp;&emsp;&emsp;&emsp; __文字コード__
data &emsp;&emsp; &emsp; = &emsp;&emsp;&emsp;&emsp;&emsp;&emsp; json &emsp;&emsp;&emsp;.dumps &emsp;&emsp; (payload_d) &emsp;&emsp; .encode('utf-8')

次にこのデータを Slack に届ける準備をしましょう。

```python:weather.py
import json
import urllib

REQUEST_URL = '作成したリクエスト URL'

WEB_HOOK_URL = '取得した Web hook URL'

reqg = urllib.request.Request(REQUEST_URL)
    with urllib.request.urlopen(reqg) as res:
        response = res.read()

response = response.decode()

d = json.loads(response)

rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']

payload_d = {
    'text': '現在の赤羽駅の降水強度は {} mm/h です。'.format(rainfall)
}

data = json.dumps(payload_d).encode('utf-8')

reqp = urllib.request.Request(WEB_HOOK_URL, data, method='POST') # 追記
with urllib.request.urlopen(reqp) as res: # 追記
        body = res.read().decode('utf-8') # 追記


```

データを届ける ( POST ) ときも urllib を使います。
データを取得したときと似ていますね。
違うところは 1 行目の `method='POST'` と 2 行目の `decode('utf-8')` になります。

`method='POST'` は HTTP メソッドの指定になります。今回は Slack に届けてもらいたいので POST ですね。
`decode('utf-8')` は文字コードの指定になります。これで Slack 側でもちゃんと読めるようになります。

以上で完成です！
試しに実行してみましょう！

`$ python weather.py`

![スクリーンショット 2019-03-27 22.15.12_edited-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/371718/321dc5f2-e877-1f4c-0a52-2a0617eb1ebe.jpeg)

このような通知が来れば成功です！

## 最後に

とても長くなってしまいましたが、最後までお付き合いいただきありがとうございました！
コードはこれで完成しましたが、デプロイがまだなので、次回 __本番編__ ということでそちらに記事を書かせていただきます。