ISLAND TV更新通知botの作り方(考え方)
今回はオタクブログにはふさわしくない技術屋としての話になるが、できる限りITに見識が薄い人でも読めるように噛み砕いて、2019年3月4日から4月19日に私が何をして、ISLAND TVの更新通知botを作っていたのか説明していく。
事の発端は
島、スクレイピング禁止されてないから更新通知bot的なもの作ってみようかな
— 秋百合 (@akiyuri_stlover) 2019年3月4日
この自分のツイートである。最初はほんの思いつきだった。
ここから16時間後、
マジで今の今までぶっ続けで作ってて、後はついったAPIの使用申請許可待ち。とりあえず更新が来てないか5分ごとに自動で確認して、更新あればメールでお知らせをよこして貰って確認でき次第手動ツイートという、しばらくは半自動で運営します。よろしければご利用ください。 @islandtv_uplog
— 秋百合 (@akiyuri_stlover) 2019年3月4日
ツイート機能以外はほぼ完成まで持ってくることに成功した。
まずはここまでにやったことをざっくり説明していこうと思う。
0、プログラミング
使用言語はPython。スクレイピングにはBeautifulsoup4というライブラリ(ツールのようなもの)を使用した。詳しい仕組みについては後述。ちなみにスクレイピングとは「ウェブサイトから情報を抽出するコンピュータソフトウェア技術のこと」(出典:Wikipedia)である。ISLAND TVの動画にはURLの末尾に必ず数字のIDが付いているので、これを利用して新しいIDの動画がアップロードされているのか確認したのである。
1、Googleアカウント取得
メールアドレスが後述の作業を行うためには必要であり、諸般のセキュリティリスクを考えると現在使用中のものと兼用は考えられなかったので、新規取得した。
2、Herokuアカウント取得
書いたプログラムを定期的に実行するためのクラウドサーバ。最小単位が10分に一度の実行だったので、後半は一日一回プログラムを起動して、プログラム内で時間を調整して30秒に一回程度の新規アップロードチェックを可能にした。
3、Twitterアカウント取得
今回の最終目的がTwitterで、最速で新規アップロード動画をツイートすることだったので、専用アカウントを開設。また、プログラムを通してツイートを行うためにはTwitter APIというものの申請(英語)が必要だったので、こちらも併せて申請を行う。今回の場合は12時間も経たずに申請許可が降りた。
以上を3月4日に行ってプロトタイプを完成させたのちに、アップデートを重ね、公式の更新通知アカウントが出現するまで(4月19日)最速を目指して、主にプログラムの改定を行っていた。
以下に最終版のコメントを入れたコードを記す。コード読むのだるい人はオレンジの文字で書いてある日本語のコメントを見てほしい。
# -*- coding: utf-8 -*-
import json, config
from requests_oauthlib import OAuth1Session
import smtplibfrom email.mime.text
import MIMETextfrom email.utils
import formatdateimport time
import sysimport urllib
from bs4 import BeautifulSoup
#動画サイト更新確認スクレイピング&ツイートプログラム
#author: Akiyuri
#create date: 2019-03-04
#Twitter二段階認証情報をconfigファイルから取得
CK = config.CONSUMER_KEY
CS = config.CONSUMER_SECRET
AT = config.ACCESS_TOKEN
ATS = config.ACCESS_TOKEN_SECRET
#Twitterにログイン
twitter = OAuth1Session(CK, CS, AT, ATS)
#Tweet関数
def tweet(msg):
url = "https://api.twitter.com/1.1/statuses/update.json"
#ツイートテキストをセット
params = {"status" : msg}
#postリクエスト送信=ツイート
res = twitter.post(url, params = params)
if res.status_code == 200: #ツイート成功ログ
print("Success.")
else: #ツイート失敗ログ
print("Failed. : %d"% res.status_code)
#新着動画検索パート
url = "https://j-island.net/movie/play/id/"
lastId = 0
beforeLast = 0
idList = []
#1分ごとに毎日18時間と少し稼働させたい:60/1 * 18 + 10 = 490
for i in range(490):
#現在ID9以上の動画が存在している
movieId = 1
#抜け番も5つ程度現時点で存在する、発見のたびに加算
movieNotFound = 0
#20以上抜け番(動画未アップロード)を確認したらその時間の確認を終了
while movieNotFound < 20:
#スクレイピングURL生成
movieUrl = url + str(movieId)
#スクレイピング開始
html = urllib.urlopen(movieUrl)
soup = BeautifulSoup(html)
pageTitle = "ISLAND TV"
#稀に通信エラーでページ読み込みが間に合わない事例があるが、無視する
if soup.find("title") is None:
pass
else:
#日本語標準出力はACIIと認識されてしまうのでエンコード
#タイトル文字化け対策
pageTitle = soup.find("title").text.encode('utf-8')
#動画ページが正式に存在するID
#動画が存在しないページのタイトルが[ISLAND TV]
if pageTitle != "ISLAND TV":
#動画のタイトル取得
movieTitle = soup.find("div", attrs={'class': 'movieplay-infomation__title-title'}).text.encode('utf-8')
#一度めのループで生成したIDリストに存在=ツイート済み動画
if movieId in idList:
#もうこの動画はツイートした古い動画だから無視
print str("True because old movie id is " + str(movieId))
pass
#初回ループ or 初回ループで生成したIDリストに存在しない
else:
#新しい動画だ!ツイートだ!
print str("False because new movie id is " + str(movieId))
print str(movieId) + ":" + str(movieTitle) + ":" + movieUrl
#初回ループではなく、初回ループで生成したIDリストに存在しない=新着動画
if i != 0:
#Tweet処理
tweetMsg = movieTitle + " " + movieUrl tweet(tweetMsg)
#初回ループ
else:
print "already tweet!"
BODY += str(movieId)
idList.append(movieId)
lastId = movieId
#動画ページが存在しないID
else:
movieNotFound += 1
pass
movieId += 1
#サーバ攻撃とみなされないためにスリープ
time.sleep(1)
#とりあえず最後の動画IDまでこの時間帯の確認を終えたよメッセージ
print u"end of check. time is " + str(i) + ". Last Id is " + str(lastId)
#1分スリープ
time.sleep(60)
#1日分の処理を終了した時に出力
print u"Ploglam is over. Please run next time."
以上を毎日午前7時に起動して、午前0時過ぎまで稼働させていた。
読んでくださった方はお分かりかと思うが、最終的には約1分に一回更新を確認できるように調整していた。
公式の更新通知ができてからは、フォロワーを全解除し、自分用に眺めるためにアカウントは使っていたが、この度凍結したので正式にこのプロジェクトは終了である。
初期はバグや事故(1分で100ツイートとか自動化の数値を間違えてやらかした)が多く、見守ってくださった方にはハラハラさせてしまったが、最後の方には安定稼働となっていたので、自身の技術に自信を持つきっかけとなった一件だった。
当時を見守って、応援してくださった方全てに心より御礼申し上げます。
実はこのプログラムというかbotを構成したことが評価されて、転職先が決まったので、人生は偶然だし、わからないことの連続を乗り越えて連関していくと実感している。
ものづくりって楽しいんだよ、と伝える仕事をこの夏から始める。