- radar_fetcher.py:呼叫 Function Server 抓 twpkinfo.com 資料後寫入 Redis (TTL 300s) - pokemon_radar_api.py:FastAPI /scan,從 Redis 讀取並依 request 即時二次篩選;Redis 不可用時回 200 空結果,不再 500 - pokemon_location_fetcher.py:舊版 CLI,仍由 fetch_and_upload.sh 使用 - 文件:README (參考手冊)、QUICKSTART (操作指南)、SUMMARY (故事線)、CLAUDE.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
常用指令
套件管理使用 uv(見 pyproject.toml、uv.lock、.python-version = 3.12)。所有 Python 進入點都透過 uv run 執行。
- 啟動 API:
./run_pokemon_radar_api.sh(內含uv run uvicorn pokemon_radar_api:app --host 0.0.0.0 --port 8008 --log-config logging.ini) - 執行新版 fetcher(寫入 Redis):
uv run python radar_fetcher.py - 執行舊版 fetcher(產生本地 JSON/CSV/截圖):
uv run python pokemon_location_fetcher.py --script twpk_radar.mjs --lat 25.0478 --lng 121.5170 --zoom 16 --state state.json --ua-from-state --min-remaining 300 --min-iv 90 - 檢視 Redis 快取內容:
uv run python reader.py(rich 表格)或uv run python check_redis.py(raw JSON dump) - 生產環境排程腳本:
./fetch_and_upload.sh(使用flock鎖定/var/lock/poke_radar.lock;呼叫舊版pokemon_location_fetcher.py,然後scp到192.168.42.104:/opt/caddy/www/pokemon/spots.json)
本專案沒有測試、linter、build 流程。
架構
這是一個兩階段的 pipeline,被一個 FastAPI 即時查詢層所包裝。有兩條共存的 fetch pipeline,修改時務必了解各自的用途:
資料流
twpkinfo.com (ipoke.aspx)
▲
│ browser automation (Puppeteer)
│
Function Server (192.168.42.124:13000/function)
▲
│ POST {code: <injected twpk_radar.mjs>}, 150s timeout
│
┌─────┴─────────────────────────────┐
│ │
│ (Pipeline A:寫入 Redis) │ (Pipeline B:寫入本地檔)
│ radar_fetcher.py │ pokemon_location_fetcher.py (CLI)
│ └─→ Redis SETEX │ └─→ pokemon_data.{json,csv}
│ pokemon:radar:latest │ + screenshot.png
│ TTL 300s │
└─────┬─────────────────────────────┘
│
▼
pokemon_radar_api.py (FastAPI, :8008)
POST /scan → 即時篩選 Redis 內容回傳
關鍵設計
-
twpk_radar.mjs是 Function Server 上跑的 worker,不是本地執行的模組。Python 端透過 regex 在字串層級注入變數,這個契約不能壞:const TARGET = {...};→ 由_inject_target_and_shot覆寫const DO_SCREENSHOT = true|false;→ 同上globalThis.__POKE_STATE__→ 由_inject_state前置插入(含 cookies/localStorage/UA/langs)- 修 MJS 時,上述 3 個錨點的形狀必須維持,否則 regex 會失效
-
pokemon_radar_api.py重用舊 client 的postprocess方法,但不透過它去抓資料:_filter_helper = PokemonRadarClient(url="", token="")。Redis 存的是已篩選過一次(由 fetcher)但仍保留較寬原始集的資料,API 再依 request 參數做即時二次篩選(min_remaining/min_iv/perfect_only/species)。ScanRequest裡的lat/lng/zoom/shot/...欄位在 Redis 模式下是忽略的,純粹保留給前端/n8n 相容。 -
兩個 fetcher 的篩選邏輯重複實作了兩次(
radar_fetcher._postprocess≈PokemonRadarClient.postprocess),修改篩選規則時要同步兩邊。 -
fetch_and_upload.sh目前走的是 Pipeline B(本地檔 + scp),不是 Pipeline A(Redis)。這是生產環境仍在使用的路徑;若改 fetcher 行為要確認影響哪一邊。
設定
.env(本地)驅動radar_fetcher.py、pokemon_radar_api.py、reader.py、check_redis.py。注意radar_fetcher.py預設REDIS_HOST=localhost,但 API / reader /.env是192.168.42.211— fetcher 跑在 Redis 本機、API 跑遠端。state.json是使用者登入後的 cookies/localStorage/UA 快照;用於繞過 twpkinfo.com 的人機驗證。過期時整條 pipeline 會靜默產 0 筆。radar_fetcher._postprocess有一個診斷:當raw_items非空但篩完為 0 時會 log remaining/perfect 的分佈,優先看這個。FUNCTION_TOKEN必填(radar_fetcher 會直接 raise),舊 CLI 則有 hard-coded default6R0W53R135510。
專案慣例
- 全專案以**繁體中文(台灣用語)**溝通與註解。
- log 訊息不要使用 emoji;現存檔案中的 emoji 是歷史遺留,新寫或修改時改成純文字。
- repo 根目錄的
*_BACKUP_YYYYMMDDHHMMSS檔案是舊備份,可以清掉。