Hobby Science&Experiment

愛と工作の日々

趣味でやっている工作や勉強したことのメモ書きです。

PythonでWeb漫画の更新をLine通知する

ONEさんのWeb漫画「ワンパンマン」が好きなのですが、更新されたことに気付くのにいつも遅れてしまいます。「1日一回自動で更新をチェックし通知するプログラム」を作ってみたいと思います。ついでにWebスクレイピングの勉強もしてしまおうという魂胆です。

ライブラリインポート

BeautifulSoup4なるライブラリが必要です。何なんでしょうこの名前…。

sudo pip install BeautifulSoup4

ページ上のHTML情報を取得する。

import requests
from bs4 import BeautifulSoup
# Webページを取得して解析する

load_url = "http://galaxyheavyblow.web.fc2.com/"
html = requests.get(load_url)
soup = BeautifulSoup(html.content, "html.parser")

# HTML全体を表示する
print(soup)

結果

<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-type"/>
<meta content="text/javascript" http-equiv="Content-Script-Type"/></head></html>
<title>ワンパンマン</title>

<body link="#000000" style="background:#D2B48C" vlink="#000000">
<font color="#000000">
<br/>
<center>
<h1>ワンパンマン</h1>
<br/>
<div id="bgi"><img alt="" height="848" src="/top.jpg" width="600"/></div>
<br/>
<br/>
<a href="http://tonarinoyj.jp/" target="_blank"><img alt="" border="0" height="162" src="/tonarino.jpg" width="600"/> </a><br/>
<p>『となりのヤングジャンプ』で連載中。(2012614日〜)</p>
<br/><iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/p7fWKezF4iU" width="560"></iframe>
<br/><br/>
<a href="http://urasunday.com/" target="_blank"><img alt="" border="0" height="162" src="/urasunday.jpg" width="600"/> </a><br/>
<p>『裏サンデー』で連載中。(2012418日〜)</p>
<br/><iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/_E0wbdZZKRc" width="560"></iframe><br/>
<br/>
<a href="touhyou2016.html">【原作】第3回キャラクター人気投票結果発表【ワンパンマン】</a><br/><br/>
<p>※画像が表示されないときは、再読み込みするか、表示されない画像を右クリックして『画像の表示』を選ぶと表示されます。画像が中途半端に表示されたときは、時間をおいて再読み込みするといいみたいです。</p>
<a href="/fc2-imageviewer/?aid=1&amp;iid=2">第1話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=3">第2話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=4">第3話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=5">第4話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=6">第5話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=7">第6話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=8">第7話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=9">第8話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=10">第9話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=11">第10話</a><br/>
・
・
・
=1&amp;iid=122">第121話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=123">第122話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=124">第123話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=125">第124話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=126">第125話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=127">第126話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=128">第127話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=129">第128話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=131">第129話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=132">第130話</a><br/>
<a href="/fc2-imageviewer/?aid=1&amp;iid=133">第131話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=134">第132話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=135">第133話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=136">第134話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=137">第135話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=138">第136話</a> <a href="/fc2-imageviewer/?aid=1&amp;iid=139">第137話</a><br/>
          2021年1月22日 137話更新 <br/>
<a href="http://twitter.com/ONE_rakugaki">twitter</a> <a href="http://form1.fc2.com/form/?id=498522">mail</a> <br/>
<br/>
<br/>
<script language="JavaScript" src="http://counter1.fc2.com/counter.php?id=4851767" type="text/javascript"></script><noscript><img src="http://counter1.fc2.com/counter_img.php?id=4851767"/></noscript>
</center>
<br/>
</font>
<script type="text/javascript"><!--
var fc2footerparam = 'charset=' + (document.charset ? document.charset : document.characterSet) + '&url=' + document.location + '&service=0&r=' + Math.floor(Math.random()*99999999999);
var fc2footertag = '<' + 'script src="//vip.chps-api.fc2.com/apis/footer/?' + fc2footerparam + '" charset="UTF-8"><' + '/script>';
document.write(fc2footertag);
//--></script>
<!-- FC2, inc.-->
<img alt="inserted by FC2 system" height="0" src="//media.fc2.com/counter_img.php?id=50" style="visibility:hidden" width="0"/>
<!-- FC2, inc.-->
</body>

HTMLが丸っと抽出されました。もちろんこのままでは何のこっちゃですのでここから特定のタグのみを抽出します。

タグで抽出する

