401 lines
12 KiB
Plaintext
401 lines
12 KiB
Plaintext
Metadata-Version: 2.4
|
|
Name: pricewatch
|
|
Version: 0.1.0
|
|
Summary: Application Python de suivi de prix e-commerce (Amazon, Cdiscount, extensible)
|
|
Author: PriceWatch Team
|
|
Keywords: scraping,e-commerce,price-tracking,amazon,cdiscount
|
|
Classifier: Development Status :: 3 - Alpha
|
|
Classifier: Intended Audience :: Developers
|
|
Classifier: Programming Language :: Python :: 3.12
|
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
Requires-Python: >=3.12
|
|
Description-Content-Type: text/markdown
|
|
Requires-Dist: typer[all]>=0.12.0
|
|
Requires-Dist: pydantic>=2.5.0
|
|
Requires-Dist: pydantic-settings>=2.1.0
|
|
Requires-Dist: requests>=2.31.0
|
|
Requires-Dist: httpx>=0.26.0
|
|
Requires-Dist: playwright>=1.41.0
|
|
Requires-Dist: beautifulsoup4>=4.12.0
|
|
Requires-Dist: lxml>=5.1.0
|
|
Requires-Dist: cssselect>=1.2.0
|
|
Requires-Dist: pyyaml>=6.0.1
|
|
Requires-Dist: python-dateutil>=2.8.2
|
|
Requires-Dist: sqlalchemy>=2.0.0
|
|
Requires-Dist: psycopg2-binary>=2.9.0
|
|
Requires-Dist: alembic>=1.13.0
|
|
Requires-Dist: python-dotenv>=1.0.0
|
|
Requires-Dist: redis>=5.0.0
|
|
Requires-Dist: rq>=1.15.0
|
|
Requires-Dist: rq-scheduler>=0.13.0
|
|
Requires-Dist: fastapi>=0.110.0
|
|
Requires-Dist: uvicorn>=0.27.0
|
|
Provides-Extra: dev
|
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
Requires-Dist: pytest-mock>=3.12.0; extra == "dev"
|
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
Requires-Dist: black>=24.0.0; extra == "dev"
|
|
Requires-Dist: mypy>=1.8.0; extra == "dev"
|
|
Requires-Dist: types-requests>=2.31.0; extra == "dev"
|
|
Requires-Dist: types-pyyaml>=6.0.0; extra == "dev"
|
|
Requires-Dist: types-beautifulsoup4>=4.12.0; extra == "dev"
|
|
|
|
# PriceWatch 🛒
|
|
|
|
Application Python de suivi de prix e-commerce (Amazon, Cdiscount, extensible).
|
|
|
|
## Description
|
|
|
|
PriceWatch est une application CLI permettant de scraper et suivre les prix de produits sur différents sites e-commerce. L'application gère automatiquement la détection du site, la récupération des données (HTTP + fallback Playwright), et produit un historique exploitable.
|
|
|
|
## Fonctionnalités
|
|
|
|
- ✅ Scraping automatique avec détection du site marchand
|
|
- ✅ Récupération multi-méthode (HTTP prioritaire, Playwright en fallback)
|
|
- ✅ Support Amazon et Cdiscount (architecture extensible)
|
|
- ✅ Extraction complète des données produit (prix, titre, images, specs, stock)
|
|
- ✅ Pipeline YAML → JSON reproductible
|
|
- ✅ Logging détaillé et mode debug
|
|
- ✅ Tests pytest avec fixtures HTML
|
|
|
|
## Prérequis
|
|
|
|
- Python 3.12+
|
|
- pip
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
# Cloner le dépôt
|
|
git clone <repository-url>
|
|
cd scrap
|
|
|
|
# Installer les dépendances
|
|
pip install -e .
|
|
|
|
# Installer les navigateurs Playwright
|
|
playwright install
|
|
```
|
|
|
|
## Structure du projet
|
|
|
|
```
|
|
pricewatch/
|
|
├── app/
|
|
│ ├── core/ # Modèles et utilitaires centraux
|
|
│ │ ├── schema.py # ProductSnapshot (modèle Pydantic)
|
|
│ │ ├── registry.py # Détection automatique des stores
|
|
│ │ ├── io.py # Lecture YAML / Écriture JSON
|
|
│ │ └── logging.py # Configuration logging
|
|
│ ├── scraping/ # Méthodes de récupération
|
|
│ │ ├── http_fetch.py # Récupération HTTP
|
|
│ │ └── pw_fetch.py # Récupération Playwright
|
|
│ ├── stores/ # Parsers par site marchand
|
|
│ │ ├── base.py # Classe abstraite BaseStore
|
|
│ │ ├── amazon/
|
|
│ │ │ ├── store.py
|
|
│ │ │ ├── selectors.yml
|
|
│ │ │ └── fixtures/
|
|
│ │ └── cdiscount/
|
|
│ │ ├── store.py
|
|
│ │ ├── selectors.yml
|
|
│ │ └── fixtures/
|
|
│ ├── db/ # Persistence SQLAlchemy (Phase 2)
|
|
│ │ ├── models.py
|
|
│ │ ├── connection.py
|
|
│ │ └── migrations/
|
|
│ ├── tasks/ # Jobs RQ (Phase 3)
|
|
│ │ ├── scrape.py
|
|
│ │ └── scheduler.py
|
|
│ └── cli/
|
|
│ └── main.py # CLI Typer
|
|
├── tests/ # Tests pytest
|
|
├── scraped/ # Fichiers de debug (HTML, screenshots)
|
|
├── scrap_url.yaml # Configuration des URLs à scraper
|
|
└── scraped_store.json # Résultat du scraping
|
|
```
|
|
|
|
## Usage CLI
|
|
|
|
### Pipeline complet
|
|
|
|
```bash
|
|
# Scraper toutes les URLs définies dans scrap_url.yaml
|
|
pricewatch run --yaml scrap_url.yaml --out scraped_store.json
|
|
|
|
# Avec debug
|
|
pricewatch run --yaml scrap_url.yaml --out scraped_store.json --debug
|
|
|
|
# Avec persistence DB
|
|
pricewatch run --yaml scrap_url.yaml --out scraped_store.json --save-db
|
|
```
|
|
|
|
### Commandes utilitaires
|
|
|
|
```bash
|
|
# Détecter le store depuis une URL
|
|
pricewatch detect https://www.amazon.fr/dp/B08N5WRWNW
|
|
|
|
# Récupérer une page (HTTP)
|
|
pricewatch fetch https://www.amazon.fr/dp/B08N5WRWNW --http
|
|
|
|
# Récupérer une page (Playwright)
|
|
pricewatch fetch https://www.amazon.fr/dp/B08N5WRWNW --playwright
|
|
|
|
# Parser un fichier HTML avec un store spécifique
|
|
pricewatch parse amazon --in scraped/page.html
|
|
|
|
# Vérifier l'installation
|
|
pricewatch doctor
|
|
```
|
|
|
|
### Commandes base de donnees
|
|
|
|
```bash
|
|
# Initialiser les tables
|
|
pricewatch init-db
|
|
|
|
# Generer une migration
|
|
pricewatch migrate "Initial schema"
|
|
|
|
# Appliquer les migrations
|
|
pricewatch upgrade
|
|
|
|
# Revenir en arriere
|
|
pricewatch downgrade -1
|
|
```
|
|
|
|
### Commandes worker
|
|
|
|
```bash
|
|
# Lancer un worker RQ
|
|
pricewatch worker
|
|
|
|
# Enqueue un job immediat
|
|
pricewatch enqueue "https://example.com/product"
|
|
|
|
# Planifier un job recurrent
|
|
pricewatch schedule "https://example.com/product" --interval 24
|
|
```
|
|
|
|
## Base de donnees (Phase 2)
|
|
|
|
```bash
|
|
# Lancer PostgreSQL + Redis en local
|
|
docker-compose up -d
|
|
|
|
# Exemple de configuration
|
|
cp .env.example .env
|
|
```
|
|
|
|
Guide de migration JSON -> DB: `MIGRATION_GUIDE.md`
|
|
|
|
## API REST (Phase 3)
|
|
|
|
L'API est protegee par un token simple.
|
|
|
|
Note: l endpoint `/products` expose des champs Amazon explicites (asin, note, badge Choix d Amazon, stock_text/in_stock, model_number/model_name, main_image/gallery_images). Les reductions ne sont plus calculees cote API.
|
|
|
|
```bash
|
|
export PW_API_TOKEN=change_me
|
|
docker compose up -d api
|
|
```
|
|
|
|
Exemples:
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" http://localhost:8001/products
|
|
curl http://localhost:8001/health
|
|
```
|
|
|
|
Filtres (exemples rapides):
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" \\
|
|
"http://localhost:8001/products?price_min=100&stock_status=in_stock"
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" \\
|
|
"http://localhost:8001/products/1/prices?fetch_status=success&fetched_after=2026-01-14T00:00:00"
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" \\
|
|
"http://localhost:8001/logs?fetch_status=failed&fetched_before=2026-01-15T00:00:00"
|
|
```
|
|
|
|
Exports (CSV/JSON):
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" \\
|
|
"http://localhost:8001/products/export?format=csv"
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" \\
|
|
"http://localhost:8001/logs/export?format=json"
|
|
```
|
|
|
|
CRUD (examples rapides):
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" -X POST http://localhost:8001/products \\
|
|
-H "Content-Type: application/json" \\
|
|
-d '{"source":"amazon","reference":"REF1","url":"https://example.com"}'
|
|
```
|
|
|
|
Webhooks (exemples rapides):
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" -X POST http://localhost:8001/webhooks \\
|
|
-H "Content-Type: application/json" \\
|
|
-d '{"event":"price_changed","url":"https://example.com/webhook","enabled":true}'
|
|
curl -H "Authorization: Bearer $PW_API_TOKEN" -X POST http://localhost:8001/webhooks/1/test
|
|
```
|
|
|
|
## Web UI (Phase 4)
|
|
|
|
Interface Vue 3 dense avec themes Gruvbox/Monokai, header fixe, sidebar filtres, et split compare.
|
|
|
|
```bash
|
|
docker compose up -d frontend
|
|
# Acces: http://localhost:3000
|
|
```
|
|
|
|
## Configuration (scrap_url.yaml)
|
|
|
|
```yaml
|
|
urls:
|
|
- "https://www.amazon.fr/dp/B08N5WRWNW"
|
|
- "https://www.cdiscount.com/informatique/clavier-souris-webcam/example/f-1070123-example.html"
|
|
|
|
options:
|
|
use_playwright: true # Utiliser Playwright en fallback
|
|
headful: false # Mode headless (true = voir le navigateur)
|
|
save_html: true # Sauvegarder HTML pour debug
|
|
save_screenshot: true # Sauvegarder screenshot pour debug
|
|
timeout_ms: 60000 # Timeout par page (ms)
|
|
```
|
|
|
|
## Format de sortie (ProductSnapshot)
|
|
|
|
Chaque produit scraped est représenté par un objet `ProductSnapshot` contenant :
|
|
|
|
### Métadonnées
|
|
- `source`: Site d'origine (amazon, cdiscount, unknown)
|
|
- `url`: URL canonique du produit
|
|
- `fetched_at`: Date/heure de récupération (ISO 8601)
|
|
|
|
### Données produit
|
|
- `title`: Nom du produit
|
|
- `price`: Prix (float ou null)
|
|
- `currency`: Devise (EUR, USD, etc.)
|
|
- `shipping_cost`: Frais de port (float ou null)
|
|
- `stock_status`: Statut stock (in_stock, out_of_stock, unknown)
|
|
- `reference`: Référence produit (ASIN pour Amazon, SKU pour autres)
|
|
- `images`: Liste des URLs d'images
|
|
- `category`: Catégorie du produit
|
|
- `specs`: Caractéristiques techniques (dict clé/valeur)
|
|
|
|
### Debug
|
|
- `debug.method`: Méthode utilisée (http, playwright)
|
|
- `debug.errors`: Liste des erreurs rencontrées
|
|
- `debug.notes`: Notes techniques
|
|
- `debug.status`: Statut de récupération (success, partial, failed)
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
# Lancer tous les tests
|
|
pytest
|
|
|
|
# Tests avec couverture
|
|
pytest --cov=pricewatch
|
|
|
|
# Tests d'un store spécifique
|
|
pytest tests/stores/amazon/
|
|
pytest tests/stores/cdiscount/
|
|
|
|
# Mode verbose
|
|
pytest -v
|
|
```
|
|
|
|
## Architecture des stores
|
|
|
|
Chaque store implémente la classe abstraite `BaseStore` avec :
|
|
|
|
- `match(url) -> float`: Score de correspondance (0.0 à 1.0)
|
|
- `canonicalize(url) -> str`: Normalisation de l'URL
|
|
- `extract_reference(url) -> str`: Extraction référence produit
|
|
- `fetch(url, method, options) -> str`: Récupération HTML
|
|
- `parse(html, url) -> ProductSnapshot`: Parsing vers modèle canonique
|
|
|
|
Les sélecteurs (XPath/CSS) sont externalisés dans `selectors.yml` pour faciliter la maintenance.
|
|
|
|
## Ajouter un nouveau store
|
|
|
|
1. Créer `pricewatch/app/stores/nouveaustore/`
|
|
2. Créer `store.py` avec une classe héritant de `BaseStore`
|
|
3. Créer `selectors.yml` avec les sélecteurs XPath/CSS
|
|
4. Ajouter des fixtures HTML dans `fixtures/`
|
|
5. Enregistrer le store dans le `Registry`
|
|
6. Écrire les tests dans `tests/stores/nouveaustore/`
|
|
|
|
## Gestion des erreurs
|
|
|
|
L'application est conçue pour être robuste face aux anti-bots :
|
|
|
|
- **403 Forbidden** : Fallback automatique vers Playwright
|
|
- **Captcha détecté** : Logged dans `debug.errors`, statut `failed`
|
|
- **Timeout** : Configurable, logged
|
|
- **Parsing échoué** : ProductSnapshot partiel avec `debug.status=partial`
|
|
|
|
Aucune erreur ne doit crasher silencieusement : toutes sont loggées et tracées dans le ProductSnapshot.
|
|
|
|
## Roadmap
|
|
|
|
### Phase 1 : CLI (actuelle)
|
|
- ✅ Pipeline YAML → JSON
|
|
- ✅ Support Amazon + Cdiscount
|
|
- ✅ Scraping HTTP + Playwright
|
|
- ✅ Tests pytest
|
|
|
|
### Phase 2 : Persistence
|
|
- [x] Base de données PostgreSQL
|
|
- [x] Migrations Alembic
|
|
- [ ] Historique des prix
|
|
|
|
### Phase 3 : Automation
|
|
- [ ] Worker (Redis + RQ/Celery)
|
|
- [ ] Planification quotidienne
|
|
- [ ] Gestion de la queue
|
|
|
|
### Phase 4 : Web UI
|
|
- [ ] Interface web responsive
|
|
- [ ] Dark theme (Gruvbox)
|
|
- [ ] Graphiques historique prix
|
|
- [ ] Gestion des alertes
|
|
|
|
### Phase 5 : Alertes
|
|
- [ ] Notifications baisse de prix
|
|
- [ ] Notifications retour en stock
|
|
- [ ] Webhooks/email
|
|
|
|
## Développement
|
|
|
|
### Règles
|
|
- Python 3.12 obligatoire
|
|
- Commentaires et discussions en français
|
|
- Toute décision technique doit être justifiée (1-3 phrases)
|
|
- Pas d'optimisation prématurée
|
|
- Logging systématique (méthode, durée, erreurs)
|
|
- Tests obligatoires pour chaque store
|
|
|
|
### Documentation
|
|
- `README.md` : Ce fichier
|
|
- `TODO.md` : Liste des tâches priorisées
|
|
- `CHANGELOG.md` : Journal des modifications
|
|
- `CLAUDE.md` : Guide pour Claude Code
|
|
|
|
## License
|
|
|
|
À définir
|
|
|
|
## Auteur
|
|
|
|
À définir
|