残プロ　第-10回　~Line Notifyの通知を華やかに~

# 今回の実装内容

- Line Notifyで絵文字を送る
- 簡単なスクレイピングを行いグラフ化，画像として送信


# 😀絵文字.py😇

pythonで絵文字を扱うには，

- 直接打ち込む(osに依存?)
- Unicodeを指定

の２つがあります．前者の方は例えば[こちら](https://lets-emoji.com/emojilist/emojilist-1/)の絵文字をコピーペーストで完了です．後者の方は同サイト一覧中のUnicodeを利用します．

### chr(Unicode) 

一つ注意点としては，Unicodeは16進数なのでそれを明記する必要があります．以下の例のように先頭に'0x'をつけることで16進数とみなしてくれます．

~~~ emoji.py
message = "Hi! Good Morning!" + chr(0x1F600)
~~~

~~~ terminal
Hi! Good Mornig!😀
~~~


# 簡単にスクレイピングをしてみる

※**過度なスクレイピングは相手側のサーバーに負荷をかけます．必ずtime.sleep等を利用して間隔を空けて使用するようにしてください．**

新型コロナについては[スマートニュースさんのサイト](https://coronavirus.smartnews.com/jp/)が簡素で綺麗にまとめてくれているので，今回はこちらをスクレイピングします．

LINEに通知したいのは上の表部分．

![smartnews.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578927/a13a6ae8-2c86-760f-5f53-cd9a47829292.png)

都合がいいことに，この部分はhtml内で最初の方に記載されているので，詳細なタグ・クラス属性の指定は必要ありません．ある程度で十分です．
今回は**[感染者数, 回復者数, 志望者数]**と，その内部に含まれる**[全体, 本日,　昨日]**をリストで指定しています．

~~~scraping.py
import requests
import time
from bs4 import BeautifulSoup

def getFromTag(soup, tag_name, class_name):
    content = soup.find(tag_name, class_=class_name)
    return content


def getFromList(soup, get_list, isText=False, regular=""):
    contents = []
    for tag_name, class_name in get_list:
        content = getFromTag(soup, tag_name, class_name)
        if isText and content:
            content = content.text
            if regular:
                content = re.findall(regular, content)
                content = ",".join(content)
        contents.append(content)
    return contents


if __name__ == '__main__':
    prefecture = "osaka"
    base_url = "https://coronavirus.smartnews.com/jp/"

    japan_html = requests.get(base_url)
    japan = BeautifulSoup(japan_html.text, 'html.parser')

    time.sleep(1)

    local_html = requests.get(base_url + prefecture)
    local = BeautifulSoup(local_html.text, 'html.parser')

    get_list = [("td", "stat confirmed"), ("td", "stat recovered"), ("td", "stat death")]
    child_get_list = [("div", "today"), ("div", "compare today"), ("div", "compare")]

    text_japan = []
    contents = getFromList(japan, get_list)
    for c in contents:
        text_japan.append(getFromList(c, child_get_list, isText=True))

    text_local = []
    contents = getFromList(local, get_list)
    for c in contents:
        text_local.append(getFromList(c, child_get_list, isText=True))
~~~


~~~
>>> print(text_japan)
>>> [['771,590', None, '昨日 +1,935'], ['724,049', None, '昨日 +3,538'], ['13,989', None, '昨日 +64']]
~~~

画像とは少し異なりますが(執筆中にサイトが更新されたようです)うまく取れてますね！prefectureに都道府県を代入できるのでお住いの県で試してみてください！


# 表を描画し画像化

先ほど取得したテキストデータを用いてmatplotlibで表をつくり，画像データ化します．
綺麗な表を作ろうとするとどうしてもプログラムが冗長になってしまいますね...

~~~imageconvert.py
from matplotlib import pyplot as plt

plt.rcParams["figure.subplot.left"] = 0
plt.rcParams["figure.subplot.bottom"] = 0
plt.rcParams["figure.subplot.right"] = 1
plt.rcParams["figure.subplot.top"] = 1
plt.rcParams["font.family"] = "meiryo"
plt.rcParams["font.size"] = 16

def text2table(text, header=None, index=None, color=None, imageTitle=""):
    if index:
        for t, i in zip(text, index):
            t.insert(0, i)
    if header:
        if index:
            header = [imageTitle] + header
        text.insert(0, header)
    fig, ax = plt.subplots()
    ax.axis('off')
    tb = ax.table(cellText=text, cellLoc='center', loc='center')
    tb.auto_set_font_size(False)
    cell_height = 1 / len(text)
    for pos, cell in tb.get_celld().items():
        cell.set_height(cell_height)
    if color:
        for i in range(len(text)):
            for j in range(len(text[0])):
                if color[i][j]:
                    tb[i, j].set_facecolor(color[i][j])
                    tb[i, j].set_text_props(weight='bold', color='white')
    if imageTitle:
        fig.savefig("images/"+ imageTitle + ".png")


if __main__ == '__name__':
    header = ["全体", "本日", "昨日"]
    index = ["感染者数", "回復者数", "死亡者数"]
    color = [
    ['', 'aqua', 'aqua', 'aqua'],
    ['red', '', '', ''],
    ['dodgerblue', '', '', ''],
    ['black', '', '', '']]

    _ = text2table(text_japan, header, index, color, "Japan")
    _ = text2table(text_local, header, index, color, "Kochi")
~~~

![Japan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578927/60a6ed47-aba9-fe49-3531-3c5addf014cf.png)

![Osaka.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578927/557f4357-82ff-ccc8-6a2f-c4f4a61a44f4.png)


# Line Notifyで通知する

まずはnotice.pyを用意しておきましょう

~~~ notice.py
import requests

TOKEN = 'hoge'
url = 'https://notify-api.line.me/api/notify'
TOKEN_dict = {'Authorization': 'Bearer ' + TOKEN}

def notice(message, img_path=None):
	message_dict = {'message': message}
	if img_path:
		files = {'imageFile': open(img_path, 'rb')}
		requests.post(url, headers=TOKEN_dict, data=message_dict, files=files)
	else:
		requests.post(url, headers=TOKEN_dict, data=message_dict)
~~~

これでモジュールとして利用できるようになりました．あとは絵文字やスクレイピング，画像を利用して通知内容を華やかにしましょう！！

![notify_emoji_scraping.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578927/581476df-c8de-7281-b450-7f60a707545b.png)


# 次回　第-11回は

ラズパイで定期的なpythonファイルの実行をしてみようと思います．温度や動作時間等のラズパイ内部情報も通知するようにする予定です．