An event-driven, asynchronous background daemon built in Python 3.12+ to monitor Japanese PC hardware retailers (Tsukumo, Dospara, and PC One's) for real-time inventory availability and price changes, dispatching rich embed notifications to Discord.
flowchart LR
subgraph Ingestion [" 1. Headless Ingestion "]
URL[Target URLs] --> Extractor[Strategy Extractors<br/>Tsukumo / Dospara / Ones]
Extractor --> Playwright[Playwright Async Engine<br/>DOM & Microdata Extraction]
end
subgraph Boundary [" 2. Validation Boundary "]
Playwright --> Scraped[Pydantic Validation<br/>ScrapedProduct]
end
subgraph Engine [" 3. Delta Engine & Alerts "]
Scraped --> Delta[Pure Delta Engine<br/>evaluate_delta]
Delta -->|State Changed| Discord[Discord Webhook<br/>Rich Embed + Thumbnail]
end
subgraph Storage [" 4. Asynchronous Storage "]
Scraped --> Queue[Single-Writer Queue<br/>asyncio.Queue]
Queue --> Worker[Writer Worker Task]
Worker --> DB[(SQLite WAL Database<br/>products & price_history)]
end
- Strategy Pattern Scraper Architecture: Decoupled retailer parsers (
TsukumoExtractor,DosparaExtractor,OnesExtractor) implementing a unifiedBaseExtractorinterface. Adding new stores requires zero changes to the daemon loop. - Defensive DOM Extraction: Scoped purchase-box targeting, multi-attribute button inspection (
disabled,aria-disabled, CSS classes, inner text), and OpenGraph image extraction (meta[property='og:image']). Usesdomcontentloadedto bypass third-party tracking script hangs. - Tokenized Price Sanitization: Targeted regex currency extraction isolating primary numeric tokens, preventing false digit concatenation with tax breakdowns (
10%税込) or point rewards (ポイント10倍). - Single-Writer SQLite Actor Pattern: Enforces serial database writes through an internal
asyncio.Queueconsumer, completely eliminating SQLitedatabase is lockederrors under concurrent coroutine load. - Pure Functional Delta Engine: Side-effect-free state transition classifier tracking compound events (e.g. simultaneous
BACK_IN_STOCKandPRICE_DROP) with configurable percentage threshold gating. - Fault-Tolerant Webhooks: Dynamic color-coded Discord Rich Embeds with thumbnail previews, rate-limit backoff handling (
429 Retry-After), and defensive error containment. - Cooperative Daemon Lifecycle: Non-blocking interruptible sleep (
asyncio.Event) with unified POSIX signal trapping (SIGINT,SIGTERM) for sub-second graceful shutdowns. - 100% Hermetic Test Suite: 160 unit and integration tests executing in under 0.6 seconds via
httpx.MockTransportand async DOM mocking fixtures—zero external network dependencies.
Clone the repository and synchronize dependencies using uv:
git clone https://github.com/your-username/price-watcher.git
cd price-watcher
# Install Python dependencies & Playwright Chromium
uv sync
uv run playwright install chromiumRun a single live extraction pass across curated Japanese hardware targets without needing a database or Discord webhook:
uv run python -m src.main --demoCopy the environment template and configure your tracking preferences:
cp .env.example .envEdit .env:
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN"
SQLITE_DB_PATH="price_watcher.db"
CHECK_INTERVAL_SECONDS=300
PRICE_DROP_THRESHOLD_PCT=0.0
LOG_LEVEL="INFO"
TARGET_URLS="https://shop.tsukumo.co.jp/goods/0409175060015/,https://www.dospara.co.jp/SBR1882/IC516296.html,https://www.1-s.jp/products/detail/308973"Start the background daemon:
uv run python -m src.mainRun the full hermetic test suite (160 tests):
uv run pytest -vRun code formatting and linting:
uv run ruff check .
uv run ruff format --check .price-watcher/
├── docs/ # Visual demo GIFs and documentation assets
├── src/
│ ├── config/ # Pydantic Settings & environment variable parsing
│ ├── db/ # aiosqlite setup, migrations & single-writer repository
│ ├── engine/ # Pure delta state transition evaluation
│ ├── extractors/ # Strategy DOM parsers (Tsukumo, Dospara, PC One's)
│ ├── models/ # Pydantic domain models (ScrapedProduct, ProductRecord, etc.)
│ ├── notifiers/ # Discord webhook notifier via httpx
│ └── main.py # Daemon lifecycle orchestrator & CLI runner
├── tests/ # Hermetic test suite with mock transports & DOM adapters
├── pyproject.toml # Project metadata and dependencies
├── README.md # English documentation
└── README.ja.md # Japanese documentation
This project is open-source and available under the MIT License.

