試してみたブログ

AI関連・iPhone/Pixelなどのガジェット・音声入力・サーマルプリンタなど興味をある事をどんどん試してみた際の記録

Coopの定期宅配の使い勝手が悪いので注文メールを任意の曜日に自動的に送信させる物を作った

背景

  • コープの定期宅配を頼んでいるが、結局忘れてしまう事が多い
  • コープの使い勝手が悪く、通知なども無い
  • せめて注文〆切の前日に現在頼んでいる注文の一覧を送付するようにしたい
  • アプローチとしては、playwrightを使ってログインし現在注文している物をメール送信させる

試してみた

  • リポジトリを作成(管理用)
  • uv venvで仮想環境の作成
  • uv install playwright python-dotenv
  • playwright install
  • あとはChatGPTと一緒にログインフォームのDOM、送信ボタンの部分を一緒に解析
  • developer toolで該当場所をChatGPTに渡していく

- 10分ぐらいでサクッと完了

# run_coop.py
import os
import sys
import time
from dotenv import load_dotenv
from playwright.sync_api import sync_playwright, TimeoutError as PWTimeoutError

load_dotenv()

LOGIN_URL  = os.getenv("LOGIN_URL")
USER = os.getenv("GC_USERNAME")
PW   = os.getenv("GC_PASSWORD")

def main(headless: bool = True):
    ts = int(time.time())
    try:
        with sync_playwright() as p:
            browser = p.chromium.launch(headless=headless)
            context = browser.new_context()  # 必要なら storage_state=... でクッキー再利用
            page = context.new_page()

            page.goto(LOGIN_URL, wait_until="domcontentloaded", timeout=30000)

            page.locator('#txID').fill(USER)
            page.locator('#txPswd').fill(PW)     # 例: ラベルが「パスワード」
            # 送信
            page.locator('input#sbLogin[alt="ログイン"]').click()

            # 3) ログイン後の遷移待ち
            page.wait_for_load_state("networkidle", timeout=30000)

            # 5) メール通知リンク押下(<a onclick="sendOrderMail()">)
            page.locator('a[onclick="sendOrderMail()"]:has(img[alt="注文内容をメールで送る"])').click()

            context.storage_state(path=f".state_{ts}.json")  # 任意:クッキー保存

    except PWTimeoutError as e:
        print("TimeoutError:", e)
        _dump(page, ts)
        sys.exit(1)
    except Exception as e:
        print("Error:", e)
        _dump(page, ts)
        sys.exit(1)

def _dump(page, ts):
    try:
        page.screenshot(path=f"error_{ts}.png", full_page=True)
        with open(f"error_{ts}.html", "w", encoding="utf-8") as f:
            f.write(page.content())
    except:
        pass

if __name__ == "__main__":
    # 初回は headless=False にして目視確認が便利
    main(headless=False)

感想と今後

  • AWS LambdaかMacのCronで毎週木曜日・金曜日あたりに自動実行させたい
  • そもそもスクレイピングなどを明示的に禁止されてたり、過度なアクセスは不可が掛かるので最小限に抑える