毎日色々と巡回して自動で通知してくれる便利Botを作ってみる【応用可】

毎日Botが自動でWeb上を見回って通知してくれると便利ですよね。

**祝日まであと何日だろう？**
**明日ってゴミの日だっけ？**
**そういえばいつも見てるあれ今どうなってるかな**

こういった時に普通だと自分で確認する事になると思うのですが全て自動でやらせてみる。
という事で出来るだけ初心者でも出来る便利Botの作り方を解説していきます。

・Slackの例
![SlackBot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/d907200e-ebb5-5d21-fd64-1eb724a11495.png)
・Twitterの例
![TwitterBot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/fbe312ea-f28b-e044-d195-7cd51a0a1e70.png)


## 🔔 通知出来るもの
通知したいデータを取得さえ出来ればどんな物でも可能です。
それをSlackやTwitterなどに通知します。

## 📄  使うもの

###・ 言語
例：**Python**
どんな言語でも可
今回はスクレイピング例も扱うのでデータの扱いやすいPythonで解説

###・ 定期実行
例：**Heroku**
言語に対応していて定期実行出来ればどんな物でも可
無料が良いので今回はHerokuで解説する。Google Cloud Functionsの定期実行Jobもオススメ

###・ 通知場所
例：**Slack, Twitter**
プログラム上から通知を飛ばせたらどんな物でも可
今回は個人的によく見ている物、TwitterとSlackに通知を飛ばす例を解説します。
　
　



## 📚 通知したいデータを用意

では早速通知したいデータを探します。

例えば、
**・祝日までの日数**
**・明日はゴミの日か**
**・リンク切れてないか**
**・サイトに新しい商品が出てないか**

### ・通知例１ 『祝日までの日数を知りたい』

作る物：「**次の祝日（〇〇の日）までは〇〇日です。**」

祝日が何月何日かが分かれば本日からの日数で出せます。
「祝日api」で検索すると祝日一覧を提供してくれている良い感じのAPIが沢山あるので使わせていただきます。

■ Holidays JP API (日本の祝日API)
https://holidays-jp.github.io/

```json:jsonの中身
{
    1577804400: "元日",
    1578841200: "成人の日",
    1581346800: "建国記念の日",
    ・・・
}
```
　
祝日の一覧データが用意できたので、今日から一番近い祝日を見つけてそれまでの時間を取得します。

```python:祝日までの日付を求める
# Holidays JP APIのURL
holidays_url = "https://holidays-jp.github.io/api/v1/date.json"

# 祝日一覧APIからデータを取得
res = requests.get(holidays_url)
holidays = json.loads(res.text)
# 比較するための今日の日付
today = datetime.datetime.strptime(str(datetime.date.today()), "%Y-%m-%d").date()
# 今日より後の日付の祝日を探す
for k, v in holidays.items():
    holiday = datetime.datetime.strptime(k, "%Y-%m-%d").date()
    # 今日より日付が後だったら（当日を含むので、<=比較）
    if today <= holiday:
        # 次の祝日（今日が2021-08-30の場合は、「2021-09-20」　）
        near_holiday_date = holiday
        # どういう祝日か（2021-09-20は、敬老の日）
        near_holiday_value = v
        # for文終わる
        break

# 祝日までの日数を計算（祝日から今日の日付を引く）
diff_date = near_holiday_date - today
# 文字列に変換
diff_date = str(diff_date.days)
# テキストを組み立てる
holiday_text = '次の祝日（' + near_holiday_value + '）までは' + diff_date + '日です。'

print(holiday_text)   # 次の祝日（敬老の日）までは21日です。
```

**「次の祝日（敬老の日）までは21日です。」**

通知したいテキストが完成！
テキストは自由にカスタムしたり、当日はメッセージを変えたりしても良いかもしれません。　　
　
他にも、ゴミの日のデータなど固定であればGitHub Pagesに日時のJSONを置いてそれをAPIと見立てて扱っても良き。
　
　

### ・通知例２ 『スクレイピングして取得』


