0
1

go-rodでmoodleの出席登録を自動化

Posted at

九大では講義時間内にmoodleの講義ページにログインすることで出席登録が行われますが、ユーザ名とパスワードを打ち込む→講義一覧から現在の講義を探す→出席登録という一連の流れが煩雑に感じたのでヘッドレスブラウザで自動化を行いました。
Goを選んだ理由はただ単に触ってみたい言語だったからです。

九大moodleでは出席していないにも関わらずコースにログインして出席とする等の行為は不正出席であり、単位を取り消される場合があります。
自動化プログラムを使用して対面講義の出席登録を行う際は必ず講義に出席し、講義室のedunet(学内LAN)へ接続するようにしてください。
本記事のプログラムを使用したことにより生じたいかなる損害にも筆者は一切責任を負いません。

実行環境

  • go version go1.22.4 darwin/arm64
  • macOS Ventura 13.4

ディレクトリ構成

auto_attend/
├── bin
│   └── auto_attend
├── go.mod
├── go.sum
└── main.go

手順

go-rodの導入

まずはモジュールの初期化

go mod init

go-rodのインストール

go get github.com/go-rod/rod

main.goの記述

ソースコード全文
package main

import (
  "fmt"
  "time"
  "github.com/go-rod/rod"
  "github.com/go-rod/rod/lib/input"
)

type Course struct{
  id string
  weekday time.Weekday
  period int
}

func main() {
  loginURL := "https://moodle.s.kyushu-u.ac.jp/login/index.php"
  username := "USERNAME"
  password := "PASSWORD"
  courses := []*Course{
    {"12345", time.Monday, 1}, //月曜1限

    {"56789", time.Wednesday, 3}, //水曜3,4限
    {"56789", time.Wednesday, 4},
  }

  periodtime := [][][]int{
    {{8,40},{10,10}}, //1限
    {{10,30},{12,0}}, //2限
    {{13,0},{14,30}}, //3限
    {{14,50},{16,20}}, //4限
    {{16,40},{18,10}}, //5限
  }
  now := time.Now()
  current := -1 //授業時間外の場合

  //現在の時限
  for id, t := range periodtime{
    start := time.Date(now.Year(), now.Month(), now.Day(), t[0][0], t[0][1], now.Second(), now.Nanosecond(), now.Location())
    end := time.Date(now.Year(), now.Month(), now.Day(), t[1][0], t[1][1], now.Second(), now.Nanosecond(), now.Location())

    if start.Unix() <= now.Unix() && end.Unix() >= now.Unix(){
      current = id + 1
    }
  }

  //fmt.Println(current)
  
  //ログイン処理
  browser := rod.New().MustConnect()
  defer browser.MustClose()
  page := browser.MustPage(loginURL).MustWaitStable()
  page.MustElement("#username").MustInput(username)
  page.MustElement("#password").MustInput(password).MustType(input.Enter)
  page.MustWaitStable()

  //出席
  for _, c := range courses{
    if c.weekday == now.Weekday() && c.period == current{
      courseURL := "https://moodle.s.kyushu-u.ac.jp/course/view.php?id=" + c.id
      page := browser.MustPage(courseURL)
      page.MustWaitStable()
      page.MustScreenshot("moodle.png")
      fmt.Println(courseURL)
    }
  }
}

ライブラリのインポート

package main

import (
  "fmt"
  "time"
  "github.com/go-rod/rod"
  "github.com/go-rod/rod/lib/input"
)

構造体Courseの定義

講義を識別するためのID、曜日、時限を記述するための構造体Courseを定義します

type Course struct{
  id string
  weekday time.Weekday
  period int
}

main関数

ログインページのURL、ユーザ名、パスワードを定義して講義の情報をCourse型スライスに記述します

func main() {
  loginURL := "https://moodle.s.kyushu-u.ac.jp/login/index.php"
  username := "USERNAME"
  password := "PASSWORD"
  courses := []*Course{
    {"12345", time.Monday, 1}, //月曜1限

    {"56789", time.Wednesday, 3}, //水曜3,4限
    {"56789", time.Wednesday, 4},
  }

実行時の時限を計算

  periodtime := [][][]int{
    {{8,40},{10,10}}, //1限
    {{10,30},{12,0}}, //2限
    {{13,0},{14,30}}, //3限
    {{14,50},{16,20}}, //4限
    {{16,40},{18,10}}, //5限
  }
  now := time.Now()
  current := -1 //授業時間外の場合

  //現在の時限
  for id, t := range periodtime{
    start := time.Date(now.Year(), now.Month(), now.Day(), t[0][0], t[0][1], now.Second(), now.Nanosecond(), now.Location())
    end := time.Date(now.Year(), now.Month(), now.Day(), t[1][0], t[1][1], now.Second(), now.Nanosecond(), now.Location())

    if start.Unix() <= now.Unix() && end.Unix() >= now.Unix(){
      current = id + 1
    }
  }

ログインページにアクセスしてフォームにユーザ名とパスワードをタイプし、Enterキーを押してログイン

  //ログイン処理
  browser := rod.New().MustConnect()
  defer browser.MustClose()
  page := browser.MustPage(loginURL).MustWaitStable()
  page.MustElement("#username").MustInput(username)
  page.MustElement("#password").MustInput(password).MustType(input.Enter)
  page.MustWaitStable()

登録した講義データに現在行われているものがあれば、講義ページにアクセスして出席登録

  //出席
  for _, c := range courses{
    if c.weekday == now.Weekday() && c.period == current{
      courseURL := "https://moodle.s.kyushu-u.ac.jp/course/view.php?id=" + c.id
      page := browser.MustPage(courseURL)
      page.MustWaitStable()
      page.MustScreenshot("moodle.png")
      fmt.Println(courseURL)
    }
  }
}

ビルド&実行

-oオプションで実行ファイルの出力先をbin/に指定しています

go build -o bin/

初回実行時にはブラウザのダウンロードとインストール処理が走るので結構時間がかかります

./bin/auto_attend

課題

アクセス時のエラー処理

ログイン、講義ページアクセス時のエラー処理を実装できていません。ステータスコード等を取得できればいけるかも?

ユーザ名、パスワード、講義情報のハードコーディング

セキュリティ上好ましくないし、あとパスワードを変えたり講義を追加・削除するたびにビルドするのが手間。別ファイル(JSON等)にまとめるのが良さそう?

まとめ

Goを実践的に学ぶ目的で自動出席ツールを作りました。

参考文献

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