開発

PADから効率化アプリをexeで共有するまで

PowerAutomateDesktopを利用したアプリは、動作が遅いことが欠点であるが、コマンドをコピーしAIでPythonに変換する方法で即座に使える。

効率化アプリを未経験でも作りたい

私が部長職についてすぐ、毎日サイトを巡回する必要が出てきた。この作業を自動化する方法について今後のためのメモ。

何を作ろうと思ったか

予約情報を毎日集める必要があった。ログインするのは良いが、最終日までのすべての日を手作業で1日ずつカレンダーからページを飛んで確認する必要があった。 構造が今ひとつつかめず、表の中に表をいくつも組み込んだサイトから予約状況を知る必要があった。 URLが日付ごとにランダムになっており、単純スクリプトでは限界があった。

生成AIは使えなかった

普段かなり生成AIのコードに頼る中、生成AIではすぐにコードを出すことができなかった。問題となった部分は以下である。

  • ログインが必要である。
  • 表が複数個に分かれており、対象の行が掴めない。
  • 予約リストの表も2つに分かれている。
  • 詳しく指定すると、フィルタに引っかかる(アルゴリズムに犯罪目的に間違われる)

このことから、私はうまく生成AIではソフトを作れなかった。 特にHTMLの表はかなりの問題となった。そもそも表が2個もある点、また詳細ページでも表にする必要があるのか謎なほど表になっている点が困った。

PADでの解決と新たなる課題

Windowsに標準で搭載されているPowerAutomateDesktopを利用することで、簡単に自動化ができることを思い出し、プログラムをノーコードで作成した。

PADでは遅すぎた

PADは起動までに時間がかかり過ぎ、また実行中にパソコンの操作ができなかった。操作時間も数分程度かかり、授業の合間に実行などができないため、目的は達成できたものの課題が残った。 また、EXCELでの処理は煩雑すぎたため、Wordでの文章としての保存となった。

Robin言語

Robin言語というものでPADの内容が書かれていることを知った。 参考 これをそのままGoogleAIStudioに貼り付けることで、Pythonコードに変更できないか考えた。

Pythonでの成功

PythonコードにGemini1.5を用いて変換することで、バックグラウンドで実行し更にCSVに保存することができた。

この記事の最後に書ける範囲でコードを書いておく。実際に使う際は、環境変数に入れパスワードの暗号化などをすべき

EXEファイル化して活用

PyInstallerを利用することで簡単に実行ファイル化できた。このため、授業の合間にダブルクリックをするだけで予約が確認できてとても助かった。

終わりに

今回、時間がない中での開発に最初PADを利用することが有効であることがわかった。無料で簡単に扱うことができ、それをPythonに変換できることがわかった。今回は成功したが、もちろん失敗する際もあるだろう。然しながら、HTMLが普段より複雑で単純にスクレイピングできない際など、GUIでの選択を簡単にできるPADの恩恵を使うのはありだと考えた。最大の問題は、GoogleAIStudioがいつまで無料なのか明確でない点である。

春休みを通して、多少複雑なスクレイピングも動かせるようになりたい。

今回のコード

今回使ったコードの一部をおいておく。今後HTMLテーブルのスクレイピング時に困ったときに確認をする。

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
from selenium.webdriver.common.keys import Keys
import time
import pandas as pd

# --- 設定 ---
USERNAME = "USER_ID"  # ユーザーID
PASSWORD = "PASSWORD"  # パスワード
BASE_URL = "対象となるサイトのURL"
LOGIN_URL = "ログインページのURL"
RESERVE_LIST_URL = "リストページのURL"

# --- WebDriverの初期化 (Chromeを使用) ---
options = webdriver.ChromeOptions()
options.add_argument("--headless")

driver = webdriver.Edge(options=options)
wait = WebDriverWait(driver, 60)  # 最大60秒待機

# --- ログイン ---
# ブログでは省略
    
# 新しいタブに切り替え
driver.switch_to.window(driver.window_handles[-1]) # 最後のタブ(新しいタブ)に切り替え

# --- 予約リストページを開く ---
driver.get(RESERVE_LIST_URL)

# --- カレンダーのリンクを取得 ---
wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".time-tble-list a")))

all_links = []
calendar_links = driver.find_elements(By.CSS_SELECTOR, ".time-tble-list a")

for link in calendar_links:
    all_links.append(link.get_attribute("href"))

# 取得したリンク一覧を出力
print("取得したリンク一覧:")
for link in all_links:
    print(link)

# --- 詳細ページを巡回し、データを抽出 ---
all_data = []

for link in all_links:
    try:
        driver.get(link)

        wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".choice-day"))) # 日付要素の読み込みを待つ

        title = driver.find_element(By.CSS_SELECTOR, ".choice-day").text.strip()

        # time-tble-detail テーブル内のすべての行を取得
        rows = driver.find_elements(By.XPATH, "//table[@class='form-tbl time-tble-detail']/tbody/tr")

        table2_data = []
        for row in rows:
             # <th> と <td> の内容を結合して1行のデータとする
            row_data = "".join([cell.text.strip() for cell in row.find_elements(By.XPATH, "./*")])
            table2_data.append(row_data)

        table2 = "\n".join(table2_data) # 複数行のデータを改行で結合
        table3 = "" # table3 はこのページには存在しないので空文字列

        all_data.append([title, table2, table3])

    except Exception as e:
        print(f"データ抽出エラー (URL: {link}): {e}")
        continue

# --- DataFrameの作成とCSV出力 ---
df = pd.DataFrame(all_data, columns=["日付", "予約状況", "表3"]) # カラム名を修正
df.to_csv("extracted_data.csv", index=False, encoding="utf-8-sig")

print("データ抽出完了! extracted_data.csv に保存しました。")

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