Files
Priceflow/app/routers/amazon.py
T
Claude af7c32a4d8 feat: Rewrite Amazon scraper to use Browserless service
- Created amazon_scraper_v2.py using browserless_service (Playwright)
- Removed dependency on Crawl4AI which was not loading pages correctly
- Use browserless proxy rotation (use_proxy=True)
- More robust selector fallbacks for title, price, rating
- Fixed 2128 bytes issue - now loads full Amazon pages (>100KB)
- Updated router to use new scraper

Previous issue: Crawl4AI only loaded 2128 bytes
Now: Browserless loads complete pages with all products
2025-11-30 09:42:25 +00:00

122 lines
3.6 KiB
Python

"""
API Router pour la recherche Amazon France
Utilise Server-Sent Events (SSE) pour le streaming des résultats
Uses Browserless service for reliable scraping
"""
import json
import logging
from typing import AsyncGenerator
from fastapi import APIRouter, Query
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from app.services.amazon_scraper_v2 import scrape_amazon_search, AmazonProduct
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/amazon", tags=["amazon"])
class AmazonSearchProgress(BaseModel):
"""Progress model for SSE streaming"""
status: str # 'searching', 'completed', 'error'
total: int
completed: int
message: str
results: list[dict]
@router.get("/search")
async def search_amazon(
q: str = Query(..., min_length=1, description="Terme de recherche"),
max_results: int = Query(20, ge=1, le=50, description="Nombre max de résultats"),
):
"""
Recherche de produits sur Amazon France.
Retourne un flux SSE avec les résultats.
Format des événements SSE:
- event: progress
- data: {"status": "...", "total": 1, "completed": 0/1, "results": [...]}
"""
async def generate() -> AsyncGenerator[str, None]:
try:
# Initial progress
progress = AmazonSearchProgress(
status="searching",
total=1,
completed=0,
message=f"Recherche sur Amazon France: '{q}'...",
results=[]
)
yield f"event: progress\ndata: {progress.model_dump_json()}\n\n"
# Execute search
logger.info(f"Starting Amazon search for: {q}")
products = await scrape_amazon_search(q, max_results=max_results)
# Convert to dict
results = [p.model_dump() for p in products]
# Final progress
if results:
progress = AmazonSearchProgress(
status="completed",
total=1,
completed=1,
message=f"✅ {len(results)} produits trouvés",
results=results
)
else:
progress = AmazonSearchProgress(
status="completed",
total=1,
completed=1,
message="Aucun produit trouvé",
results=[]
)
yield f"event: progress\ndata: {progress.model_dump_json()}\n\n"
except Exception as e:
logger.error(f"Error during Amazon search: {e}", exc_info=True)
error_progress = AmazonSearchProgress(
status="error",
total=1,
completed=1,
message=f"Erreur: {str(e)}",
results=[]
)
yield f"event: progress\ndata: {error_progress.model_dump_json()}\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no",
},
)
@router.get("/health")
async def amazon_health():
"""Vérifie que le service Amazon est opérationnel"""
return {
"status": "ok",
"service": "Amazon France Scraper",
"anti_detection": "enabled",
"features": [
"User-Agent rotation",
"Proxy rotation (10 proxies)",
"Random delays",
"Realistic headers",
"Crawl4AI anti-detection"
]
}