PythonとHerokuでKindle日替わりセールの情報を送ってくれるslackbotを作ってみる
まずはslackbot
ライブラリとスクレイピングするために必要なライブラリ(requests
とBeautiful Soup
)をインストールする。
$ pip install slackbot $ pip install requests beautifulsoup4
ディレクトリ構造
$ tree . ├── Procfile ├── libs │ ├── __init__.py │ └── my_functions.py ├── plugins │ ├── __init__.py │ └── my_mention.py ├── requirements.txt ├── run.py └── slackbot_settings.py
実装
run.py
とslackbot_settings.py
# -*- coding: utf-8 -*- from slackbot.bot import Bot def main(): bot = Bot() bot.run() if __name__ == "__main__": print('start slackbot') main()
# -*- coding: utf-8 -*- import os # botアカウントのトークンを指定 API_TOKEN = os.environ.get('SLACKBOT_API_TOKEN') # このbot宛のメッセージで、どの応答にも当てはまらない場合の応答文字列 DEFAULT_REPLY = "何言ってんだこいつ" # プラグインスクリプトを置いてあるサブディレクトリ名のリスト PLUGINS = ['plugins']
my_functions.py
は以下の通りです。
# -*- coding: utf-8 -*- import re import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry from bs4 import BeautifulSoup headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36'} def kindle_daily_deal(url): text = '' s = requests.Session() retries = Retry(total=5, backoff_factor=0.1, status_forcelist=[500, 502, 503, 504]) s.mount("https://", HTTPAdapter(max_retries=retries)) html = s.get(url, headers=headers).text.encode('utf-8') soup = BeautifulSoup(html, features="html.parser") # CSSセレクターを使って日替わりセールリストを取得する carousel_list = soup.find('ol', attrs={'class': 'a-carousel'}) # 本のタイトルと著者名を取得する title_author_list = carousel_list.select("[class='a-truncate-full']") # 本の価格を取得する price_list = carousel_list.select("[class='a-price-whole']") res = {} res['title'] = ['『{}』'.format(t.get_text()) for i, t in enumerate(title_author_list) if i % 2 == 0] res['author'] = [re.sub(r"[\n ]", "", a.get_text()) for i, a in enumerate(title_author_list) if i % 2 == 1] res['price'] = ['{}\n'.format(p.get_text()) for p in price_list] for i in range(len(price_list)): text += '📚 '+ res['title'][i] + '\n著者:' + res['author'][i] + '\n価格:' + res['price'][i] return text
my_mention.py
kindleというキーワードに反応して、今日のKindle日替わりセール情報を返事する。
# -*- coding: utf-8 -*- import re from slackbot.bot import respond_to # @botname: で反応するデコーダ from slackbot.bot import listen_to # チャネル内発言で反応するデコーダ from libs import my_functions # 外部関数の読み込み @respond_to(r'kindle', re.I) @listen_to(r'kindle', re.I) def kindle(message): url = 'https://www.amazon.co.jp/Kindle%E6%97%A5%E6%9B%BF%E3%82%8F%E3%82%8A/b/?ie=UTF8&node=3338926051&ref_=sv_nav_ebook_4' text = my_functions.kindle_daily_deal(url) msg = 'ほら!今日のKindle日替わりセールだぞ\n```' + text + '```' message.reply(msg)
デプロイ
requirements.txt
とHerokuの設定ファイルProcfile
を用意する。
$ pip freeze > requirements.txt
Procfile
worker: python run.py
$ heroku config:set SLACKBOT_API_TOKEN=xoxb-xxxxx
環境変数の確認。
$ heroku config
Settingsタブでpython buildpackを追加する。
あとは、Deployタブで書いた通りにコマンドを実行する。
$ heroku login $ git init $ heroku git:remote -a xxx $ git add . $ git commit -am "make it better" $ git push heroku master
さて、プロセスを起動してみる。
$ heroku ps:scale worker=1
プロセスを確認する。
$ heroku ps
プロセスを停止するには、以下のコマンドを実行すれば良い。
$ heroku ps:scale worker=0
ログを見る。
$ heroku logs --tail
定期投稿
日替わりセールなので、やっぱり毎日指定した時間にメッセージを投稿したいです。 Herokuでの定期実行はHeroku Schedulerというアドオンが提供しているが、今回はpython-crontabというライブラリを用いて定期実行を行う。
python-crontabライブラリをインストールする(croniterのインストールも必要になる)。
$ pip install python-crontab $ pip install croniter
cron.py
HerokuのタイムゾーンはUTC
なので、9時間の時差がある。
# -*- coding: utf-8 -*- from crontab import CronTab def main(): cron = CronTab() job1 = cron.new('python3 kindle.py') # 毎日の20:00(JST)に実行する job1.setall('00 11 * * *') for res in cron.run_scheduler(): print('The schedule has been executed.') if __name__ == "__main__": main()
kindle.py
# -*- coding: utf-8 -*- import re import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry from slacker import Slacker from bs4 import BeautifulSoup from slackbot_settings import API_TOKEN headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36'} def kindle_daily_deal(url): # 省略 def main(): url = 'https://www.amazon.co.jp/Kindle%E6%97%A5%E6%9B%BF%E3%82%8F%E3%82%8A/b/?ie=UTF8&node=3338926051&ref_=sv_nav_ebook_4' text = kindle_daily_deal(url) msg = 'ほら!今日のKindle日替わりセールだぞ\n```' + text + '```' slack = Slacker(API_TOKEN) slack.chat.post_message('#reminder', msg, as_user=True) if __name__ == "__main__": main()
Procfile
worker: python run.py cron: python cron.py
プロセスを起動する。
$ heroku ps:scale cron=1
結果はこんな感じ