web漫画の最新話が投稿されるとLINEに通知する【python3】


## はじめに
web漫画は最新話の投稿日が不定期なため、いつ投稿されるか定期的に確認しなければならない。
面倒なので、最新話がアップされたらLINEに通知するプログラムを作成しました。

## 環境
OS:macOS Mojave 10.14
言語：Python3.5.1

## 手順
1.プログラムからLINEに通知
2.スクレピング
3.定期実行

## 1.プログラムからLINEに通知
まず、[こちらのサイト](https://notify-bot.line.me/ja/)からLINENotifyのアクセストークンを発行します。
発行したアクセストークンをコピーして以下のコードを追加します。


```python:lineNotify.py
import requests
from config import config
#! python3
# -*- coding: utf-8 -*-

# LINEに更新を通知する
def lineNotify(text):
    line_notify_token = 'アクセストークン'
    line_notify_api = 'https://notify-api.line.me/api/notify'
    payload = {'message': text}
    headers = {'Authorization': 'Bearer ' + line_notify_token}
    requests.post(line_notify_api, data=payload, headers=headers)

lineNotify('text')
```

pythonでのLINEの通知は[こちら](https://qiita.com/analytics-hiro/items/e42f857bd6b40bc178a3)が参考になりました。




## 2.スクレイピング
今回は[ワンパンマンのサイト](https://tonarinoyj.jp/episode/13932016480028985383)をスクレイピングします。
まず、抽出する情報を見てみましょう。
### 抽出する情報
chromeを利用されている方ならデベロッパーツールを利用してリソースをみてください。
すると、aタグに最新話のurlが埋め込まれているのがわかります。
トップページには３話分掲載されているので、下記のようなurlが３個あるかと思います。
https://tonarinoyj.jp/episode/10834108156636232181

### プログラム
今回、プログラムの作成は[こちらの記事](https://qiita.com/taka-kawa/items/f0597b2f375da7ddbb73)が大変参考になりました。
この記事同様に、プログラムの流れは、
1.最新話のurl取得
2.最新話かどうか判定
3.情報をLINEに通知する

最新話が掲載されている場合、下記のように通知
```
[139話]ワンパンマン
https://tonarinoyj.jp/episode/10834108156636232181
```

最新話が掲載されていない場合、下記のように通知
```
最新話はアップされていません。
https://tonarinoyj.jp/episode/10834108156636232181
```

#### スクレイピングプログラム
```python:extract_web.py
#! python3
# -*- coding: utf-8 -*-

# web漫画の最新話がアップされると通知するシステム

from bs4 import BeautifulSoup
import urllib.request as url_req
from config import config, update_recent_article
from line_notification import lineNotify

first_view = url_req.urlopen(config['web_info']['url']).read()
soup = BeautifulSoup(first_view, "lxml")


def extract_pick_up(soup=soup):
    """
    htmlを詠み込み、最新記事を抜粋
    """
    episodes = soup.find_all("ul", class_="test-readable_product-list series-episode-list ")
    return episodes[0:4]

def extract_url(column):
    """
    エピソードのurlを取得
    """
    episode_html = BeautifulSoup(str(column), "lxml")
    url = episode_html.find("a").get("href")
    return url


def extract_title(column):
    """
    エピソードのタイトルを取得する
    """
    episode_html = BeautifulSoup(str(column), "lxml")
    title = episode_html.find("h4").string
    return title

def extract_update_article(columns):
    """
    更新された記事を抽出
    更新前の最新の記事のindexはconfig.iniで管理
    """
    # 最新の記事番号を取得
    recent_article = config['web_info']['recent_article']
    # 更新された記事のurlを取得
    article_list = []
    update_start = False

    # 最新話の話のurlを取得
    url = extract_url(columns)
    # 記事番号取得
    article_num = url.replace('https://tonarinoyj.jp/episode/', "")

    # タイトル取得
    title = extract_title(columns)

    # 前回取得した最新話かどうか判定
    if not recent_article == article_num:
        article_list.append([title, url])
        recent_article = article_num

    # config更新
    update_recent_article(recent_article)
    if article_list == []:
        return [["最新話はアップされていません", "https://tonarinoyj.jp/episode/13932016480028985383"]]
    return article_list



if __name__ == "__main__":
    episodes = extract_pick_up()
    url = extract_url(episodes[0])
    article_list = extract_update_article(episodes)
    lineNotify(article_list[0])

```

このプログラムを実行することで、ワンパンマンの最新話が掲載されたかどうかを
LINEに通知します。

### LINE通知プログラム
```python:line_notification.py
import requests
from config import config
#! python3
# -*- coding: utf-8 -*-

# LINEに更新を通知する
def lineNotify(article_list):
    line_notify_token = config['line_info']['line_notify_token']
    line_notify_api = config['line_info']['line_notify_api']
    payload = {'message': article_list}
    headers = {'Authorization': 'Bearer ' + line_notify_token}
    requests.post(line_notify_api, data=payload, headers=headers)

```
1.で述べたプログラムに少し改良を加えています。
トークンなどは、設定のiniファイルで管理しています。

### 設定プログラム
```python:config.py
import configparser
import re

config = configparser.ConfigParser()
config.read('config.ini')

# recent_articleの記事番号を更新
def update_recent_article(article_num):
    with open('config.ini', 'r') as f:
        lines = f.readlines()
    with open('config.ini', 'w') as f:
        for line in lines:
            if re.match(r'(recent_article = )', line):
                f.write("recent_article = {}".format(article_num))
                continue
            f.write(line)
```


```python:config.ini
[line_info]
line_notify_token = 'アクセストークン'
line_notify_api = https://notify-api.line.me/api/notify

[web_info]
url = https://tonarinoyj.jp/episode/13932016480028985383
# 前回取得した番号
recent_article = 10834108156636232181

```
extract_web.pyで最新話と過去の話のurlを比較した際、
差分があった場合、過去のurlの番号を最新話の番号に上書きします。

## 3.定期実行
定期実行はcronを利用するとすぐできます。
詳しくは[こちらの記事](https://saba.omnioo.com/note/1233/crontab%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/)を参考にしてください。

## 参考
- [スクレイピングして更新された記事をslackに通知する【python】【BeautifulSoup】](https://qiita.com/taka-kawa/items/f0597b2f375da7ddbb73)
- [PythonでLINEに通知を送る](https://qiita.com/analytics-hiro/items/e42f857bd6b40bc178a3)
- [crontabの使い方](https://saba.omnioo.com/note/1233/crontab%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/)