Files
Michael f223dc5a29 feat: Increase Amazon limit to 50 and fix screenshot framing
- Increased default Amazon search results limit from 20 to 50 in backend and frontend
- Improved TrackingScraperService to target main product area on Amazon (avoiding reviews)
- Added specific selectors for Amazon product page (#imgTagWrapperId, #productTitle, etc.)
2025-12-01 16:18:35 +01: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_service import amazon_scraper_service, 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(50, ge=1, le=100, 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 with persistent browser service
logger.info(f"Starting Amazon search for: {q}")
products = await amazon_scraper_service.scrape_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"
]
}