5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PSO2の緊急クエストをSlackで通知

Posted at

きっかけ

研究室の先輩がPHANTASY STAR ONLINE2(以下PSO2)ジャンキーなので、先輩のために緊急クエストをLINEとかで通知してくれるようなbotを作ろうと始まったこの緩い開発業務。研究室の連絡手段がSlackであり、Python用のライブラリもあるようなので「とりあえずこれでいいか笑」という感じで作り始めた。

というのは口実で、実際は「院試のストレス解消のために、とにかくなんか作りたかった」という感じ笑。

開発環境

OS:Ubuntu 16.04.5
使用言語:Python 3.6.4
Webスクレイピング:BeautifulSoup4 4.6.0
Slack通知:slackweb 1.0.5

前準備

色々調べてるとどうやらSlack通知を受け取るために、incoming-webhookを有効にしないといけないと分かった。基本的にはこの記事のように設定すれば簡単に有効化できる。

とりあえずコード全部晒す

pso2_via_slack.py
from bs4 import BeautifulSoup
import requests
import datetime
import re
import sys
import slackweb
import time

if sys.version_info[0] == 2:
    from urlparse import urljoin
elif sys.version_info[0] == 3:
    from urllib.parse import urljoin

def scrape_status(reqs, verbose=True):
    if verbose:
        if reqs.status_code < 200:
            sys.stdout.write('\nNow accsessing...\n')
        elif reqs.status_code < 300:
            sys.stdout.write('\nSuccsessed\n')
        elif reqs.status_code < 400:
            sys.stdout.write('\nNow Redirecting...\n')
        elif reqs.status_code < 500:
            raise Exception('Client error, Not scraped...')
        elif reqs.status_code < 600:
            raise Exception('Server error, Not scraped...')
        else:
            raise Exception('Unknown error...')

def maintenance_flag(property_list):
    if len(property_list) == 0:
        raise Exception('Server maintenance')

# ---------- init parameters ----------
WEEKDAYS = {
        0:'monday',
        1:'tuesday',
        2:'wednesday',
        3:'thursday',
        4:'friday',
        5:'saturday',
        6:'sunday'
        }
BASEURL = 'http://pso2.jp/players/'
ENCODE = 'utf-8'
YOUR_SLACK = 'incoming-webhookで取得した自身のSlack URL'
SLACK = slackweb.Slack(url=YOUR_SLACK)
SLACK_INFO = ''

while True:
    today = datetime.datetime.today()
    weekday = WEEKDAYS[today.weekday()+1]

    if '17:06' in str(today).split()[1]:
# ---------- scrape base URL site ----------
        htmldata = requests.get(BASEURL)
        scrape_status(reqs=htmldata)
        htmldata.encoding = ENCODE
        soup = BeautifulSoup(htmldata.content, 'lxml')
        href_list = list(set(soup.find_all('a', href='boost/')))
        maintenance_flag(href_list)

# ---------- get boost quest URL ----------
        boost_url = urljoin(BASEURL, href_list[0].get('href'))

# ---------- scrape boost quest timetable ----------
        boostdata = requests.get(boost_url)
        scrape_status(reqs=boostdata)
        boostdata.encoding = ENCODE
        boostsoup = BeautifulSoup(boostdata.content, 'lxml')
        today_quests = list(set(boostsoup.find_all('td', class_='day-{0}'.format(weekday))))
        maintenance_flag(today_quests)

# --------- informed via slack ----------
        quest_info = [str(content.div) for content in today_quests]
        for quest in quest_info:
            if quest != 'None':
                info = re.split('[<,>]', quest)
                SLACK_INFO += '{0}{1} {2} {3}\n'.format(info[18].replace('', '-'),info[22],info[10],info[4])
        SLACK.notify(text=SLACK_INFO)

    time.sleep(60)

ほとんど殴り書きに近いスクリプト笑。他にも簡略化できる部分はかなりあるため、とりあえずのα版。流れとしては、翌日の曜日を取得後、requestsとBeautifulSoupでPSO2の公式サイトの緊急クエストテーブルまでのパスを取得、これをもう一度パースして、クエストの時間・名称を文字列に変換してSlackにぶん投げる、というもの。またスクリプトはサーバー内で永久稼働していないと使えないので、無限ループで何もせず待機、クエストが更新される午後5時になったらスクレイピングを開始して、クエストをSlackから通知する(本当は水曜日の午後5時に1週間分のクエストが更新される、今後直します)。基本的にバックエンドジョブで流す。

関数の説明

scrape_status

requestsライブラリで取得したステータスコードの値に応じて、メッセージを表示したり、例外を返したりする部分。正直あってもなくてもどっちでもいい。単純に自分の勉強のために作ってみた。本当はtry-exceptでスマートに決めたかった。

maintenance_flag

緊急クエストテーブルがメンテナンス中のときにスクレイピングすると、スクリプトのtoday_questが空のリストととなる。これを判断して例外を返すために作成。そのエラーメッセージもSlackで通知できればなおよし。

結果

20190307_172020.jpg

20190307_172053.jpg

公式のタイムテーブルとスマホのSlack画面。時間を時系列順にソートしていないけど通知はできている。α版としてはいい出来かも笑。

注意点として

スリープ時間に関して

ループ時にsleepを60秒にしているが、これを1桁にした暁には、Slack画面が通知で荒れることになる。LINEのスタンプ爆撃並みにイライラする。あとSlackの無料版はメッセージの一括削除ができないのでいちいち消していかないといけない。これが恐ろしくめんどくさい。今年一番の鬼畜プレイだった。

datetimeの時間に関して

このスクリプトでは、datetimeの時間が午後5時6分にスクレピングするよう設定しているが、使用するLinuxサーバーによって通知が来る時間が異なる。実際の時間とUnix時間のギャップは予め確認しておき、環境に応じて適宜変える必要がある。本当はUnix時間と実時間を一致させたいが、方法を現在模索中。

最後に

スクレイピングは楽しかった。そして無料版のSlackはクソ。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?