mirror of
https://github.com/R0m1k3/Priceflow.git
synced 2026-10-11 17:29:14 +02:00
3 files changed
+60
-16
No files matched your search
@@ -49,13 +49,17 @@ POPUP_SELECTORS = [
|
||||
"button:has-text('Tout accepter')",
|
||||
"button:has-text('Accepter')",
|
||||
"input[aria-labelledby='sp-cc-accept-label']",
|
||||
# Amazon interstitials
|
||||
"#nav-flyout-prime button",
|
||||
|
||||
# Amazon Interstitials (Soft blocks)
|
||||
"button:has-text('Continuer les achats')",
|
||||
"span:has-text('Continuer les achats')",
|
||||
"a:has-text('Continuer les achats')",
|
||||
"input[value='Continuer les achats']",
|
||||
"input[value='Continue shopping']",
|
||||
"span.a-button-inner > input.a-button-input[type='submit']",
|
||||
"form:has-text('Continuer les achats') input[type='submit']",
|
||||
"[aria-labelledby='continue-shopping-label']",
|
||||
]
|
||||
|
||||
|
||||
@@ -200,21 +204,42 @@ class BrowserlessService:
|
||||
|
||||
@staticmethod
|
||||
async def _handle_popups(page: Page):
|
||||
"""Attempt to close popups and cookie banners."""
|
||||
"""Attempt to close popups and cookie banners with retry logic."""
|
||||
logger.debug("Attempting to close popups...")
|
||||
|
||||
# First pass: Try to close all visible popups
|
||||
closed_popups = []
|
||||
for popup_selector in POPUP_SELECTORS:
|
||||
try:
|
||||
if await page.locator(popup_selector).count() > 0:
|
||||
logger.info(f"🚫 Closing popup: {popup_selector}")
|
||||
await page.locator(popup_selector).first.click(timeout=2000)
|
||||
await page.wait_for_timeout(500)
|
||||
closed_popups.append(popup_selector)
|
||||
await page.wait_for_timeout(1000)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
await page.keyboard.press("Escape")
|
||||
except Exception:
|
||||
pass
|
||||
# Try Escape key multiple times
|
||||
for _ in range(2):
|
||||
try:
|
||||
await page.keyboard.press("Escape")
|
||||
await page.wait_for_timeout(500)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Second pass: Verify and retry if any popups are still visible
|
||||
if closed_popups:
|
||||
logger.info(f"Verifying {len(closed_popups)} closed popup(s)...")
|
||||
await page.wait_for_timeout(1000)
|
||||
|
||||
for popup_selector in closed_popups:
|
||||
try:
|
||||
if await page.locator(popup_selector).count() > 0:
|
||||
logger.warning(f"Popup reappeared, retrying: {popup_selector}")
|
||||
await page.locator(popup_selector).first.click(timeout=2000)
|
||||
await page.wait_for_timeout(1000)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
async def _extract_amazon_price(page: Page) -> str:
|
||||
|
||||
@@ -16,15 +16,28 @@ class ItemService:
|
||||
@staticmethod
|
||||
def get_items(db: Session):
|
||||
items = db.query(models.Item).all()
|
||||
return [
|
||||
{
|
||||
**item.__dict__,
|
||||
"screenshot_url": f"/screenshots/item_{item.id}.png"
|
||||
if os.path.exists(f"screenshots/item_{item.id}.png")
|
||||
else None,
|
||||
}
|
||||
for item in items
|
||||
]
|
||||
result = []
|
||||
for item in items:
|
||||
# Get latest price history with screenshot
|
||||
latest_history = (
|
||||
db.query(models.PriceHistory)
|
||||
.filter(models.PriceHistory.item_id == item.id)
|
||||
.filter(models.PriceHistory.screenshot_path.isnot(None))
|
||||
.order_by(models.PriceHistory.timestamp.desc())
|
||||
.first()
|
||||
)
|
||||
|
||||
screenshot_url = None
|
||||
if latest_history and latest_history.screenshot_path:
|
||||
# Convert absolute path /app/screenshots/... to URL /screenshots/...
|
||||
filename = os.path.basename(latest_history.screenshot_path)
|
||||
screenshot_url = f"/screenshots/{filename}"
|
||||
elif os.path.exists(f"screenshots/item_{item.id}.png"):
|
||||
# Fallback to legacy static file
|
||||
screenshot_url = f"/screenshots/item_{item.id}.png"
|
||||
|
||||
result.append({**item.__dict__, "screenshot_url": screenshot_url})
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def create_item(db: Session, item: schemas.ItemCreate):
|
||||
|
||||
@@ -20,6 +20,12 @@ POPUP_SELECTORS = [
|
||||
"input[aria-labelledby='sp-cc-accept-label']",
|
||||
"#nav-flyout-prime button", # Prime flyout
|
||||
|
||||
# Amazon Interstitials (Soft blocks)
|
||||
"button:has-text('Continuer les achats')",
|
||||
"input[value='Continuer les achats']",
|
||||
"span.a-button-inner > input.a-button-input[type='submit']",
|
||||
"[aria-labelledby='continue-shopping-label']",
|
||||
|
||||
# French RGPD/Cookie consent platforms
|
||||
"#axeptio_btn_acceptAll", # Axeptio
|
||||
"#axeptio_main_button",
|
||||
|
||||
Reference in new issue
Block a user