今回はサンプルコードとして下記の悩みがあったとして解決したいと思います。
『**阿部 寛さんのホームページの彼の画像がリンク切れていないか毎日心配で見ているという悩み**』

つまりサイト上の物を自動で見回らせて通知させたい。
「〇〇という文字列が含まれた新作商品が出ていたら」「〇〇がどうなっているか」などの応用可能です。

画像が変わる可能性があるので直接画像URLを指定してリンク切れを判別するのではなく、ページから画像を取得してからリンク切れかを判別させます。

```python:阿部寛さんの画像が見れているか
# スクレイピングにライブラリ「BeautifulSoup」を扱う
from bs4 import BeautifulSoup
import requests

# 阿部 寛さんのホームページのURL
url = 'http://abehiroshi.la.coocan.jp/'
# iframeで別HTMLを読んでるみたいなのでページのURL
page_url = 'top.htm'

# ページのデータを取得
response = requests.get(url + page_url)
html = response.content
soup = BeautifulSoup(html, "html.parser")
# HTMLデータから画像を探す
img_src = soup.find("img").get("src")

# 画像にアクセス
resp = requests.get(url + img_src)
# 404なら知らせる
if resp.status_code == 404:
    abe_text = '阿部 寛さんの画像リンクが切れています。'
else:
    abe_text = '画像は今日も問題ないです。'

print(abe_text)   # 画像は今日も問題ないです。
```


　**「画像は今日も問題ないです。」**

簡単に通知したいテキストが完成！

ここではスクレイピングに便利な`BeautifulSoup`というライブラリを扱います。
スクレイピングを行う場合はサイトへの妨害にならない範囲で注意しよう。

