7
10

More than 3 years have passed since last update.

時間割をLINEで自動通知する。(selenium+LINE Notify)

Posted at

はじめに

今回の目標は最新の時間割を大学のポータルサイトからスクレイピングしてLINEnotifyで通知を受け取れるようにすることです。
動機は先日、大学の授業変更に気付けず1コマ分の出席を無駄にしてしまった(せっかく早起きしたのに...)からです。

準備

準備として、大学のポータルサイトへの自動ログインを以下のコードで書きました。

from selenium import webdriver 
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless')
webdriver = webdriver.Chrome(options=options)

webdriver.get("<ポータルサイトのURL>")
#Xpathで指定
webdriver.find_element_by_xpath('//*[@id="userId"]').send_keys("USERID")
webdriver.find_element_by_xpath('//*[@id="password"]').send_keys("PASSWORD")
#クリックするボタン
webdriver.find_element_by_css_selector("#loginButton").click()

optionでheadlessを付けることでブラウザが立ち上がらなくなるので便利です。
他のサイトの場合はwebdriver.getwebdriver.find_element_by_〇〇の中身をサイトの形式に合わせて変えると動くと思います。

スクレイピング

週末は時間割がなく、空欄が返ってくるのでif文で簡単な関数を作っておきました。

#週末は空欄になってしまうので...
def check (subjects):
    x=[]
    for subject in subjects:
       x.append(subject.text)

    if x == ['']:
        return '''""""""""""""
授業はありません♪
"""""""""""" '''
    else:
        for subject in subjects:
            x=subject.text
        return '''""""""""""""
%s
"""""""""""" ''' % x


try:

    today_list = webdriver.find_elements_by_xpath('//*[@id="weekly"]/tbody/tr[3]/td[2]')
    tomorrow_list = webdriver.find_elements_by_xpath('//*[@id="weekly"]/tbody/tr[3]/td[3]')

    msg='''
今日の時間割
%s

明日の時間割
%s'''%(check(today_list),check(tomorrow_list))
    print(msg)


finally:
    webdriver.quit()

ここでmsgの中身を確認しておくと、


print(msg)
>>今日の時間割
""""""""""""
時限
基幹物理学ⅠB
時限
中国語Ⅱ
時限
課題協学科目
時限
課題協学科目
"""""""""""" 

明日の時間割
""""""""""""
時限
情報科学
"""""""""""" 

いい感じにスクレイピング出来ました。

LINE Notifyで通知

(https://notify-bot.line.me/ja/ )にアクセスしログイン後、マイページにてトークンを発行します。この際、モバイルからだとトークン発行画面が表示されなかったのでpcからアクセスすると表示されるはずです。以下のコードは「Pythonでスクレイピングした情報をLINE Notifyを使って通知する」を参考にさせて頂きました。

import urllib.request
import sys
LINE_TOKEN =  "<取得したTOKEN>"
LINE_NOTIFY_URL = "https://notify-api.line.me/api/notify"

def class_info(msg):
    method = "POST"
    headers = {"Authorization": "Bearer %s" % LINE_TOKEN}
    payload = {"message": msg}
    try:
        payload = urllib.parse.urlencode(payload).encode("utf-8")
        req = urllib.request.Request(
            url=LINE_NOTIFY_URL, data=payload, method=method, headers=headers)
        urllib.request.urlopen(req)
    except Exception as e:
        print ("Exception Error: ", e)
        sys.exit(1)

def main():
    class_info(msg)

最終的なコード

class_notify.py
from selenium import webdriver 
from selenium.webdriver.chrome.options import Options
import urllib.request
import sys

options = Options()
options.add_argument('--headless')
webdriver = webdriver.Chrome(options=options)

webdriver.get("<URL>")
#Xpathで指定
webdriver.find_element_by_xpath('//*[@id="userId"]').send_keys("USERID")
webdriver.find_element_by_xpath('//*[@id="password"]').send_keys("PASSWORD")
#クリックするボタン
webdriver.find_element_by_css_selector("#loginButton").click() 

#週末は空欄になってしまうので...
def check (subjects):
    x=[]
    for subject in subjects:
       x.append(subject.text)

    if x == ['']:
        return '''""""""""""""
授業はありません♪
"""""""""""" '''
    else:
        for subject in subjects:
            x=subject.text
        return '''""""""""""""
%s
"""""""""""" ''' % x


try:

    today_list = webdriver.find_elements_by_xpath('//*[@id="weekly"]/tbody/tr[3]/td[2]')
    tomorrow_list = webdriver.find_elements_by_xpath('//*[@id="weekly"]/tbody/tr[3]/td[3]')

    msg='''
今日の時間割
%s

明日の時間割
%s'''%(check(today_list),check(tomorrow_list))
    print(msg)


finally:
    webdriver.quit()

LINE_TOKEN =  "<TOKEN>"
LINE_NOTIFY_URL = "https://notify-api.line.me/api/notify"

def class_info(msg):
    method = "POST"
    headers = {"Authorization": "Bearer %s" % LINE_TOKEN}
    payload = {"message": msg}
    try:
        payload = urllib.parse.urlencode(payload).encode("utf-8")
        req = urllib.request.Request(
            url=LINE_NOTIFY_URL, data=payload, method=method, headers=headers)
        urllib.request.urlopen(req)
    except Exception as e:
        print ("Exception Error: ", e)
        sys.exit(1)

def main():
    class_info(msg)


if __name__ == '__main__':
    main()

そして以下のように問題なく通知がきました。
1572336804873.jpg

おまけ

pythonファイルを手動で実行するのはめんどくさいので、今回は簡単なバッチファイルを作り、windowsのタスクスケジューラで自動実行させようと思います。

バッチファイル作成

hoge.bat
cd \
cd C:\Users\ユーザー名\〇〇〇 (←実行するpythonファイルの階層まで移動)
call C:\\Users\\ユーザー名\\Anaconda3\\Scripts\\activate.bat
python class_notify.py

cd \をせずに階層まで移動しようとするとエラーが出たため、いったんcd \を付けています。)
anacondaの環境で実行したいので(anaconda promptで実行!的なことが出来ます。)callactivate.batの場所を書いています。activate.batの場所が違う場合があるので確認して記述します。

タスクスケジューラ

windowsのスタートメニューの検索欄からタスクスケジューラを検索し、起動します。
タスクの作成を選択し、操作のタブから新しい操作を選択し、参照から、作成したバッチファイルを選択します。後は名前とトリガーを記述するだけで完了です。
自分はpcをスリープからログインした際に実行されるように、トリガーのタスクの開始を「ワークステーションアンロック時」に設定しました。
詳しくはこちらを参考にしてください。

おわりに

pythonのコードを書くところまでは順調だったのですが、意外にも、タスクスケジューラの使い方で結構詰まりました。
スクレイピングしたり何かしらのAPI使うことは楽しいので、これからも気が向けばやってみようと思いました。

参考にした記事

Pythonでスクレイピングした情報をLINE Notifyを使って通知する
Python3 文字列中に変数展開したい
XPathのまとめ、要素の参照方法いろいろ
初心者でもわかるWindowsタスクスケジューラの使い方
タスクスケジューラ:トリガー

7
10
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
7
10