どーでもいい背景
大学決まりました。
春からの新生活に思いをはせてたら
大学「コロナだから授業延期するわ。入学式もなくすわ。新入生特設サイトに情報乗っけるからマメに確認しろよ」
ということで5月くらいまで授業ないです
さて、せっかくの長期休みなので勉強でもします
けれどここで一つだけ気をつけるべきことがあります
大学「新入生特設サイトに情報乗っけるからマメに確認しろよ」
↑これです
新入生なので情報逃すのは結構きついです
なのでちゃんと更新は確認しないといけません
でも毎日毎日Website見るのはめんどくさくてやってらんね
じゃあもうお分かりですね
そうです、更新通知を作ります
というか大学側もChromeの通知機能使って更新通知くらいしてくれよ
今回は早稲田大学 新入生情報サイトで作っていきましょう
更新通知を作っていく
やりかた
まずどうやって通知の機能を作るか考えていきましょう
- スクレピングで最新のサイトの状態をとってくる
- 昨日のサイトと比較する
- 変化してたら更新されたということにする
- 更新の通知(tweetする)
こんなところです
シンプルですね
ファイル構成
.
├── info.txt
├── main.py
└── tweet.py
作る前に
スクレイプする予定なのでまずrobots.txtの存在を確認します
robots.txtがない場合でも常識を弁えた程度にしましょう
今回作るのは1日に1回程度なので負荷はそんなに大きくないですね
今回のサイトではrobots.txtはありませんでした
https://www.waseda.jp/robots.txt
↑404ですね
例としてとりあえず他の大学のrobots.txtでも置いときます
興味ある人は中身覗いてみてください
- 東大のrobots.txt
-
慶應大学のropbots,txt
東大は設定されてますね
慶應は空だけどファイルはありますね
早稲田もrobots.txtくらい設定しとけよ
次にサイトの中でアクセスポリシーなどをみていきます
accesibility-and-copyright
一応プライバシーポリシーなどもみていきます
privacy-policy
ここでサイトのクロールなどに関して書いてある場合はちゃんと読みましょう
ダメだと書いてあったらスクレイプしないでください
スクレピングの裁判事例などもあるのでそこらへんはしっかりしましょう
Librahack事件
更新確認のプログラム作っていく
今回は簡単にPythonでチャチャっとやっていきます
スクレイプにはChromedriver使います
入ってなければhomebrewとかで入れてください
1回目(失敗)
まずWebsiteの情報を取ってきます
bs4で取ってこようとしたら動的に生成されるタイプだったのか失敗しました
特に悩む気もないのでseleniumで対応しました
2回目(成功)
わざわざサイト全部の情報抜いてくる必要もないので更新についてのところだけCSSselectorで抜いていきます
サンプルコード
import os
import datetime
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
f_path = 'info.txt'
tweet_text = '【早稲田大学 新入生特設サイト】\n'
options = Options()
options.set_headless(True)
driver = webdriver.Chrome(chrome_options=options)
url = 'https://www.waseda.jp/fsci/news/2020/03/04/13353/'
# read saved info
if os.path.exists(f_path):
with open(f_path) as f:
old_info = f.read()
else:
old_info = ''
# get latest info
driver.get(url)
html = driver.page_source.encode('utf-8')
soup = BeautifulSoup(html, "html.parser")
latest_info = driver.find_element_by_css_selector(
'#anc_pagetop > div.wrap-outer > div > div.post.soft-double-bottom.global-bg.container-outer > div > div > div.col-sm-9.eq.bg-white > div.bg-white.soft-double.post-body.wp-text > p:nth-child(1) > span').text
# comparison info
if latest_info == old_info:
print('keep info')
tweet_text += f'''{datetime.datetime.now()}現在において更新はありません
{url}
'''
else:
print('change info')
tweet_text += f'''{datetime.datetime.now()}現在、更新を確認しました
WebSiteを確認してください
{url}
'''
with open(f_path, mode='w') as f:
f.write(latest_info)
取ってきた情報はこんな感じでinfo.txtに保存されます
info.txt
[最終更新日]
2020/3/25 2020年度授業開始日程について追加しました。
2020/3/24 学科専攻Majorガイダンス一覧を公開しました。
2020/3/19 学生証配付日程および奨学金関連手続きについて追加しました。
2020/3/17 [学部/日本語学位/正規生の皆さんへ]
WEB出願システム登録メールアドレスにお知らせを送信しました。
2020/3/16 英語プレイスメント試験(WeTEC)受験ページおよび受験ガイドを公開しました。
2020/3/13 英語プレイスメント試験(WeTEC)受験期間および学生定期健康診断について追加しました。
2020/3/12 科目登録日程について更新しました。
2020/3/5 WasedaIDについて追加しました。
2020/3/4 ページを公開しました。
通知機能のプログラムを作っていく
通知機能はいろいろありますね
GmailのAPIあたりたたいてもいいんですけど今回はTwitterAPIででもやっていきましょう
APIの取り方は過去記事でも補助にしてさくっと取ってみてください
けっこう遊べて楽しいですよ
まずKeyとかの設定とかするファイルだけ作っちゃいます
tweetの関数とかも入れときましょう
tweet.py
import tweepy
CONSUMER_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CONSUMER_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxJ"
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
ACCESS_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ACCESS_TOKEN_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)
def tweet(string):
api.update_status(status=string)
更新確認と通知機能をまとめましょう
最終的にこんな感じですね
main.py
import os
import datetime
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import tweet as tw
f_path = 'info.txt'
tweet_text = '【早稲田大学 新入生特設サイト】\n'
options = Options()
options.set_headless(True)
driver = webdriver.Chrome(chrome_options=options)
url = 'https://www.waseda.jp/fsci/news/2020/03/04/13353/'
# read saved html
if os.path.exists(f_path):
with open(f_path) as f:
old_info = f.read()
else:
old_info = ''
# get latest info
driver.get(url)
html = driver.page_source.encode('utf-8')
soup = BeautifulSoup(html, "html.parser")
latest_info = driver.find_element_by_css_selector(
'#anc_pagetop > div.wrap-outer > div > div.post.soft-double-bottom.global-bg.container-outer > div > div > div.col-sm-9.eq.bg-white > div.bg-white.soft-double.post-body.wp-text > p:nth-child(1) > span').text
# comparison html
if latest_info == old_info:
print('keep info')
tweet_text += f'''{datetime.datetime.now()}現在において更新はありません
{url}
'''
else:
print('change info')
tweet_text += f'''{datetime.datetime.now()}現在、更新を確認しました
WebSiteを確認してください
{url}
'''
with open(f_path, mode='w') as f:
f.write(latest_info)
print(tweet_text)
tw.tweet(tweet_text)
tweet.py
import tweepy
CONSUMER_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CONSUMER_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxJ"
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
ACCESS_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ACCESS_TOKEN_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)
def tweet(string):
api.update_status(status=string)
実験
実際にやるとこんな感じ
【早稲田大学 新入生特設サイト】
— 電電⚡️猫猫 (@nya3_neko2) March 26, 2020
2020-03-26 23:44:13.217527現在において更新はありませんhttps://t.co/nm9QSo8ZC2
おわりー
このコードをcronで定期的に実行するとか、AWSとかにのっけて自動化することもできますね
AWSの1年無料期間終わっちゃったから僕はしないとおもうので誰かやってくれないかな
じゃあ新入生の皆さん、新しい情報を見逃さず良いキャンパスライフを!
最後に
スクレピングは常識的にやりましょう
このコードを試すのは自己責任です