スクレイピングの基礎は前に書いた事があるので興味ある方はどうぞ↓
[【Python】猫でも出来るWebスクレイピングの基礎【BeautifulSoup4】 - Qiita](https://qiita.com/aocattleya/items/2eab8ad744d9a28fb9ce)　
　
　


## 📫 通知させる（Twitter、Slackなど）

巡回して取得した「**祝日までの日付**」「**阿部寛さんの画像が見れているか**」のテキストを繋げて好みのアプリに通知します。

### ・ Slackの場合

どこのSlackのチャンネルに通知するかの為に、Slackアプリの一つ『**Incoming Webhooks**』を利用します。
通知するにはそのSlackチャンネルのWebhookURLの取得が必要になります。

WebhookURLの取得については「WebhookURL　取得」などで調べるとすぐ出るかと思います。

```python:SlackAPIを使った通知
# jsonを扱うので読み込む
import json

# 取得したWebhookURL
webhook_url = "https://hooks.slack.com/services/hoge/piyo/huga"
# 「祝日までの日付」と「阿部寛さんの画像が見れているか」を好きに繋げる
text = "今日の巡回結果だよ！\n\n" + holiday_text + '\n' + abe_text
# Slack通知
requests.post(webhook_url, data=json.dumps({
    "text" : text,
    "icon_emoji" : ":aocattleya:",
    "username" : "巡回Botちゃん"
}))
```

**結果**
![SlackBot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/d907200e-ebb5-5d21-fd64-1eb724a11495.png)

こうして阿部寛さんの画像リンクのために毎日サイトにアクセスする悩みが解決出来ました。
　
### ・ Twitterの場合

Twitter廃人なのでツイッター通知しか勝たん！という場合です✊
　

１、Twitterに呟くためのTwitter APIキーとトークンが必要なので取得しよう。

https://developer.twitter.com/en/apps/

`Create an app`を選択して利用目的などの申請が必要です。
自分の場合は特に見て審査されたという感じも無くすぐにキーを使えた記憶があります。
参考になりそうな良さげなリンクを貼っておきます。

https://www.itti.jp/web-direction/how-to-apply-for-twitter-api/


申請を行った,または既に行っていた場合は、`Create an app`を再度選択してアプリを作成しアプリの上部の`Keys and tokens`を選択してTwitter APIキーとトークンを取得します。



取得したキーは、`.env`で管理します。

```shell:ターミナル
pip install python-dotenv
```



```shell:.env
# 取得したキー
TW_CONSUMER_KEY=''
TW_CONSUMER_SECRET=''
TW_TOKEN=''
TW_TOKEN_SECRET=''
# SlackのWebhookURLもここで管理するのが良さそう
HOOKS_SLACK_KEY=''
```

取得したキーを読み込んでTwitterに呟きます。

```python:main.py
from bs4 import BeautifulSoup
import requests, json, os
from twitter import *
from dotenv import find_dotenv, load_dotenv

# .env読み込み
load_dotenv(find_dotenv())
TW_CONSUMER_KEY = os.environ.get('TW_CONSUMER_KEY')
TW_CONSUMER_SECRET = os.environ.get('TW_CONSUMER_SECRET')
TW_TOKEN = os.environ.get('TW_TOKEN')
TW_TOKEN_SECRET = os.environ.get('TW_TOKEN_SECRET')

# TwitterAPIを使う
t = Twitter(auth=OAuth(TW_TOKEN, TW_TOKEN_SECRET, TW_CONSUMER_KEY, TW_CONSUMER_SECRET))
# 自分宛にリプライで通知させる（holiday_text、abe_textは、上記で作成したデータ）
text = "@test 今日の巡回結果だよ！\n\n" + holiday_text + '\n' + abe_text

# 140文字の制限があるのでテキストを短くするなど工夫しよう
if len(text) > 140:
    # Slack通知に切り替えるのもあり
    text = "今日の巡回結果だよ！\n\n長いからSlackを見てね！"

# Twitterに通知
t.statuses.update(status=text)
```

**結果**
![TwitterBot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/6fffebca-5943-5958-e721-b7fe7329787d.png)

ツイッター通知が一番気づきやすい人はとても助かりますが、不特定多数に見られて大丈夫な物にしましょう。
他にも阿部寛さんの画像リンクが切れていないか毎日アクセスしている人がいるかもしれないので専用アカウントとして運用しても良いですね。　　

さらに細かく書くと、
連続して同じツイートは出来ないので現在時間を文言に追加したり、スクレイピング中にサイトの方に問題があった時にエラーが発生するので例外処理を入れて例外を踏んだ場合は、エラー文をSlackの方に飛ばすなど小さな気遣いは必要になります。
ここは運用してから気付ける物も多いので日々アップデートです。
 　
　

 

## 🌐 定期実行させる

必要なデータを取得して通知したいテキストを作成し、それを通知させるプログラムが完成しました。
次にこれを定期実行させて自動で通知させてきます。

<a href="https://heroku.com/"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/3869fb76-52d4-9f4e-3449-cbdcc92021b1.png" width="200px"/></a>
今回はHerokuを使って自動でプログラムを定期実行させます。

Herokuに登録して、`Heroku CLI`をインストールします。

https://devcenter.heroku.com/articles/getting-started-with-python#set-up

こちらにスターターガイドがあるのでそのまま実行します。
Heroku内でGitを扱うのでGitのインストールも必要です。

例えばMacの場合は以下のコマンド、ログインするとブラウザが立ち上がります。

```shell:ターミナル
#　インストール
brew install heroku/brew/heroku
# Herokuにログイン
heroku login
```

Heroku側に必要なライブラリの環境を用意する必要があるので、`requirements.txt`を作成しておきましょう。
Pythonのライブラリのリストみたいなものが書かれたファイルが生成されます。

```shell:ターミナル
pip freeze > requirements.txt
```

よく見ると、さっき入れた`python-dotenv`などもここに入っている事が確認できます。

HerokuにPushします。（エラーが出たら翻訳してググろう）

```shell:ターミナル
git init
git add main.py
git add requirements.txt
git commit -m 'initial commit'

heroku create
git remote add heroku https://git.heroku.com/xxxx-xxxxx-12345.git
git push heroku master
```

Herokuの環境変数では以下で設定出来ます。簡単

```shell:ターミナル
heroku config:set TW_CONSUMER_KEY="xxxxxxxxxxxxxxxxx" -a Herokuのアプリ名
heroku config:set TW_CONSUMER_SECRET="xxxxxxxxxxxxxxxxx" -a Herokuのアプリ名
heroku config:set TW_TOKEN="xxxxxxxxxxxxxxxxx" -a Herokuのアプリ名
heroku config:set TW_TOKEN_SECRET="xxxxxxxxxxxxxxxxx" -a Herokuのアプリ名
# 確認する場合
heroku config:get TW_CONSUMER_KEY -a Herokuのアプリ名
```

プログラムをHerokuにPush完了し、環境変数も設定したら実行してみます。

```shell:ターミナル
heroku run python main.py
```

これでHeroku上からの実行が成功しました。
![TwitterBot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/6fffebca-5943-5958-e721-b7fe7329787d.png)


次に、『**Heroku Schduler**』を利用してHeroku上で定期実行させる設定をしましょう。

```shell:ターミナル
heroku addons:create scheduler:standard --app Herokuのアプリ名
```

基本無料ですが、無料枠を超えた時のためにクレジットカードの設定が必要です。
そのまま表示されたURLにアクセスして設定します。

```
 ▸  Please verify your account to install this add-on plan (please enter a credit card) For more information, see
 ▸  https://devcenter.heroku.com/categories/billing Verify now at https://heroku.com/verify
```
クレジットカードを設定したらそのままコマンドを再度実行し、Heroku上にスクジューラーのアイコンが表示されました。
![Heroku Schduler](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/3a5052c0-b4ed-41ec-1bf9-180577d29ec1.png)

上部の`Resources`タブからを`Heroku Schduler`選択しさらに`Create job`を選択します。

![スクリーンショット 2021-09-06 10.21.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/3d80d1f7-d5f6-9a5d-b8de-85ee2f046636.png)
実行コマンドは対応するコマンド、Pythonだと`python main.py`など

タスクの間隔は「10分に1回」「1時間に1回」「1日1回」で、今回の場合では1日1回で飛ばします。
注意するところは、UTC時間なので9時間の差がある日本時間に置き換えて考えて設定する必要があります。
![スクリーンショット 2021-09-06 10.23.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/572817ff-51c1-bded-6e6f-9e9cf5615a2a.png)
これにて1日1回巡回した結果を通知してくれる便利Botの完成です。

あとは好きにカスタマイズして自分だけの便利Botを作ってみるといいですね！
![TwitterBot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/fbe312ea-f28b-e044-d195-7cd51a0a1e70.png)


## まとめ

このBotは手軽に作れるので個人的にも運用しているのですが、
初めは定期的にチェックしている物を自動で通知させたい...から始まり、今日の天気を通知させたり今では毎日色々と巡回して通知してくれる便利なBotになっています。

という事で、簡単なコードと定期実行を組み合わせるだけで便利なBotが作成できました。
何かを自動化させたいという興味ある方はぜひ作ってみてください！
　

**おまけ**
祝日までが長く毎日悲しい通知が飛んで来る日の図
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/f3d72e66-ad1b-9f9f-76cb-2fffece1ecef.png" width="700px" alt="残念でした" />

おわり。
記事のLGTM:+1:やコメントなど貰えたらとても励みになります。
　

📄 　**書いた過去記事**
・[【GitHub】README.mdをカッコ可愛くデザインしてアプリの魅力を120%にする](https://qiita.com/aocattleya/items/5f836e9c65ba3eb3af03)
・ [CSSアニメーションとJSで『崩壊するサイト』を簡単に作る](https://qiita.com/aocattleya/items/485174fde66d4f957788)
・ [Vue.jsとCSSアニメーションでラーメンタイマーを作る + Firebaseで簡単公開](https://qiita.com/aocattleya/items/3faa42b5d27a0f608785)

<a href="https://hrmos.co/pages/vivion/jobs?"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/452a6198-5ce1-0f65-a81d-93a58e6bd07f.png" width="300px"/></a>