なろうの更新通知をLINEで受け取る。

# 背景とやったこと
更新頻度の低い小説をいちいち目視で更新確認するのが面倒だったので、最新話の更新を検知して通知をLINEで受け取れるツールを作成した。

# プログラム実行環境

 - macOS Big Sur バージョン1.5

# 使用した技術および言語

 - LINE Notify

 - なろう小説API

 - Python3.9.1

 - crontab(プログラムの定期実行に使用)

# コード全体

なろうAPIで最新話数の取得を行い、更新されていた場合LINE Notifyで更新通知を行う。


```python:syosetu_notify.py
import requests
from bs4 import BeautifulSoup
import re

def main():

    #通知用LINE Notifyの設定
    notify_url = 'https://notify-api.line.me/api/notify'
    notify_token = 'ここにトークンを貼り付け'
    headers = {"Authorization" : "Bearer "+ notify_token}

    #前回のプログラム実行時に保存された最新話の確認
    f = open('/path/to/current_chapter_syosetu.txt', 'r')
    previous_chapter_number = f.readline()
    f.close()

    #小説の最新話の話数を取得する
    res = requests.get('https://api.syosetu.com/novelapi/api/?of=ga&ncode=小説コード')
    soup = BeautifulSoup(res.text, 'html.parser')
    text = soup.get_text()
    current_chapter = re.search('general_all_no: [0-9]+', text)
    current_chapter_text = current_chapter.group()
    current_chapter_num_search = re.search('[0-9]+', current_chapter_text)
    current_chapter_number = current_chapter_num_search.group()

    #保存された話数とサイトから取得した話数が異なっていれば更新されたと判断する
    if current_chapter_number != previous_chapter_number:

        #最新話の更新通知メッセージ
        notify = '最新話'+current_chapter_number+'が更新されました！'
        payload = {"message" : notify}
        requests.post(notify_url, headers = headers, params = payload)

        #Line通知時に、トーク内に小説のリンクを貼る(任意)
        syosetu_link = 'https://ncode.syosetu.com/小説コード/'
        payload = {"message" : syosetu_link}
        requests.post(notify_url, headers = headers, params = payload)

        #保存する話数を更新
        f = open('/path/to/current_chapter_syosetu.txt','w')
        f.write(current_chapter_number)
        f.close()

if __name__ ==  '__main__' :
    main()


```

### LINE Notifyの設定部分

```python
    #通知用LINE Notifyの設定
    notify_url = 'https://notify-api.line.me/api/notify'
    notify_token = 'ここにトークンを貼り付け'
    headers = {"Authorization" : "Bearer "+ notify_token}
```

#### トークンの入手
[LINE Notify](https://notify-bot.line.me/ja/) にログインして、マイページに移動すると画面下部にトークンの発行できるフォームがある。トークン発行のボタンを押し、LINE Notifyと連携するトークを選択する(選択したトークに通知が送信される)。 その後発行されたトークンを `notify_token` の部分に貼り付ける。


![スクリーンショット 2021-08-01 8.11.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1521871/35bcb2ee-54df-5a19-d856-9277e217b80a.png)

### 現在保存されている最新話の確認

```python
    #前回のプログラム実行時に保存された最新話の確認
    f = open('/path/to/current_chapter_syosetu.txt', 'r')
    previous_chapter_number = f.readline()
    f.close()
```

`current_chapter_syosetu.txt` に更新前の最新話数を保存する。
`syosetu_notify.py` の初回実行時に `current_chapter_syosetu.txt` が空のままだと話数の比較ができないため予め話数を記入しておく。2度目以降の実行では自動で更新されるので触らなくて良い。
`previous_chapter_number` に `current_chapter_syosetu.txt` から読み込んだ話数が格納される。

### 最新話数の取得

```python
    #小説の最新話の話数を取得する
    res = requests.get('https://api.syosetu.com/novelapi/api/?of=ga&ncode=小説コード')
    soup = BeautifulSoup(res.text, 'html.parser')
    text = soup.get_text()
    current_chapter = re.search('general_all_no: [0-9]+', text)
    current_chapter_text = current_chapter.group()
    current_chapter_num_search = re.search('[0-9]+', current_chapter_text)
    current_chapter_number = current_chapter_num_search.group()
```

#### なろう小説API

詳しい案内は[こちら](https://dev.syosetu.com/man/api/)。
今回は特定の小説に対して、APIを用いて最新話の取得を行なっている。
`https://api.syosetu.com/novelapi/api/?of=ga&ncode=小説コード` について
`of` パラメータの `ga` で話の総数、`ncode` パラメータで小説ごとに割り振られたIDを指定する。
小説のIDは、なろうのサイトで該当する作品の小説情報を参照する。
`current_chapter_number` にAPIで取得した最新話数(正確には総話数)が格納される。

## 話数の比較

```python
    #保存された話数とサイトから取得した話数が異なっていれば更新されたと判断する
    if current_chapter_number != previous_chapter_number:

        #最新話の更新通知メッセージ
        notify = '最新話'+current_chapter_number+'が更新されました！'
        payload = {"message" : notify}
        requests.post(notify_url, headers = headers, params = payload)

        #LINE通知時に、トーク内に小説のリンクを貼る(任意)
        syosetu_link = 'https://ncode.syosetu.com/小説コード/'
        payload = {"message" : syosetu_link}
        requests.post(notify_url, headers = headers, params = payload)

        #保存する話数を更新
        f = open('/path/to/current_chapter_syosetu.txt','w')
        f.write(current_chapter_number)
        f.close()
```

前述の `previous_chapter_number` と `current_chapter_number` を比較して、両者の値が異なっていれば小説が更新されたとみなしてLINEで通知する。
その後更新された話数を `current_chapter_syosetu.txt` に上書きする。
`notify` や `syosetu_link` の部分はLINEトーク中にメッセージとして表示される部分であり適宜いじって問題ない。

## crontab

以上のプログラムをcrontabで自動実行する。なろうAPIはこの記事の執筆時点(2021年 8月1日)でアクセス数に特に制限はないが、プログラムを走らせるたびにサイトへアクセスが発生するのは確かなので、実行間隔はほどほどに(自分の場合は1日1回ペース)。


# ふりかえり
作った後で調べてみたらメールを介して通知を受け取れるサービスは既に存在するようだった。まあLINEで受け取れる方が今風かなということでひとつ。