SeleniumとPythonでClassiに自動ログインして本日の連絡事項をスクレイピングしてみた

## はじめに（困り事）
職場では特定ドメインで閉じたネットワークが存在し、そこにポータルサイトがあります。
これを活用したいと考えているのですが、手動で更新しないといけない。
また外部サイトから更新出来ずと、使いにくく、また今はClassiで朝の情報共有をしています。

自然な移行を推進する為に学習支援サービス「Classi」の情報を自動取得してポータルに投げられたら便利だなと思い計画を開始しました。

今回は「Classi」をPythonとSeleniumを用いて自動操作し、ログイン後に表示される「本日の連絡事項」を取得するまでの手順を紹介します。

:::note alert
**注意事項:**  
- 本記事は、技術的な解説を目的としており、Classiの利用規約や学校の規則に反する行為を推奨するものではありません。  
- 内容を試される場合は、すべて自己責任で行ってください。
:::


## 前提条件

- Pythonがインストール済み（3.8以上を推奨）
- Seleniumがインストール済み (`pip install selenium`)
- Chromeブラウザと対応するChromeDriverが用意されている

ChromeDriverの入手方法: [https://chromedriver.chromium.org/](https://chromedriver.chromium.org/)  
Macの場合はHomeBrewでインストール可能。
ダウンロード後、環境に合わせてPATHを通してください。


## 使用環境
- MacBookAir M3
- Python3.13
- Google Chrome 131.0.6778.109
- venv環境で実行

## やりたいこと

1. Classiのログインページへアクセス  
2. Classi ID、パスワードを自動入力しログイン  
3. ログイン後に表示される「本日の連絡事項」を取得  
4. コンソールへ出力

定期的に実行すれば、毎朝手動でログインせずとも連絡事項を収集することが可能になります。

## コード例

以下はサンプルコードです。  
`Your_Classi_ID` や `Your_Password` は実際のID・パスワードに、`https://id.classi.jp/login/identifier` は実際にアクセス可能なClassiログインURLに置き換えてください。

```python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# ChromeDriverを利用する例（PATHが通っているか、同ディレクトリ配置を想定）
driver = webdriver.Chrome()

try:
    print("ログインページへアクセス中...")
    driver.get("https://id.classi.jp/login/identifier")

    print("Classi IDを入力します...")
    classi_id_field = WebDriverWait(driver, 20).until(
        EC.presence_of_element_located((By.NAME, "username"))
    )
    classi_id_field.send_keys("Your_Classi_ID")

    print("パスワード入力へ画面に移動します...")
    next_button = WebDriverWait(driver, 20).until(
        EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'パスワード入力へ')]"))
    )
    next_button.click()

    time.sleep(2)  # ページ描画を待機

    print("パスワードを入力します...")
    password_field = WebDriverWait(driver, 20).until(
        EC.presence_of_element_located((By.NAME, "password"))
    )
    password_field.send_keys("Your_Password")

    print("ログインします...")
    login_button = WebDriverWait(driver, 20).until(
        EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'ログイン')]"))
    )
    login_button.click()

    print("ログイン後のページを読み込み中...")
    WebDriverWait(driver, 60).until(
        lambda d: d.execute_script('return document.readyState') == 'complete'
    )

    # 非同期レンダリングが遅い場合はさらに待機
    time.sleep(10)

    print("本日の連絡事項を取得中...")
    notice_section = WebDriverWait(driver, 60).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, ".today-information p"))
    )
    notice_text = notice_section.text

    print("本日の連絡事項:")
    print(notice_text)

except Exception as e:
    print(f"エラーが発生しました: {e}")

finally:
    print("ブラウザを閉じます...")
    time.sleep(2)
    driver.quit()
```

このコードでは個人使用なのでユーザーIDやパスワードをハードコードしていますが、セキュリティ上非常に良くありません。（面倒臭いのでコード書きません）
jsonファイルで保存して読みにいったり環境変数から取得したりやり方はいろいろとあります。
自分の好きなセキュリテイ対策をしてください。

## ポイント

- 要素待機の活用: WebDriverWait と Expected Conditionsを用いることで、ページロードや要素表示を待つことができます。
- 正しいロケータの取得: ブラウザの開発者ツール(F12)でHTML構造を調べ、適切なBy.XPATHやBy.CSS_SELECTORを指定しましょう。
- 動的コンテンツ対応: time.sleep()やdocument.readyStateチェックで、ページ表示完了を待つことがポイントです。SPAの場合は要素の描画に時間がかかる場合があります。

### 応用

- 定期実行: cronやWindowsタスクスケジューラで定期的にこのスクリプトを実行すれば、自動で毎日「本日の連絡事項」を取得可能です。
- 外部通知: 取得した情報をSlackやメールに通知するスクリプトと組み合わせることで、情報共有を自動化できます。

## まとめ

SeleniumとPythonを活用することで、ClassiをはじめとしたWebベースの学習支援ツールに自動ログインし、必要な情報をスクレイピングできます。
本記事では「本日の連絡事項」取得を例に紹介しましたが、原理は他のページや機能にも応用可能です。

ここからPowerAutomate等を活用して、ポータルサイトに自動で埋め込む方法や自動同期の方法を模索したいと考えています。