データ通信残量をLINE通知してくれるスクリプトをつくってみた

一日の終りにデータ通信量の残量をLINEで通知してくれるスクリプトをつくってみました。今回はMySoftBankをスクレイピングしてデータ残量を抽出、Messaging APIを使ってLINEに通知をします。

本記事はこちらの記事（[Pythonでのウェブサイトへのログイン]
(https://qiita.com/morinokami/items/46b76b365f030be83418)）を参考にしました。ログインを伴う高度なスクレイピングについて詳しく説明されているのでとても参考になります。良記事ありがとうございました！

完成形...こんな感じになる...
<img width="375" alt="Photo 2018-07-13 18 01 14.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/213579/3f829808-8de8-7951-9a16-811e84f75fb9.jpeg">


##実行環境と外部モジュール
・MacBook Air Early2015（MacOS High Sierra）

・Python 3.6.2（pip3）

・requests (pip3 install requests)

・buautifulsoup (pip3 install BeautifulSoup4)

##一連の流れ
1，MySoftBankにログインする際アクセス毎にアクセストークンを発行しているのでスクレイピングを行い必要な値を抜き出す。

2, ログインに必要なパラメーターを指定してセッションを行う。

3, 同一セッション内でページ遷移をしてデータ通信量をスクレイピング。

4, データを整形してLINE通知

##コード
###ログイン
MySoftbankのログインページはアクセストークンが予めURLに含まれているので毎回URLが変わっています。（URLが固定されていない）そこでログインページが被リンクされている、[ここ](https://www.softbank.jp/mysoftbank/)の「会員ページ ログイン」のURL（https://my.softbank.jp/msb/d/webLink/doSend/MSB020063） にリクエストを送り、リダイレクトさせたものからスクレイピングをしてアクセストークンを取得する必要があります。

ログインページのHTMLは以下のようになっています。

```html
<form id="authAction" method="post" class="formReset" action="login.php" onfocusout="SMS_AUTH.field.observe(event);" novalidate="">
<input type="hidden" name="ticket" value="ZjI0YzAyNWEtYzk0OS00MzgxLTljNDQtY2NmMzg5MDFiZGY1">

<div class="flex flexMg0 j_ani start" style="">
<div class="bgWh section flex7 spFlex12">
<div class="sectionWrap">

<h2 class="ttlNormal">ログイン</h2>
<div class="inner">

<div class="item messageAdjust required">
<div class="inputArea">
<div class="flex">
<ul class="txtError"></ul>
<p class="inputName flex8 spFlex12">携帯電話番号</p>
</div>
<div class="flex flexMg20 flexMb20 spFlexMg10 spFlexMb10">
<div class="flex8 spFlex12"><input type="tel" class="validate-mobile-number han num" name="telnum" placeholder="" minlength="11" maxlength="11"></div>
</div>
</div>
</div>

<div class="item messageAdjust required">
<div class="inputArea">
<div class="flex">
<ul class="txtError"></ul>
<p class="inputName flex8 spFlex12">パスワード</p>
</div>
<div class="flex flexMg20 flexMb20 spFlexMg10 spFlexMb10">
<div class="flex8 spFlex12"><input type="password" class="validate-password han numalpha" name="password" placeholder="" minlength="8" maxlength="16"></div>
</div>
</div>
</div>
```
アクセストークンである```"ticket"```、電話番号の```"telnum"```、パスワードの```"password"```をパラメーターとして https://id.my.softbank.jp/sbid_auth/type1/2.0/login.php に送られることがわかります。

以下のコードはログインをするためのメソッドです。ticketはBeautifulSoupで抜き出した値を、telnumとpasswordを自分のものに書き換えて実行します。

```Python

def login():
    s = requests.Session()
    r = s.get('https://my.softbank.jp/msb/d/webLink/doSend/MSB020063')
    soup = bs(r.text,'html.parser')
    ticket = soup.find('input',type='hidden').get('value')
    payload = {
        'telnum': '0123XXX4567',
        'password': 'your_password',
        'ticket':ticket
    }
    s.post('https://id.my.softbank.jp/sbid_auth/type1/2.0/login.php', data=payload, proxies=proxies)
    return s
```

###データ残量の取得
実際にMySoftBank内のトップページから「使用量の管理」にページを遷移すると一旦 https://my.softbank.jp/msb/d/webLink/doSend/MRERE0000 というリンクを経てから https://re11.my.softbank.jp/resfe/top/ に遷移していることがわかります。直接re11.my.softbank... から使用量のデータは取れず my.softbank.jp/msb... が発行するアクセストークンをパラメータとして re11.my.softbank... に送る必要があります。

![output.gif](https://qiita-image-store.s3.amazonaws.com/0/213579/8a5bc2c6-9dde-c6a8-6f0b-4f58edd71583.gif)

my.softbank.jp/msb...のhtmlは以下になります。ページがすぐに切り替わってしまいブラウザからはhtmlを確認することができないので、requests.getなどでhtmlをコンソールに表示させて解析しました。

```html
<form action="https://re11.my.softbank.jp/resfe/top/" method="post" name="webLink">
<input name="mfiv" type="hidden" value="rIiXkRb5EghZUxTc"/>
<input name="mfsb" type="hidden" value="X//LixcOOUkAMMWKtxbO8xuDzy/J/tk54UuO3z8kYAIiGzrqGEy07GvE304/YbjhLtdWotFTzUszj6G2cJS/I36TMGl/BAuqNJYlQnXYxXZzmBP3LzfBJyGWPGGPna3JLug4awmDQYrPxEYsyVUFSu3Tu0YSY/gZSYAHcojug3/J35zW8wKq6zPZrXmZl6qL"/>
</form>
```

```"mfiv"```と```"mfsb"```の2つの値をパラメーターとして https://re11.my.softbank.jp/resfe/top/ に送られることがわかります。

以下のコードはMySoftBank内のトップページから「使用量の管理」に遷移してデータ残量を取得するまでです。

```Python
def get_data(s):
    r = s.get('https://my.softbank.jp/msb/d/webLink/doSend/MRERE0000')
    soup = bs(r.text,'html.parser')
    auth_token = soup.find_all('input')
    payload = {
        'mfiv': auth_token[0].get('value'),
        'mfsb': auth_token[1].get('value'),
    }
    req = s.post('https://re11.my.softbank.jp/resfe/top/', data=payload)
    data = bs(req.text,'html.parser')
    match = re.findall('<span>(.+)</span>GB',str(data))
    print(match)
    return match[0],match[1]
```
loginメソッドと殆ど同じ操作をします。データの取得は個人的にあまり好きではないのですが正規表現を使って抜き出しています。（htmlが変更された場合の影響が大きいため）契約プランのデータ残量に先月の繰越残量を加算したものと、今月のデータ残量を返り値とします。

###取り敢えず実行してみる
loginメソッドでセッションオブジェクトを返り値とし、get_dataメソッドの引数とします。

```Python
get_data(login())

#out
('4.31', '6.18')
```

使用可能残量と今月の総残量が確認できると思います。
##全体像

```Python
import re
import requests
from bs4 import BeautifulSoup as bs


def login():
    s = requests.Session()
    r = s.get('https://my.softbank.jp/msb/d/webLink/doSend/MSB020063')
    soup = bs(r.text,'html.parser')
    ticket = soup.find('input',type='hidden').get('value')
    payload = {
        'telnum': '0123XXX4566',
        'password': 'hogettomonster',
        'ticket':ticket
    }
    s.post('https://id.my.softbank.jp/sbid_auth/type1/2.0/login.php', data=payload)
    return s


def get_data(s):
    r = s.get('https://my.softbank.jp/msb/d/webLink/doSend/MRERE0000')
    soup = bs(r.text,'html.parser')
    auth_token = soup.find_all('input')
    payload = {
        'mfiv': auth_token[0].get('value'),
        'mfsb': auth_token[1].get('value'),
    }
    req = s.post('https://re11.my.softbank.jp/resfe/top/', data=payload)
    data = bs(req.text,'html.parser')
    match = re.findall('<span>(.+)</span>GB',str(data))
    return match[0],match[1]


def line(text):
    line_notify_token = 'hogemonGo'
    line_notify_api = 'https://notify-api.line.me/api/notify'
    message = text
    payload = {'message': message}
    headers = {'Authorization': 'Bearer ' + line_notify_token}
    line_notify = requests.post(line_notify_api, data=payload, headers=headers)
    

if __name__ == '__main__':
    data = get_data(login())
    text =  'dataTraffic\n{}GB / {}GB({}%)'.format(data[0],data[1],int(float(data[0])/float(data[1])*100))
    line(text)
```

1, loginメソッドのtelnumを自分の電話番号に
2, loginメソッドのpasswordをMySoftBankのパスワードに
3, lineメソッドのline_notify_tokenを自分のアクセストークンに

以上3点の書き換えでコピペ実行できると思います。（多分...）

crontabなどのスケジューラーを利用して一日一回プログラムを実行すれば便利です。