5
1

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 1 year has passed since last update.

VolareAdvent Calendar 2021

Day 3

大学の講義資料のダウンロードをPythonで自動化してしまった話

Last updated at Posted at 2021-12-02

動機

僕の通う東京工業大学っていうFラン大学では、
講義資料や課題がOCWiっていう大学の管理してるウェブサイトに上がるんですけど
ログインするのに、毎回パスワードとマトリクスコードが必要です。
それだけでなく、クソみたいに古臭いWebサイトだし
めちゃめちゃ重いし、講義資料をダウンロードするだけでも一苦労なんですよ(汗...
ということで自動化してしまおうという発想に至りました。

まぁ、僕は設計しただけで、実装は友達がしたんですけど、同じような境遇にある大学生の役に立てればいいかなぁという事で。
ぜひ皆さんの大学でも実装してみてください。

Iris(Interval request information service)

解決すべき課題(Issue to be Solved)

現状

  • 更新された授業資料をダウンロードするのは手間
  • 講義資料をダウンロードした人がSlackの各授業チャンネルにアップロードしている

課題

  • めんどくせぇ

UserStory

image.png

  • IrisがOCWiから講義資料をとってくる
  • GoogleDriveAPIを使ってポストする
  • 講義資料がアップデートされていたらSlackに通知をとばす
  • SlackとGoogleDriveは連動しているので、Slackから資料が見れる
  • GoogleDriveから必要な資料を見れる

設計

image.png

使用するライブラリ

  • selenium(認証突破)
  • urllib(ファイルダウンロード)
  • beautifulsoup(スクレイピング)
  • google-api-python client
  • PyDrive(google-api-python clientのラッパー)

実行の自動化

一般的にはcrontabがLinuxだと使われるみたいですが、
自動化するときは、自分でデーモンを作ってあげた方が使いやすいんですよ。

通知とか分散実行とかしたいときはdigdagとかAirflowとか使いますけどね。
そういった難しい事する記事はまた書くとして、
今回はシンプルにLinuxのデーモンを新しく作ってしまいます。

重要になるファイル

  • /etc/systemd/system/[デーモン名].service
    これがユニットファイルと呼ばれているもので、ここのディレクトリ下にファイルを置くだけで、systemctlにサービスだと認識してもらえます。

以下のような感じで作りました。

/etc/systemd/system/iris.service
[Unit]
Description = This is OCWi login service daemon
After=local-fs.target
ConditionPathExists=自動起動したいプログラムへのパス(/opt/[パッケージ名]/bin)

[Service]
ExecStart=定期実行するコマンド(これがそのまま実行されます)
Type=oneshot

[Install]
WantedBy=multi-user.target

After=local-fs.targetはストレージのマウントが終わってから実行してくださいって意味です。
この辺はちょっとLinuxの(大学生にとっては)難しい話になるのですが、

/usr, /opt, /varの三つのディレクトリってLinuxにはあるじゃないですか。
あの3つは、ローカルファイルシステムのパーティションが別に区切られていることがあるんです。というか区切っていいとされているんです。

パーティションが分かれているということはすなわち、使用する際にマウントして使用するということである。
メリットは単純で、更新作業などがシステムへの影響を及ぼしにくかったり、
swap領域のパーティションを新たに設けたりできるということ。
/optはパッケージがもっさり入っていて、容量もでかいし、更新も頻繁だからパーティション分けてもいいよってされてるんですよ。

だから/opt以下を使用するときは、使っているときは気がつかないけれど、実はメモリの論理領域にアクセスしてマウントポイントを得てからマウントして使用しているってことです。
だから、今回はマウント前に実行してしまうとそんなディレクトリないよ〜ってエラーで返ってきちゃうので、念の為、マウントしてから実行してねって言ってます。

  • /opt/[パッケージ名]/bin/[デーモン名].sh

systemdのユニットファイル中のExecStartのところにPyhton3 [ファイル名]としてもいいのですが、
拡張性が担保されないことと, systemdとプログラムの切り分けができないことから
shell script側で実行してあげようと思います。

/opt/iris/bin/iris.sh
exec python3 /opt/iris/bin/iris.py

binと.shと.pyにchmod755chown root:rootしておくのは忘れないでください。
permission deniedで落ちるので。

$ sudo systemctl daemon-reload 
$ sudo systemctl enable iris.service
$ sudo systemctl start iris.service
/etc/systemd/system/iris.timer
[Service]
ExecStart=/opt/iris/bin/iris.sh
Type=oneshot

[Install]
WantedBy=multi-user.target
jrny@iris:/etc/systemd/system$ cat iris.timer
[Unit]
Description=timer of iris

[Timer]
OnCalendar=*-*-* 5:00
Persistent=true

[Install]
WantedBy=timers.target

タイマーは拡張子が .timer の systemd のユニットファイルです。

[Timer]以下のOnCalendarの部分で頻度を決めています。
OnBootSec=15minなら15分おきに実行されます。
OnCalendar=Mon,Tue *-*-01..04 12:00:00毎月の1日から4日まで、月曜日か火曜日の場合にのみ、午後0時
Sat *-*-1..7 18:00:00毎月第1土曜日
OnCalendar=*-*-* 4:00:00毎朝四時
という感じで指定できます。
基本はcrontabと同じですね。

sudo systemctl daemon-reload で反映
sudo systemctl enable iris.timerで有効化
``

よくある失敗

permisson error

ls -l filenameの一番左にシステムコールに関する権限が出るので確認してください。
知ってると思いますが、所有者、グループ、その他の順で出ます。
実行権限がなかったら、755とかにしておくと大丈夫です。

systemctl側の問題

systemctl status iris.serviceで確認できるので、確認してください。

プログラム側の問題

journalctl -u ユニットファイル名でログが見れるので確認してください。

Seleniumを使ったログイン

driver.find_element_by_name('usr_name').send_keys(secret.studentu_num)
driver.find_element_by_name('usr_password').send_keys(secret.password)
driver.find_element_by_name('OK').click()

Seleniumではelement_by_nameで要素を取得して
値を代入することができるので、上記のような処理でSessionIDを取得できます。

あとは講義資料のあるページをスクレイピングして、資料をダウンロードするだけです。
https://qiita.com/memakura/items/20a02161fa7e18d8a693
この記事が非常にわかりやすくまとまっているのでご参考ください。

GoogleDriveとIrisの接続

GCSって選択肢もあったんですけど、極力GCPに課金したくなかったので、Driveにしました。

認証はGoogleアカウントの鍵で繋げます。
ファイアーウォールとかポート開けたりしなくていいので簡単です。

    gauth = GoogleAuth()
    gauth.LocalWebserverAuth()
    drive = GoogleDrive(gauth)

ってやるときにログインしろって言われるので言われるがままにしておけば、直下にcredential.jsonできてます。

ファイルのアップロード自体はupfilesという関数があるので、それ使うとファイルがアップされます。

5
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?