So-net ゼロSIMの今の使用量を自動で取得するRuby Script

GCP上のRailsで定期実行させるために作ったRuby Code部分について書いてみました．
Mechanize機能の勉強も兼ねてだったので，いろいろ抜けているものもあるかも．

---

# 機能
MechanizeとXPATHを利用して，So-netのゼロSIM使用量確認ページにLoginして今の使用量を取得するRuby Script.
Cronに入れたり，Railsに組み込んだり，して使うことを想定しています．

# やること
Step1 : MechanizeからLoginページ取得
Step2 : Login処理
Step3 : 『利用状況確認』ページに移動
Step4 : 『利用状況確認』ページの内容取得
Step5 : HTMLをParseして『今月のデータ使用量(速報値)』を取得

# Step1 : MechanizeからLoginページ取得

```rb:script.rb
# Mechanize instance生成
agent = Mechanize.new
agent.user_agent_alias = 'Linux Mozilla'

# LoginページのHTMLをGET
login_page = agent.get('https://www.so-net.ne.jp/retail/u/')
```

↓ login_page.bodyで取れるHTMLにあるLogin Formはこんな感じ(作成時現在)

```html:Login.html
<!-- 省略 -->

<form name="Login" action="/retail/u/login?realm=/retail/retail_userweb" method="post">
  <table class="inputDataElem">
    <tr>
      <th>
        <label for="simNumber">ログインID<span class="pcCR mL">(半角数字)</span></label>
      </th>
      <td>
        <input type="text" name="IDToken1" class="inputTextL hidden" id="simNumber" maxlength="11" />
        <span class="spCR mL">(例：09011112222)</span>
      </td>
    </tr>
    <tr>
      <th>
        <label for="simPassword">パスワード</label>
      </th>
      <td>
        <input type="password" name="IDToken2" class="inputTextL hidden" id="simPassword" maxlength="16" />
        <span class="spCR mL"></span>
      </td>
    </tr>
  </table>

  <div class="entryElem">
    <label for="" class="submitEntry regular disabled">
      <input type="submit" value="決定" class="inner hidden" id="simSubmit" />
    </label>
  </div>

  <input type="hidden" name="IDButton" value="login" />
  <input type="hidden" name="IDToken0" value="" />
  <input type="hidden" name="goto" value="" />
  <input type="hidden" name="encoded" value="false" />
</form>

<!-- 省略 -->
```
Step2でこのFormに必要な情報をMechanizeからInputしてSubmitする．

# Step2 : Login処理

```rb:script.rb
# Formに情報をInput
login_form = login_page.form_with(:name => 'Login')
login_form.IDToken1 = '090xxxxyyyy'
login_form.IDToken2 = 'password'

# Login Buttonを押してFormの内容をPOST
top_page = agent.submit(login_form)
```
これでLogin処理が完了．Webから操作するよりも素早くLogin処理が完了しているように見える．

# Step3 : 『利用状況確認』ページに移動
Login後のTop Pageの『利用状況確認』ページへのLinkまわりはこんな感じ．


```html:Top.html
<!-- 省略 -->
<ul class="main mainMenu">
  <li class="block">
    <form name="userUsageActionForm" method="post" action="/retail/u/userUsage/">
      <div>
        <input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="8a0e887a8ffdeb7db5a69d1a4662af89">
      </div>
      <label for="menuUseCondition" class="outer">
        <input type="submit" name="index" value="ご利用状況確認" id="menuUseCondition" class="inner">
      </label>
    </form>
  </li>
</ul>
<!-- 省略 -->
```
『利用状況確認』のLinkボタンは内部ではFormになっていて，HiddenのParameterをPOSTしている模様．
このPOSTをMechanizeから発行することでページ移動する．

```rb:script.rb
# UsageのFormを取得してPOST
usage_form = top_page.form_with(:name => 'userUsageActionForm')
usage_page = agent.submit(usage_form)
```

# Step4 : 『利用状況確認』ページの内容取得
↓ ページ移動後の利用状況確認ページのHTMLはこんな感じ．
(生データはなぜか\<dd\>の中に大量のスペースやTabが入っていたので整形しています)

```html:Usage.html
<!-- 省略 -->
<dl class="useConditionDisplay">
  <dt>今月のデータ使用量(速報値)</dt>
  <dd>67MB</dd>
  <dt>本日のデータ使用量(速報値)</dt>
  <dd>6MB</dd>
  <dt>昨日のデータ使用量</dt>
  <dd>10MB</dd>
  <dt class="end">一昨日のデータ使用量</dt>
  <dd class="end">51MB</dd>
</dl>
<!-- 省略 -->
```
あとはこれをParseして"67"とかの情報を取り出してあげればOK.

# Step5 : HTMLをParseして『今月のデータ使用量(速報値)』を取得
Mechanizeのsearch関数でXPATHが使えるので，これを使ってHTMLをParseする．

```rb:script.rb
usage_list = usage_page.search('//dl[@class="useConditionDisplay"]')
month_used_current_mb = usage_list.search('dd')[0].text.to_i

puts month_used_current_mb # 今月の使用量(速報値)
```

# まとめ
- So-netのサーバ側のErrorに対応するError Handleがない
- Login Fail時のError Handleがない
- So-netページのID名とかの内部仕様が変わったら破綻する

のような課題はあるものの，一応当初の目的の機能は実装できました．
GCP上のRailsに入れて，cronで定期的に情報取得→移動機に通知，という運用ができています．

///---