mirror of
https://github.com/R0m1k3/Priceflow.git
synced 2026-10-23 07:08:12 +02:00
feat: Implement HTTPX fallback in Cataloguemate scraper for enhanced reliability and add associated implementation plan and debug script.
This commit is contained in:
1 parent
17b3009b1d
commit
4bf950c5eb
4 files changed
+179
-27
No files matched your search
@@ -8,20 +8,38 @@ Refactored to use BrowserlessService for robust containerized scraping.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
import hashlib
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Optional
|
||||
import httpx
|
||||
import random
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from sqlalchemy.orm import Session
|
||||
async def _fetch_with_fallback(url: str) -> str:
|
||||
"""Fetch content using Browserless first, then fallback to HTTPX."""
|
||||
# 1. Try Browserless
|
||||
try:
|
||||
_, html_content = await browserless_service.get_page_content(url)
|
||||
if html_content and len(html_content) > 500:
|
||||
return html_content
|
||||
except Exception as e:
|
||||
logger.warning(f"Browserless fetch failed for {url}: {e}")
|
||||
|
||||
from app.models import Enseigne, Catalogue, CataloguePage, ScrapingLog
|
||||
from app.services.browserless_service import browserless_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
BASE_URL = "https://www.cataloguemate.fr"
|
||||
# 2. Fallback to HTTPX
|
||||
logger.info(f"Using HTTPX fallback for {url}...")
|
||||
try:
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"Accept-Language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
}
|
||||
async with httpx.AsyncClient(verify=False, timeout=30.0) as client:
|
||||
response = await client.get(url, headers=headers)
|
||||
if response.status_code == 200:
|
||||
logger.info(f"HTTPX fetch successful ({len(response.text)} chars)")
|
||||
return response.text
|
||||
else:
|
||||
logger.error(f"HTTPX failed with status {response.status_code}")
|
||||
except Exception as e:
|
||||
logger.error(f"HTTPX fallback failed: {e}")
|
||||
|
||||
return ""
|
||||
|
||||
async def scrape_catalog_list(enseigne: Enseigne) -> list[dict[str, Any]]:
|
||||
"""
|
||||
@@ -40,8 +58,8 @@ async def scrape_catalog_list(enseigne: Enseigne) -> list[dict[str, Any]]:
|
||||
url = f"{BASE_URL}/offres/paris/{slug}/"
|
||||
logger.info(f"Scraping catalog list from: {url}")
|
||||
|
||||
# Use browserless service to get content
|
||||
_, html_content = await browserless_service.get_page_content(url)
|
||||
# Use robust fetch with fallback
|
||||
html_content = await _fetch_with_fallback(url)
|
||||
|
||||
if not html_content:
|
||||
logger.error(f"Failed to fetch list {url}")
|
||||
@@ -108,10 +126,9 @@ async def scrape_catalog_pages(catalog_url: str) -> list[dict[str, Any]]:
|
||||
page_num = 1
|
||||
max_pages = 100 # Default safety limit
|
||||
|
||||
# IMPORTANT: Pagination links only appear on page 2+, not on page 1
|
||||
# So we fetch page 2 first to detect the max pages
|
||||
page_2_url = f"{catalog_url}?page=2"
|
||||
_, page_2_html = await browserless_service.get_page_content(page_2_url)
|
||||
page_2_html = await _fetch_with_fallback(page_2_url)
|
||||
|
||||
if page_2_html:
|
||||
soup = BeautifulSoup(page_2_html, 'html.parser')
|
||||
@@ -162,7 +179,7 @@ async def scrape_catalog_pages(catalog_url: str) -> list[dict[str, Any]]:
|
||||
if page_num == 2 and page_2_html:
|
||||
html_content = page_2_html
|
||||
else:
|
||||
_, html_content = await browserless_service.get_page_content(current_url)
|
||||
html_content = await _fetch_with_fallback(current_url)
|
||||
|
||||
if not html_content:
|
||||
logger.warning(f"Failed to fetch page {page_num}")
|
||||
|
||||
Reference in new issue
Block a user