【初心者】船のスケジュールが変更されたら、LINEで通知がくるようにしてみました


自己紹介

30代サラリーマン。
パソコンはエクセル程度しか触っておりません。
長年勤めた会社を辞め、時間ができたので興味のあったプログラミングを学んでみたいと思った為、アイデミーを受講中。

なぜ今回このようなプログラムを作ったか

貿易関係の仕事をしており、毎日変更される船のスケジュールをHPで確認する必要がありました。
毎回、変更されているかされていないかも分からない貿易船のスケジュールをHPに確認しにいくのがすごく面倒。。。
変更されていたら変更されていたで、お客様と日程の調整が必要。
そこで、本船スケジュールが変更されると、自分の手元に通知が来るように
プログラムを組んでみました。

プログラムの準備


会社のパソコンなどでpython環境を都度、作るのは難しいと考え
GoogleColaboratory で 構築することにしました。

◎必要なもの
・グーグルアカウント
・Line API(https://developers.line.biz/ja/services/messaging-api/)アカウント

以下、準備とコードです。(GoogleColaboratoryで実行)
プログラムを置くフォルダと同じ場所に「before.txt」ファイル(最初はファイルだけあればよく、中身は空白でかまいません)を作っておいて下さい。「before.txt」に更新日時を記載して、HPから情報取得時に比べて、更新されたかどうか調べます。

#1 はモジュール(セレニウム)のインストール。
#2がLINE通知、HPからの情報取得コードになります。

# 1 モジュール(セレニウム)のインストール ------------------------------

%%shell

cat > /etc/apt/sources.list.d/debian.list <<'EOF'
deb [arch=amd64 signed-by=/usr/share/keyrings/debian-buster.gpg] http://deb.debian.org/debian buster main
deb [arch=amd64 signed-by=/usr/share/keyrings/debian-buster-updates.gpg] http://deb.debian.org/debian buster-updates main
deb [arch=amd64 signed-by=/usr/share/keyrings/debian-security-buster.gpg] http://deb.debian.org/debian-security buster/updates main
EOF


apt-key adv --keyserver keyserver.ubuntu.com --recv-keys DCC9EFBF77E11517
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 112695A0E562B32A

apt-key export 77E11517 | gpg --dearmour -o /usr/share/keyrings/debian-buster.gpg
apt-key export 22F3D138 | gpg --dearmour -o /usr/share/keyrings/debian-buster-updates.gpg
apt-key export E562B32A | gpg --dearmour -o /usr/share/keyrings/debian-security-buster.gpg


cat > /etc/apt/preferences.d/chromium.pref << 'EOF'
Package: *
Pin: release a=eoan
Pin-Priority: 500


Package: *
Pin: origin "deb.debian.org"
Pin-Priority: 300


Package: chromium*
Pin: origin "deb.debian.org"
Pin-Priority: 700
EOF

apt-get update
apt-get install chromium chromium-driver

pip install -q selenium


#2  LINE通知、HPからの情報取得 --------------------------------------------

Line Developers にて、Line Notify を使用する為の準備をします。

https://notify-bot.line.me/ja/

ログインできたら、右上の「マイページ」をクリック
アクセストークンの発行(開発者向け) へ進みます
「トークン名」を入力、「トークルーム」を選んで「発行する」を選択。


以下の画面になったら、赤字で表示される「トークン」を控えて下さい。
(トークンは各自の発行ごとに異なります。)

発行されたトークンをテキストメモに保存。ファイル名は「LineToken.txt」として、グーグルドライブの当プログラムと同じ場所において下さい。
プログラム中に直接トークン名を書いても動きますが、今回は別にしてあります。

# モジュールのインポート
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import time
import requests

from google.colab import drive
drive.mount('/content/drive')
 #事前準備として 、プログラムと同じフォルダに「before.txt」を用意する(中身はなんでもいい)

 #LINE  に通知を送るためのトークンをLineToken.txtから読み込み、変数「TOKEN」に格納 #プログラム内にトークンを書く必要が無くなる 
file_path = '/content/drive/MyDrive/成果物'
fname = file_path + '/LineToken.txt'   # 入力ファイル
f = open( fname, 'r' )         # ファイルを開く
TOKEN = f.read()                # 内容を読み込む
f.close()                      # ファイルを閉じる
 #LINE  に通知を送る関数
def send_message(LineText):
  headers = {
      'Authorization': 'Bearer ' + TOKEN,
  }

  files = {
      'message': (None, LineText),
  }

  requests.post('https://notify-api.line.me/api/notify', headers=headers, files=files)
#------------------------------------------------------------------------------------------------------ #船会社のスケジュールを  google chrome で開いて、内容を取得 #LastUpdate  を取得し、result に格納、before.txtを開いてsに格納 #result  と s をif分で比較して、同じであれば「更新無し」異なればLINEに通知、before.txtを上書き

def shipschedule():
    # 参考にしたサイト https://zenn.dev/robes/articles/b0542824ec61a6
    # ブラウザをheadlessモード実行
    options = webdriver.ChromeOptions()
    #ヘッドレスモード (バックグラウンドで起動)で実行。コラボの場合、必須。
    options.add_argument('--headless')
    #サンドボックスモードの解除 。これも必須。
    options.add_argument('--no-sandbox')
    #これも設定した方がよい
    options.add_argument('--disable-dev-shm-usage')

    #インスタンス化 
    driver = webdriver.Chrome('chromedriver',options=options)
    #指定したドライバーが見つかるまで待機 
    driver.implicitly_wait(10)

    #urlの指定 
    url = "https://www.toyoshingo.com/yangming/index.php?port=13&week=3"

    driver.get(url)
    time.sleep(3)

    print("サイトのタイトル:", driver.title)

    # サイトのHTMLを取得
    html = driver.page_source

    # HTMLを解析
    soup = BeautifulSoup(html, "html.parser")

    file_path = '/content/drive/MyDrive/成果物'
    fname = file_path + '/newSoup.txt'
    f = open(fname,'w')
    f.write(str(soup))
    f.close()

    # spanタグのidがupdateの要素を探す
    span = soup.find("span", id="update")

    # spanタグのテキストを取得
    text = span.get_text()
    #'更新日時を出力 参考例:Last Update:05/27 12:10

    # テキストからLast Update:を抽出する正規表現
    pattern = r"Last Update:..........."

    # 正規表現にマッチする部分文字列を探す
    match = re.search(pattern, text)

    # マッチした部分文字列を取り出す
    if match:
        result = match.group()
    #    print(result) # Last Update:

    # ブラウザを閉じる
    driver.quit()

    #print (file_path)
    with open(file_path + '/before.txt') as f:
      s = f.read()

    #before .txt に記載の更新時間と新しく取得した更新時間を比べて
    #異なるようであれば通知を送る  
    if result == s:
      print('更新されてません')
    else:
      LineText = "スケジュール更新:" + result
      send_message(LineText)
      print('HPが更新されました。' + result)
      print('--------------------------------')
      print('前回 ' + s)
      file_path = '/content/drive/MyDrive/成果物/before.txt'

      with open(file_path,'w', encoding='UTF-8') as f:
        f.write(result)
 #3 --------------------------------------------------------------- #定期実行  時間を決めて繰り返す処理
for i in range(0, 2, 1):
    shipschedule()
    time.sleep(60)

以下、関数 def shipschedule(): の説明になります

#船会社のスケジュールを google chrome で取得
#LastUpdate を取得し、result に格納、
before.txtを開いてsに格納
#result と s をif分で比較して、同じであれば「更新無し」
異なればLINEに通知、before.txtを上書き


今回は「https://www.toyoshingo.com/yangming/index.php?port=13&week=3」という所のURLから、情報を取得しています。

画面右上に「Last Update」とあったので、この部分をBeautifulSoupで取得しました
# サイトのHTMLを取得
html = driver.page_source
# HTMLを解析 soup = BeautifulSoup(html, "html.parser")
span = soup.find("span", id="update")

----------------------------------------------------------------
また以下に定期実行のことを考えて time モジュールを用いて
関数 shipschedule() を繰り返しています。
・「range(0,2,1)」の「2」の部分を「10」にすれば10回繰り返します。
・(60)のかっこ内を「1800」と書き換えれば、30分ごとに
プログラムが動きます。

#定期実行  時間を決めて繰り返す処理
for i in range(0, 2, 1):   
  shipschedule()   
  time.sleep(60)

----------------------------------------------------------------

Line に通知が来ると以下のような画面になります。
(「船スケジュール通知」の部分は設定した名前で各自異なります)

おわりに

会社で働く上で、プログラミングを活かして、業務の効率化を常に模索していきたいと思っています。
今回作ったプログラムは、HPが更新されたら通知するものですが、
本当は更新時にどういった内容が更新されたのか比べれて通知するプログラムを作ってみたいです。
是非もっと有用なものを作りたいです。

最後まで読んでくださり、ありがとうございました。


この記事が気に入ったらサポートをしてみませんか?