SPB Git

spb/fabri-ka Public

Agrégateur de produits québécois — www.fabri-ka.com

HTML 57.9% Python 18.6% TypeScript 15.6% CSS 7.8%
1.8 KB · 52 lines python
Raw Blame History
1# -----------------------------------------------------------------------------2# Fabri-Ka — Agrégateur de produits québécois3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# connectors/scrapfly.py : transport de secours via l'API Scrapfly (anti-bot,5#   rendu JS optionnel). Utilisé quand l'accès direct échoue (403/429/HTML6#   au lieu de JSON). Chaque appel consomme des crédits : on ne l'emploie7#   qu'en dernier recours et on mémorise les échecs définitifs.8# -----------------------------------------------------------------------------9from __future__ import annotations1011import json12import os13import threading14import time1516import requests1718API = "https://api.scrapfly.io/scrape"19_LOCK = threading.Lock()20_MIN_INTERVAL = 0.521_last = [0.0]222324def available() -> bool:25    return bool(os.environ.get("SCRAPFLY_API_KEY"))262728def scrapfly_get(url: str, render_js: bool = False, timeout: int = 150) -> tuple[int, str]:29    """GET via Scrapfly. Retourne (status_code_amont, contenu)."""30    key = os.environ.get("SCRAPFLY_API_KEY")31    if not key:32        raise RuntimeError("SCRAPFLY_API_KEY manquant (voir .env)")33    with _LOCK:34        wait = _MIN_INTERVAL - (time.time() - _last[0])35        if wait > 0:36            time.sleep(wait)37        _last[0] = time.time()38    params = {"key": key, "url": url, "asp": "true", "country": "ca"}39    if render_js:40        params["render_js"] = "true"41    r = requests.get(API, params=params, timeout=timeout)42    r.raise_for_status()43    res = r.json().get("result", {})44    return int(res.get("status_code") or 0), res.get("content") or ""454647def scrapfly_json(url: str, render_js: bool = False) -> dict | list:48    status, content = scrapfly_get(url, render_js=render_js)49    if status != 200:50        raise RuntimeError(f"scrapfly upstream {status} pour {url}")51    return json.loads(content)52