HTML情報の中から特定のタグのみを抽出することが出来ます。第〇話という文字列はいずれも"a"というタグが付いていますので、これで抽出してみようと思います。

import requests
from bs4 import BeautifulSoup
# Webページを取得して解析する

load_url = "http://galaxyheavyblow.web.fc2.com/"
html = requests.get(load_url)
soup = BeautifulSoup(html.content, "html.parser")

# HTML全体を表示する
print(soup.find_all("a"))

結果

[<a href="http://tonarinoyj.jp/" target="_blank"><img alt="" border="0" height="162" src="/tonarino.jpg" width="600"/> </a>, <a href="http://urasunday.com/" target="_blank"><img alt="" border="0" height="162" src="/urasunday.jpg" width="600"/> </a>, <a href="touhyou2016.html">【原作】第3回キャラクター人気投票結果発表【ワンパンマン】</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=2">第1話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=3">第2話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=4">第3話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=5">第4話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=6">第5話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=7">第6話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=8">第7話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=9">第8話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=10">第9話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=11">第10話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=12">第11話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=13">第12話
・
・
aid=1&amp;iid=134">第132話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=135">第133話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=136">第134話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=137">第135話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=138">第136話</a>, <a href="/fc2-imageviewer/?aid=1&amp;iid=139">第137話</a>, <a href="http://twitter.com/ONE_rakugaki">twitter</a>, <a href="http://form1.fc2.com/form/?id=498522">mail</a>]

第〇話という部分がかなり抽出できましたが、まだごちゃごちゃしています。ここからは通常のリストの処理になります。

文字列を抽出する

先ほど抽出したリストの各要素をfor文で取り出し、かつその要素の文字列部分を".text"により取り出しています。また"第" と "話"を含む要素のみを取り出すことでページ上の話数を得ます。

import requests
from bs4 import BeautifulSoup
# Webページを取得して解析する

load_url = "http://galaxyheavyblow.web.fc2.com/"
html = requests.get(load_url)
soup = BeautifulSoup(html.content, "html.parser")

for element in soup.find_all("a"):    # すべてのaタグを検索して表示
    if "第" and "話" in element.text:
        print(element.text)

結果

第1話
第2話
第3話
第4話
・
・
第135話
第136話
第137話

必要な情報は抽出できました。あとは通知プログラムとして完成させるだけです。

完成版のプログラム

話数を取得し情報をログ("onepunch_log.txt")として保存します。前回実行時のログと今回の話数を比較し、異なればLINEで通知するようになっています。LINE送信のコードについてはこちらの記事にまとめました。

import requests
from bs4 import BeautifulSoup
import os

def get_latest_ep():#話数を取得
    load_url = "http://galaxyheavyblow.web.fc2.com/"
    html = requests.get(load_url)
    soup = BeautifulSoup(html.content, "html.parser")#全HTML全体
    for element in soup.find_all("a"):    # すべてのaタグを検索
        if "第" and "話" in element.text: # 要素を文字列化し、話数を抽出
            latest_ep = element.text
    return latest_ep

def log_check(content):#最新話かどうか判定
    logfile_name = "onepunch_log.txt"
    if not os.path.exists("./"+logfile_name):#ログファイルの存在を確認
        file = open(logfile_name, 'w')#なければ作る
    file = open(logfile_name, 'r')#読み取りでファイルを開く
    if file.readline() == content:
        checker = False
    else:
        checker = True
        file = open(logfile_name, 'w')
        file.write(content)
        file.close()    
    return checker

def send_line(text):#ライン送信
    url ='https://notify-api.line.me/api/notify'
    token = "トークンを張り付け"
    headers ={'Authorization' : 'Bearer ' + token}
    message = "ワンパンマン(ONE版)"+text+"が更新されました"
    payload = {'message' : message}
    p = requests.post(url, headers=headers, data=payload)
    print(p)

if __name__ == "__main__":
    latest_episode = get_latest_ep()
    if log_check(latest_episode):
        send_line(latest_episode)

定期実行

ラズパイのcrontabで定期実行を行います。頻繁にアクセスすると迷惑となりますので、1日に一回、12:20分に実行することにしました。

20 12 * * * sudo python3 /home/pi/210205_one_punch_man.py

動作

こんな感じで通知が来ます。実際に更新通知はまだ来てないですが、来る日を楽しみにしています!
f:id:tara-chang:20210214195736p:plain
※追記 動作確認出来ました。