やったこと
1日1回、MyDocomoから今月の通信量を取得してLINE Notifyでお知らせするプログラムを作りました。
また、これをHerokuで定期実行する環境を作りました。
使ったもの
1日1回実行するために...
- Heroku
- Heroku Scheduler
今月の通信量を取得するために...
- Python3 (言語)
- Selenium (ブラウザ自動操作ツール)
- Chrome (ブラウザ)
- Chrome Webdriver (Chromeを自動操作するためのドライバ)
作成したファイル
今回作成したファイルは以下のとおりです。
$ ls
Procfile
main.py
requirements.txt
README.md
mydocomo.py
Procfile
Procfileは、Herokuのプラットフォーム上にあるアプリケーションのdynosにより実行されるコマンドが 何であるかを宣言するためのメカニズム
(https://github.com/herokaijp/devcenter/wiki/procfile より引用)
web: python main.py
main.py
Webアプリに適用するダミーのコード。
よく分かってはいませんがWebアプリにはダミーを置いておくもののようです。
おそらく、誰かにWebアプリに対してリクエストを送られたタイミングで定期実行用のプログラムが動かないようにするため?だと解釈しています。
# -*- coding: utf-8 -*-
import os
from bottle import route, run
@route("/")
def hello_world():
return "" # ここで返す内容は何でもよい
run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
requirements.txt
必要なライブラリを記載しておくファイル。
これに記載したライブラリは、デプロイのたびにHerokuの環境へ自動インストールされるらしい。便利。
pipをインストール済みの場合、↓のコマンドを打つとインストール済みのライブラリを出してくれて楽でした。
$ pip freeze -l > requirements.txt
astroid==2.2.5
beautifulsoup4==4.7.1
bottle==0.12.16
certifi==2019.3.9
chardet==3.0.4
chromedriver-binary==74.0.3729.6.0
Click==7.0
colorama==0.4.1
Flask==1.0.2
future==0.17.1
idna==2.8
isort==4.3.16
itsdangerous==1.1.0
Jinja2==2.10
lazy-object-proxy==1.3.1
line-bot-sdk==1.8.0
MarkupSafe==1.1.1
mccabe==0.6.1
PyLink==0.3.3
pylint==2.3.1
pyserial==3.4
requests==2.21.0
rope==0.14.0
selenium==3.141.0
six==1.12.0
soupsieve==1.9
typed-ast==1.3.1
urllib3==1.24.1
Werkzeug==0.15.2
wrapt==1.11.1
インストール済みのライブラリが全て出てくるので、今回の実行には不要なライブラリも含まれちゃうみたいです。
README.md
なくても良いので割愛します。
mydocomo.py
定期実行するプログラム本体。
MyDocomoにログインする際のID、PW、LINE Notifyのトークンは、Herokuの環境変数に設定しました。
# coding: UTF-8
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os
import requests
import sys
# 環境変数からトークンなどの情報を取得
notify_access_token = os.getenv('NOTIFY_ACCESS_TOKEN', None)
docomo_id = os.getenv('DOCOMO_ID', None)
docomo_pw = os.getenv('DOCOMO_PW', None)
if notify_access_token is None:
print('Specify NOTIFY_ACCESS_TOKEN as environment variable.')
sys.exit(1)
if docomo_id is None:
print('Specify DOCOMO_ID as environment variable.')
sys.exit(1)
if docomo_pw is None:
print('Specify DOCOMO_PW as environment variable.')
sys.exit(1)
# 通信量の取得
def getLog():
# Selenium用オプション
op = Options()
op.add_argument("--disable-gpu")
op.add_argument("--disable-extensions")
op.add_argument("--proxy-server='direct://'")
op.add_argument("--proxy-bypass-list=*")
op.add_argument("--headless")
driver = webdriver.Chrome(chrome_options=op)
driver.get('https://www.nttdocomo.co.jp/auth/cgi/mltdomanidlogin?rl=https%3A%2F%2Fwww.nttdocomo.co.jp%2Fmydocomo%2F')
# ID入力
id = driver.find_element_by_id("Di_Uid")
id.send_keys(docomo_id)
# 「次へ」クリック
login_button = driver.find_element_by_name("subForm")
login_button.click()
# PW入力
password = driver.find_element_by_id("Di_Pass")
password.send_keys(docomo_pw)
# 「ログイン」クリック
login_button = driver.find_element_by_name("subForm")
login_button.click()
# 通信量のページへ遷移
driver.get("https://www.nttdocomo.co.jp/mydocomo/data/")
dataSpan = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "#mydcm_data_data-08 > div > dl > dd > p.mydcm_data_data-09-1 > span.card-t-ssnumber.t-bold.mydcm_data_data-10-1"))
)
return dataSpan.text
def main():
mount = getLog()
url = "https://notify-api.line.me/api/notify"
token = notify_access_token
headers = {"Authorization" : "Bearer "+ token}
message = '今月の通信量は ' + mount + ' GBです。'
payload = {"message" : message}
r = requests.post(url ,headers = headers ,params=payload)
if __name__ == '__main__':
main()
Herokuの設定
GUIが大好きなのでHerokuのアプリケーションのページから設定しました。
Heroku CLIをインストールしてCUIで設定しても良いです。
buildpackの追加
Heroku上でChromeとChrome Webdriverを使うためにbuildpackというものを追加します。
Settings
タブのbuildpacks
からAdd buildpack
をクリックして、以下のURLを1つずつ追加します。
https://github.com/heroku/heroku-buildpack-google-chrome.git
https://github.com/heroku/heroku-buildpack-chromedriver.git
環境変数の設定
Settings
タブのConfig Vars
からReveal Config Vars
をクリックして、以下の変数を追加します。
変数名 | 値 |
---|---|
CHROME_BINARY_LOCATION | /app/.apt/usr/bin/google-chrome |
CHROME_DRIVER_PATH | chromedriver |
DOCOMO_ID |
hogehoge@hogehoge.com (MyDocomoのID) |
DOCOMO_PW | hoge(MyDocomoのパスワード) |
NOTIFY_ACCESS_TOKEN | 取得したLINE Notifyのトークン |
TZ | Asia/Tokyo |
TZは今回設定しなくても良いですが、合わせておいた方が何かと便利かと思います。
※とりあえず動作テスト
ここまで設定しておいてデプロイすれば、(おそらく)一旦は動くようになっていると思います。
コンソールからmydocomo.py
を実行してみます。
Herokuのアプリケーションのページの右上にあるMore
から、Run console
をクリックし以下のコマンドを実行します。
python mydocomo.py
Herokuのサーバーがスリープ状態だと実行までに時間がかかるみたいです。
しばらく待ってもLINEの通知が来なかったらLog等を確認してみてください。
問題なければ30秒も待てば通知が来ると思います。
Heroku Schedulerの設定
※Heroku Schedulerのインストール方法は割愛します。
Resource
タブのHeroku Scheduler
をクリックし、ジョブの管理画面を開きます。
ジョブの管理画面でAdd Job
をクリックします。
Schedule
Schedule
はEvery day at...
を選び、
時間は私の場合、3:00 PM
を選びました。
設定する時間は世界協定時
での設定になるため、
日本の時刻は設定する時間+9時間
で考えます。
→UTC午後3時を設定すると、日本時刻では午前0時となります。
Run Command
Run Command
は先程の動作テストで流したコマンドです。
python mydocomo.py
これで毎日0時に今月の通信量がLINE Notifyに通知されるようになります。
課題
Pythonの勉強がてら試しに作ったので取得するデータは今月の通信量
だけですし、通知されるメッセージも簡素です。
多少の実用性を考えるのであれば、使いすぎた日の翌日だけ通知するとかにした方が良さそうです。
参考ページ
大変お世話になりました。