[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-fr-comment-scraper-api-rest-binance-proxies":3},{"success":4,"payload":5,"related":61,"errors":126},true,{"id":6,"slug":7,"title":8,"excerpt":9,"body_html":10,"meta_title":11,"meta_description":12,"canonical_url":13,"canonical_override":14,"og_title":15,"og_description":16,"og_image_url":17,"faq_json":18,"key_takeaways":14,"allow_index":4,"noindex_google_only":28,"allow_follow":4,"published_at":29,"updated_at":29,"content_updated_at":30,"featured_image_url":31,"featured_image_alt":32,"card_image_url":33,"reading_time_minutes":34,"author":35,"categories":39,"tags":46,"alternates":47,"locale_paths":53,"views":60},194,"comment-scraper-api-rest-binance-proxies","Limites de poids des API d'exchanges crypto : collecter les données de marché avec des proxies (exemple Binance)","Guide pratique pour collecter les données de marché publiques de Binance via son API REST à grande échelle en utilisant des proxies rotatifs. Endpoints, poids, rate limiting, code Python et Node.js inclus.","\u003Ch2>Comment scraper l'API REST de Binance avec des proxies : vue d'ensemble\u003C\u002Fh2>\n\u003Cp>Si vous construisez des jeux de données de prix ou d'order book pour du backtesting quant, vous avez probablement besoin de récupérer les données de marché publiques de Binance. Mais comment scraper l'API REST de Binance avec des proxies sans se faire bannir ? La réponse tient en trois mots : \u003Cem>endpoints, poids, rotation\u003C\u002Fem>. Binance impose un système de rate limiting basé sur un budget de poids par adresse IP, et un seul endpoint mal choisi peut épuiser votre quota en quelques minutes.\u003C\u002Fp>\n\u003Cp>Ce guide s'adresse aux développeurs quant et ingénieurs de données crypto. Nous couvrons les endpoints clés (\u003Ccode>\u002Fapi\u002Fv3\u002Fklines\u003C\u002Fcode>, \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode>, \u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002F24hr\u003C\u002Fcode>, \u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002Fprice\u003C\u002Fcode>), le système de poids de Binance, la rotation d'IP via \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">ProxyHat\u003C\u002Fa>, et des exemples de code prêts à l'emploi en Python et Node.js.\u003C\u002Fp>\n\u003Cblockquote>\u003Cp>\u003Cstrong>Conformité :\u003C\u002Fstrong> ce guide couvre uniquement les \u003Cem>données de marché publiques\u003C\u002Fem> exposées par l'API REST publique de Binance. Respectez les poids documentés, lisez le \u003Ca href=\"https:\u002F\u002Fwww.binance.com\u002Fen\u002Fterms\" rel=\"noopener noreferrer\">Terms of Service\u003C\u002Fa> de Binance, et utilisez l'accès officiel si les conditions l'exigent. Ne scrapez pas de données authentifiées ou privées.\u003C\u002Fp>\u003C\u002Fblockquote>\n\n\u003Ch2>Endpoints de marché public et système de poids\u003C\u002Fh2>\n\u003Cp>L'API REST publique de Binance (domaine \u003Ccode>api.binance.com\u003C\u002Fcode>) expose des endpoints de marché sans authentification. Chaque endpoint consomme un certain « poids » (weight) dans votre budget de rate limit. Le tableau ci-dessous récapitule les endpoints les plus utiles pour la collecte de données.\u003C\u002Fp>\n\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>Endpoint\u003C\u002Fth>\u003Cth>Description\u003C\u002Fth>\u003Cth>Poids par requête\u003C\u002Fth>\u003Cth>Paramètres clés\u003C\u002Fth>\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fklines\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Bougies OHLCV (chandeliers)\u003C\u002Ftd>\u003Ctd>1–2 (selon limit)\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode>, \u003Ccode>interval\u003C\u002Fcode>, \u003Ccode>limit\u003C\u002Fcode> (max 1000)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Order book (carnet d'ordres)\u003C\u002Ftd>\u003Ctd>5–20 (selon limit)\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode>, \u003Ccode>limit\u003C\u002Fcode> (5, 10, 20, 50, 100, 500, 1000)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002F24hr\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Statistiques 24h par symbole\u003C\u002Ftd>\u003Ctd>1–40 (selon paramètres)\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode> (optionnel)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002Fprice\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Prix spot en temps réel\u003C\u002Ftd>\u003Ctd>1–2\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode> (optionnel)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Cp>Binance renvoie l'en-tête de réponse \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode> qui indique le poids total consommé par votre IP dans la fenêtre courante d'une minute. C'est \u003Cstrong>la métrique la plus importante\u003C\u002Fstrong> à surveiller en production. Vous trouverez la documentation officielle des poids sur \u003Ca href=\"https:\u002F\u002Fdevelopers.binance.com\u002Fdocs\u002Fbinance-spot-api-docs\u002Frest-api\" rel=\"noopener noreferrer\">developers.binance.com\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch3>Le piège de l'order book profond\u003C\u002Fh3>\n\u003Cp>Un appel \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth?limit=1000\u003C\u002Fcode> coûte 20 poids. Le budget par IP est d'environ \u003Cstrong>6000 poids par minute\u003C\u002Fstrong>. À 20 poids par requête, vous pouvez faire 300 appels\u002Fminute\u002FIP — soit un toutes les 200 ms. Si vous sondez \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode> en continu sans rotation d'IP, vous épuisez le budget en moins de 5 minutes, puis recevez des HTTP 429 (rate limit) puis potentiellement un HTTP 418 (IP bannie temporairement).\u003C\u002Fp>\n\n\u003Ch2>Rate limiting Binance : 429, 418 et Retry-After\u003C\u002Fh2>\n\u003Cp>Binance utilise un système de limite de débit basé sur le poids, pas sur le nombre brut de requêtes. Le budget par défaut est de 6000 poids par minute et par IP pour les endpoints de marché. Quand vous dépassez ce budget :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>HTTP 429 (Too Many Requests)\u003C\u002Fstrong> — vous avez dépassé la limite. L'en-tête \u003Ccode>Retry-After\u003C\u002Fcode> indique combien de secondes attendre.\u003C\u002Fli>\n\u003Cli>HTTP 418 (I'm a teapot) — Binance a détecté un comportement abusif répété et bannit votre IP temporairement (souvent 2 minutes à plusieurs heures).\u003C\u002Fli>\n\u003Cli>HTTP 451 (Unavailable for Legal Reasons) — l'IP est dans une juridiction bloquée (ex. États-Unis vers Binance.com).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>La stratégie de mitigation comporte trois axes : (1) surveiller \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode>, (2) implémenter un backoff exponentiel sur 429, (3) répartir le poids sur plusieurs IP via des \u003Ca href=\"\u002Ffr\u002Fproxy\u002Fresidential\">proxies résidentiels\u003C\u002Fa> rotatifs.\u003C\u002Fp>\n\u003Cblockquote>\u003Cp>Avec 10 IP résidentielles rotatives et 6000 poids\u002FIP\u002Fminute, votre budget total passe à 60 000 poids\u002Fminute — suffisant pour sonder l'order book BTCUSDT à limit=1000 toutes les 20 ms sans interruption.\u003C\u002Fp>\u003C\u002Fblockquote>\n\n\u003Ch2>Rotation d'IP avec ProxyHat : répartition du poids et contournement géo\u003C\u002Fh2>\n\u003Cp>\u003Ca href=\"\u002Ffr\u002Fuse-cases\u002Fweb-scraping\">Le web scraping à grande échelle\u003C\u002Fa> exige une rotation d'IP fiable. ProxyHat fournit des proxies résidentiels, mobiles et datacenter accessibles via le gateway \u003Ccode>gate.proxyhat.com\u003C\u002Fcode> (HTTP port 8080, SOCKS5 port 1080). La rotation et le ciblage géographique se contrôlent directement dans le nom d'utilisateur.\u003C\u002Fp>\n\n\u003Ch3>Format de connexion\u003C\u002Fh3>\n\u003Cpre>\u003Ccode># HTTP — rotation automatique par requête\nhttp:\u002F\u002FUSERNAME:PASSWORD@gate.proxyhat.com:8080\n\n# HTTP — ciblage pays (ex. États-Unis pour Binance.US)\nhttp:\u002F\u002Fuser-country-US:PASSWORD@gate.proxyhat.com:8080\n\n# HTTP — session collante (même IP pour pagination\u002Fbackfill)\nhttp:\u002F\u002Fuser-sid-abc123:PASSWORD@gate.proxyhat.com:8080\n\n# SOCKS5\nsocks5:\u002F\u002FUSERNAME:PASSWORD@gate.proxyhat.com:1080\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3>Binance.com vs Binance.US et le HTTP 451\u003C\u002Fh3>\n\u003Cp>Binance.com restreint l'accès depuis certaines juridictions (notamment les États-Unis) avec un HTTP 451. Si vous devez accéder à Binance.US depuis une IP non-US, ou à l'inverse accéder à Binance.com depuis une IP US, le ciblage géographique \u003Ccode>-country-US\u003C\u002Fcode> ou \u003Ccode>-country-DE\u003C\u002Fcode> dans le nom d'utilisateur ProxyHat résout le problème. Consultez la liste complète des \u003Ca href=\"\u002Ffr\u002Flocations\">localisations disponibles\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch2>Implémentation Python : rotation par requête avec requests\u003C\u002Fh2>\n\u003Cp>Voici un exemple complet en Python utilisant \u003Ccode>requests\u003C\u002Fcode> avec rotation d'IP ProxyHat, throttling basé sur le poids, et retries avec backoff exponentiel.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import requests\nimport time\nimport logging\nfrom urllib.parse import urlencode\n\nlogging.basicConfig(level=logging.INFO, format=&apos;%(asctime)s %(levelname)s %(message)s&apos;)\nlogger = logging.getLogger(&quot;binance_scraper&quot;)\n\nPROXYHAT_GATEWAY = &quot;gate.proxyhat.com&quot;\nPROXYHAT_PORT = 8080\nPROXYHAT_USER = &quot;USERNAME&quot;\nPROXYHAT_PASS = &quot;PASSWORD&quot;\n\nBASE_URL = &quot;https:\u002F\u002Fapi.binance.com&quot;\nWEIGHT_BUDGET_PER_IP = 6000  # poids par minute et par IP\n\n# Dictionnaire des poids par endpoint\u002Fparamètres\nENDPOINT_WEIGHTS = {\n    &quot;\u002Fapi\u002Fv3\u002Fklines&quot;: 2,          # limit &lt;= 100\n    &quot;\u002Fapi\u002Fv3\u002Fdepth_100&quot;: 5,\n    &quot;\u002Fapi\u002Fv3\u002Fdepth_1000&quot;: 20,\n    &quot;\u002Fapi\u002Fv3\u002Fticker\u002Fprice&quot;: 1,\n    &quot;\u002Fapi\u002Fv3\u002Fticker\u002F24hr_single&quot;: 1,\n}\n\nclass BinanceScraper:\n    def __init__(self, max_retries=5):\n        self.session = requests.Session()\n        self.max_retries = max_retries\n        self.used_weight = 0\n\n    def _get_proxy_url(self, country=None, session_id=None):\n        &quot;&quot;&quot;Construit l&apos;URL du proxy ProxyHat avec rotation ou session collante.&quot;&quot;&quot;\n        user = PROXYHAT_USER\n        if country:\n            user += f&quot;-country-{country}&quot;\n        if session_id:\n            user += f&quot;-sid-{session_id}&quot;\n        return f&quot;http:\u002F\u002F{user}:{PROXYHAT_PASS}@{PROXYHAT_GATEWAY}:{PROXYHAT_PORT}&quot;\n\n    def _fetch(self, path, params=None, country=None, session_id=None):\n        url = f&quot;{BASE_URL}{path}&quot;\n        proxy_url = self._get_proxy_url(country=country, session_id=session_id)\n        proxies = {&quot;http&quot;: proxy_url, &quot;https&quot;: proxy_url}\n\n        for attempt in range(self.max_retries):\n            try:\n                resp = self.session.get(url, params=params, proxies=proxies, timeout=15)\n\n                # Surveiller le poids consommé\n                weight_header = resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;)\n                if weight_header:\n                    self.used_weight = int(weight_header)\n                    logger.info(f&quot;Used weight (1M): {self.used_weight} | status={resp.status_code}&quot;)\n\n                if resp.status_code == 200:\n                    return resp.json()\n\n                if resp.status_code == 429:\n                    retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 5))\n                    logger.warning(f&quot;429 rate limited — waiting {retry_after}s&quot;)\n                    time.sleep(retry_after)\n                    continue\n\n                if resp.status_code == 418:\n                    retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 120))\n                    logger.error(f&quot;418 IP banned — waiting {retry_after}s&quot;)\n                    time.sleep(retry_after)\n                    continue\n\n                if resp.status_code == 451:\n                    logger.error(&quot;451 geo-blocked — switching country&quot;)\n                    # Forcer un autre pays au prochain appel\n                    return None\n\n                resp.raise_for_status()\n\n            except requests.RequestException as e:\n                wait = 2 ** attempt\n                logger.warning(f&quot;Attempt {attempt+1} failed: {e} — retry in {wait}s&quot;)\n                time.sleep(wait)\n\n        raise RuntimeError(f&quot;Max retries exceeded for {path}&quot;)\n\n    def get_klines(self, symbol, interval=&quot;1m&quot;, limit=100, session_id=None):\n        params = {&quot;symbol&quot;: symbol, &quot;interval&quot;: interval, &quot;limit&quot;: limit}\n        return self._fetch(&quot;\u002Fapi\u002Fv3\u002Fklines&quot;, params=params, session_id=session_id)\n\n    def get_depth(self, symbol, limit=100):\n        params = {&quot;symbol&quot;: symbol, &quot;limit&quot;: limit}\n        path = &quot;\u002Fapi\u002Fv3\u002Fdepth&quot;\n        weight = ENDPOINT_WEIGHTS.get(f&quot;\u002Fapi\u002Fv3\u002Fdepth_{limit}&quot;, 5)\n        # Throttle : si on approche du budget, attendre\n        if self.used_weight + weight &gt; WEIGHT_BUDGET_PER_IP * 0.8:\n            logger.info(&quot;Approaching weight budget — pausing 10s&quot;)\n            time.sleep(10)\n        return self._fetch(path, params=params)\n\n    def get_ticker_price(self, symbol=None):\n        params = {&quot;symbol&quot;: symbol} if symbol else {}\n        return self._fetch(&quot;\u002Fapi\u002Fv3\u002Fticker\u002Fprice&quot;, params=params)\n\n# Utilisation\nscraper = BinanceScraper(max_retries=5)\n\n# Rotation par requête — chaque appel utilise une nouvelle IP\nklines = scraper.get_klines(&quot;BTCUSDT&quot;, interval=&quot;1m&quot;, limit=100)\nprint(f&quot;Récupéré {len(klines)} bougies BTCUSDT&quot;)\n\n# Order book profond\ndepth = scraper.get_depth(&quot;BTCUSDT&quot;, limit=1000)\nprint(f&quot;Bids: {len(depth.get(&apos;bids&apos;, []))} | Asks: {len(depth.get(&apos;asks&apos;, []))}&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Session collative pour backfill de klines (httpx async)\u003C\u002Fh2>\n\u003Cp>Pour récupérer des données historiques via pagination (backfill), vous devez garder la même IP pendant toute la séquence afin d'éviter des incohérences de poids et de latence. Utilisez le flag \u003Ccode>-sid-abc123\u003C\u002Fcode> dans le nom d'utilisateur ProxyHat.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import httpx\nimport asyncio\nimport logging\nfrom datetime import datetime, timedelta\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(&quot;klines_backfill&quot;)\n\nPROXYHAT_USER = &quot;USERNAME&quot;\nPROXYHAT_PASS = &quot;PASSWORD&quot;\nGATEWAY = &quot;gate.proxyhat.com&quot;\nPORT = 8080\n\nasync def backfill_klines(symbol, interval, start_ms, end_ms, batch_size=1000):\n    &quot;&quot;&quot;Récupère toutes les bougies entre start_ms et end_ms avec session collante.&quot;&quot;&quot;\n    session_id = f&quot;backfill-{symbol}-{int(start_ms\u002F1000)}&quot;\n    proxy_url = (\n        f&quot;http:\u002F\u002F{PROXYHAT_USER}-sid-{session_id}&quot;\n        f&quot;:{PROXYHAT_PASS}@{GATEWAY}:{PORT}&quot;\n    )\n\n    all_klines = []\n    current_start = start_ms\n\n    async with httpx.AsyncClient(\n        proxy=proxy_url,\n        timeout=httpx.Timeout(30.0),\n        limits=httpx.Limits(max_connections=5, max_keepalive_connections=3),\n    ) as client:\n        retry_count = 0\n\n        while current_start &lt; end_ms:\n            params = {\n                &quot;symbol&quot;: symbol,\n                &quot;interval&quot;: interval,\n                &quot;startTime&quot;: current_start,\n                &quot;endTime&quot;: end_ms,\n                &quot;limit&quot;: batch_size,\n            }\n\n            try:\n                resp = await client.get(\n                    &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fklines&quot;,\n                    params=params,\n                )\n\n                weight = resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, &quot;?&quot;)\n                logger.info(f&quot;Status {resp.status_code} | Weight: {weight} | Batch from {current_start}&quot;)\n\n                if resp.status_code == 429:\n                    retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 5))\n                    logger.warning(f&quot;429 — sleeping {retry_after}s&quot;)\n                    await asyncio.sleep(retry_after)\n                    continue\n\n                if resp.status_code == 418:\n                    retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 120))\n                    logger.error(f&quot;418 ban — sleeping {retry_after}s&quot;)\n                    await asyncio.sleep(retry_after)\n                    continue\n\n                resp.raise_for_status()\n                data = resp.json()\n\n                if not data:\n                    break\n\n                all_klines.extend(data)\n                current_start = data[-1][0] + 1  # open time du dernier + 1ms\n                retry_count = 0\n\n                # Throttle doux : 10 req\u002Fs max\n                await asyncio.sleep(0.1)\n\n            except httpx.HTTPStatusError as e:\n                retry_count += 1\n                if retry_count &gt; 5:\n                    raise\n                wait = 2 ** retry_count\n                logger.warning(f&quot;HTTP error — retry in {wait}s: {e}&quot;)\n                await asyncio.sleep(wait)\n\n            except Exception as e:\n                logger.error(f&quot;Unexpected error: {e}&quot;)\n                raise\n\n    return all_klines\n\n# Exemple : récupérer 7 jours de bougies 1m pour ETHUSDT\nnow_ms = int(datetime.utcnow().timestamp() * 1000)\nweek_ago_ms = now_ms - int(timedelta(days=7).total_seconds() * 1000)\n\nklines = asyncio.run(backfill_klines(&quot;ETHUSDT&quot;, &quot;1m&quot;, week_ago_ms, now_ms))\nprint(f&quot;Total bougies récupérées : {len(klines)}&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>ProxyHat SDK vs proxy brut : comparaison côte à côte\u003C\u002Fh2>\n\u003Cp>ProxyHat expose un SDK Python qui simplifie la rotation, les retries et la gestion des sessions. Voici le même appel \u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002Fprice\u003C\u002Fcode> réalisé avec un proxy brut puis avec le SDK.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># --- Méthode 1 : proxy brut avec requests ---\nimport requests\n\nproxy_url = &quot;http:\u002F\u002FUSERNAME:PASSWORD@gate.proxyhat.com:8080&quot;\nproxies = {&quot;http&quot;: proxy_url, &quot;https&quot;: proxy_url}\n\nresp = requests.get(\n    &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fticker\u002Fprice&quot;,\n    params={&quot;symbol&quot;: &quot;BTCUSDT&quot;},\n    proxies=proxies,\n    timeout=10,\n)\nprint(resp.json())\n\n# --- Méthode 2 : ProxyHat SDK ---\nfrom proxyhat import ProxyHatClient\n\nclient = ProxyHatClient(\n    username=&quot;USERNAME&quot;,\n    password=&quot;PASSWORD&quot;,\n    gateway=&quot;gate.proxyhat.com&quot;,\n    port=8080,\n)\n\n# Rotation automatique par requête\nresp = client.get(\n    &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fticker\u002Fprice&quot;,\n    params={&quot;symbol&quot;: &quot;BTCUSDT&quot;},\n    country=&quot;US&quot;,  # optionnel : ciblage géo\n    timeout=10,\n)\nprint(resp.json())\n\n# Session collante pour pagination\nresp2 = client.get(\n    &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fklines&quot;,\n    params={&quot;symbol&quot;: &quot;ETHUSDT&quot;, &quot;interval&quot;: &quot;1m&quot;, &quot;limit&quot;: 100},\n    session_id=&quot;backfill-eth-001&quot;,\n)\nprint(f&quot;Bougies : {len(resp2.json())}&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Node.js (axios) : scraping concurrent avec rotation\u003C\u002Fh2>\n\u003Cp>Pour les équipes JavaScript\u002FTypeScript, voici un exemple avec \u003Ccode>axios\u003C\u002Fcode> et un pool de proxies rotatifs ProxyHat.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>const axios = require(&apos;axios&apos;);\nconst HttpsProxyAgent = require(&apos;https-proxy-agent&apos;).HttpsProxyAgent;\n\nconst PROXYHAT_USER = &apos;USERNAME&apos;;\nconst PROXYHAT_PASS = &apos;PASSWORD&apos;;\nconst GATEWAY = &apos;gate.proxyhat.com&apos;;\nconst PORT = 8080;\n\nconst BASE_URL = &apos;https:\u002F\u002Fapi.binance.com&apos;;\nconst MAX_CONCURRENT = 10;\nconst WEIGHT_BUDGET = 6000;\n\nlet usedWeight = 0;\n\nfunction buildProxy(country = null, sessionId = null) {\n  let user = PROXYHAT_USER;\n  if (country) user += `-country-${country}`;\n  if (sessionId) user += `-sid-${sessionId}`;\n  return `http:\u002F\u002F${user}:${PROXYHAT_PASS}@${GATEWAY}:${PORT}`;\n}\n\nasync function fetchBinance(path, params = {}, options = {}) {\n  const proxyUrl = buildProxy(options.country, options.sessionId);\n  const agent = new HttpsProxyAgent(proxyUrl);\n\n  for (let attempt = 0; attempt &lt; 5; attempt++) {\n    try {\n      const resp = await axios.get(`${BASE_URL}${path}`, {\n        params,\n        httpsAgent: agent,\n        timeout: 15000,\n      });\n\n      const weight = parseInt(resp.headers[&apos;x-mbx-used-weight-1m&apos;] || &apos;0&apos;, 10);\n      usedWeight = weight;\n      console.log(`Status ${resp.status} | Weight: ${usedWeight} | ${path}`);\n\n      \u002F\u002F Throttle : si on approche du budget, attendre\n      if (usedWeight &gt; WEIGHT_BUDGET * 0.8) {\n        console.log(&apos;Approaching weight budget — pausing 10s&apos;);\n        await new Promise(r =&gt; setTimeout(r, 10000));\n      }\n\n      return resp.data;\n    } catch (err) {\n      if (err.response) {\n        const status = err.response.status;\n        const retryAfter = parseInt(err.response.headers[&apos;retry-after&apos;] || &apos;5&apos;, 10);\n\n        if (status === 429) {\n          console.warn(`429 rate limited — waiting ${retryAfter}s`);\n          await new Promise(r =&gt; setTimeout(r, retryAfter * 1000));\n          continue;\n        }\n        if (status === 418) {\n          console.error(`418 banned — waiting ${retryAfter}s`);\n          await new Promise(r =&gt; setTimeout(r, retryAfter * 1000));\n          continue;\n        }\n        if (status === 451) {\n          console.error(&apos;451 geo-blocked — try different country&apos;);\n          throw err;\n        }\n      }\n\n      const wait = Math.pow(2, attempt);\n      console.warn(`Attempt ${attempt + 1} failed: ${err.message} — retry in ${wait}s`);\n      await new Promise(r =&gt; setTimeout(r, wait * 1000));\n    }\n  }\n  throw new Error(`Max retries exceeded for ${path}`);\n}\n\n\u002F\u002F Scraping concurrent de plusieurs symboles\nasync function scrapeMultipleSymbols() {\n  const symbols = [&apos;BTCUSDT&apos;, &apos;ETHUSDT&apos;, &apos;BNBUSDT&apos;, &apos;SOLUSDT&apos;, &apos;XRPUSDT&apos;];\n  const semaphore = { count: 0 };\n\n  const tasks = symbols.map(async (symbol) =&gt; {\n    while (semaphore.count &gt;= MAX_CONCURRENT) {\n      await new Promise(r =&gt; setTimeout(r, 50));\n    }\n    semaphore.count++;\n\n    try {\n      const data = await fetchBinance(&apos;\u002Fapi\u002Fv3\u002Fticker\u002Fprice&apos;, { symbol });\n      console.log(`${symbol}: $${data.price}`);\n      return data;\n    } finally {\n      semaphore.count--;\n    }\n  });\n\n  return Promise.all(tasks);\n}\n\nscrapeMultipleSymbols().catch(console.error);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>curl : test rapide d'un endpoint via ProxyHat\u003C\u002Fh2>\n\u003Cp>Pour valider votre configuration proxy avant de lancer un script complet, un simple \u003Ccode>curl\u003C\u002Fcode> suffit.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># Vérifier le prix BTCUSDT via un proxy résidentiel US\ncurl -x &quot;http:\u002F\u002Fuser-country-US:PASSWORD@gate.proxyhat.com:8080&quot; \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fticker\u002Fprice?symbol=BTCUSDT&quot; \\\n  -D -\n\n# L&apos;option -D - affiche les en-têtes, dont X-MBX-USED-WEIGHT-1M\n\n# Récupérer l&apos;order book avec limit=100\ncurl -x &quot;http:\u002F\u002FUSERNAME:PASSWORD@gate.proxyhat.com:8080&quot; \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fdepth?symbol=BTCUSDT&amp;limit=100&quot; \\\n  -H &quot;Accept: application\u002Fjson&quot;\n\n# Via SOCKS5\ncurl -x &quot;socks5:\u002F\u002FUSERNAME:PASSWORD@gate.proxyhat.com:1080&quot; \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fklines?symbol=ETHUSDT&amp;interval=1m&amp;limit=10&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Quand préférer les WebSockets au REST polling\u003C\u002Fh2>\n\u003Cp>Binance propose des flux WebSocket publics (\u003Ccode>wss:\u002F\u002Fstream.binance.com:9443\u002Fws\u003C\u002Fcode>) pour les bougies (\u003Ccode>kline\u003C\u002Fcode>), l'order book (\u003Ccode>depth\u003C\u002Fcode>), et les trades en temps réel. Pour des cas d'usage en temps réel, les WebSockets sont nettement supérieurs au polling REST :\u003C\u002Fp>\n\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>Critère\u003C\u002Fth>\u003Cth>REST polling\u003C\u002Fth>\u003Cth>WebSocket streams\u003C\u002Fth>\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>Latence\u003C\u002Ftd>\u003Ctd>200–500 ms par requête\u003C\u002Ftd>\u003Ctd>&lt; 100 ms (push)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Coût en poids\u003C\u002Ftd>\u003Ctd>Consomme le budget 6000\u002Fmin\u003C\u002Ftd>\u003Ctd>0 poids (hors limite REST)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Backfill historique\u003C\u002Ftd>\u003Ctd>Idéal (pagination startTime\u002FendTime)\u003C\u002Ftd>\u003Ctd>Impossible (temps réel uniquement)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Connexions simultanées\u003C\u002Ftd>\u003Ctd>Limitées par le budget poids\u003C\u002Ftd>\u003Ctd>Max 5 connexions par IP, 1024 streams\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Fiabilité réseau\u003C\u002Ftd>\u003Ctd>Requêtes indépendantes\u003C\u002Ftd>\u003Ctd>Reconnexion nécessaire si coupure\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Cp>Règle pratique : utilisez le REST pour le backfill historique et les snapshots d'order book, et les WebSockets pour le suivi en temps réel. Pour le \u003Ca href=\"\u002Ffr\u002Fuse-cases\u002Fserp-tracking\">suivi de données en continu\u003C\u002Fa>, combinez les deux : un snapshot REST initial puis un flux WebSocket pour les mises à jour incrémentales.\u003C\u002Fp>\n\n\u003Ch2>Erreurs courantes et edge cases\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Ignorer X-MBX-USED-WEIGHT-1M — c'est la seule façon de savoir où vous en êtes dans le budget. Loggez-le systématiquement.\u003C\u002Fli>\n\u003Cli>Poller \u002Fapi\u002Fv3\u002Fdepth avec limit=1000 en continu — 20 poids par appel = budget épuisé en 300 appels. Utilisez limit=100 (5 poids) ou passez aux WebSockets.\u003C\u002Fli>\n\u003Cli>Pas de rotation d'IP — un seul proxy datacenter en IP fixe sera banni en minutes si le volume est élevé.\u003C\u002Fli>\n\u003Cli>Oublier le Retry-After sur 429 — continuer à envoyer des requêtes pendant un 429 accélère le passage au 418.\u003C\u002Fli>\n\u003Cli>Mélanger Binance.com et Binance.US sans géo-ciblage — un proxy EU sur Binance.US renverra 451 ; un proxy US sur Binance.com aussi.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Concurrency non contrôlée\u003C\u002Fstrong> — lancer 50 requêtes parallèles sans semaphore peut saturer le proxy et déclencher des timeouts côté Binance.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Configuration ProxyHat et liens utiles\u003C\u002Fh2>\n\u003Cp>Pour configurer vos proxies ProxyHat, connectez-vous au \u003Ca href=\"https:\u002F\u002Fdashboard.proxyhat.com\u002F\">dashboard\u003C\u002Fa> et récupérez vos identifiants. Consultez la \u003Ca href=\"\u002Ffr\u002Fpricing\">tarification\u003C\u002Fa> pour choisir le plan adapté à votre volume, et la \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">documentation officielle\u003C\u002Fa> pour les détails techniques du SDK.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"\u002Ffr\u002Fpricing\">Tarification ProxyHat\u003C\u002Fa> — plans résidentiels, datacenter et mobile\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Ffr\u002Fuse-cases\u002Fweb-scraping\">Cas d'usage : web scraping\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Ffr\u002Fuse-cases\u002Fserp-tracking\">Cas d'usage : SERP tracking\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Ffr\u002Flocations\">Localisations disponibles\u003C\u002Fa> — 190+ pays pour le géo-ciblage\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>Points clés à retenir\u003C\u002Fh2>\n\u003Cblockquote>\n\u003Cul>\n\u003Cli>Surveillez X-MBX-USED-WEIGHT-1M — c'est votre jauge de consommation. Budget : ~6000 poids\u002Fmin\u002FIP.\u003C\u002Fli>\n\u003Cli>Rottez vos IP via \u003Ccode>gate.proxyhat.com:8080\u003C\u002Fcode> (HTTP) ou \u003Ccode>:1080\u003C\u002Fcode> (SOCKS5) pour répartir le poids.\u003C\u002Fli>\n\u003Cli>Utilisez des sessions collantes (\u003Ccode>-sid-abc123\u003C\u002Fcode>) pour le backfill paginé de klines.\u003C\u002Fli>\n\u003Cli>Gérez 429 et 418 avec Retry-After et backoff exponentiel — ne jamais ignorer ces codes.\u003C\u002Fli>\n\u003Cli>Préférez les WebSockets pour le temps réel ; le REST reste roi pour le backfill historique.\u003C\u002Fli>\n\u003Cli>Respectez les ToS de Binance — données publiques uniquement, ne scrapez pas de endpoints authentifiés.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fblockquote>","Limites de poids des API crypto et proxies (Binance) | ProxyHat","Guide développeur pour scraper l'API REST de Binance avec des proxies rotatifs. Endpoints, poids, rate limiting, code Python\u002FNode.js et meilleures pratiques.","\u002Ffr\u002Fblog\u002Fcomment-scraper-api-rest-binance-proxies",null,"Données de marché crypto : limites de poids et proxies | ProxyHat","Guide développeur pour scraper l'API REST de Binance avec des proxies rotatifs. Endpoints, poids, rate limiting, code Python\u002FNode.js inclus.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fcomment-scraper-api-rest-binance-proxies-og.webp",[19,22,25],{"question":20,"answer":21},"Pourquoi utiliser des proxies pour scraper l'API Binance ?","Binance limite les requêtes par adresse IP avec un système de poids. Sans rotation, un polling intensif épuise le budget en quelques minutes, déclenchant des HTTP 429 puis des bannissements temporaires (HTTP 418). Les proxies résidentiels rotatifs répartissent le poids sur des dizaines d'IP, multipliant le budget effectif et contournant les blocages géographiques (HTTP 451).",{"question":23,"answer":24},"Comment éviter les blocages quand on scrape l'API Binance ?","Surveillez l'en-tête X-MBX-USED-WEIGHT-1M, implémentez un backoff exponentiel sur HTTP 429, respectez l'en-tête Retry-After, rottez vos IP via ProxyHat, et limitez la profondeur de l'order book. Pour le temps réel, basculez sur les WebSockets qui ne consomment pas de poids REST. Ne dépassez jamais 80% du budget avant de marquer une pause.",{"question":26,"answer":27},"Faut-il utiliser Binance.com ou Binance.US avec des proxies ?","Cela dépend de votre juridiction. Binance.com bloque les IP américaines (HTTP 451), tandis que Binance.US est destiné au marché US. Avec ProxyHat, utilisez le flag -country-US pour cibler des IP américaines vers Binance.US, ou un autre pays pour Binance.com. Vérifiez toujours les Terms of Service de chaque plateforme.",false,"2026-08-03T10:04:04+00:00","2026-10-04T01:29:50+00:00","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fcomment-scraper-api-rest-binance-proxies-master.webp","How to Scrape the Binance REST API with Proxies: A Developer Guide","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fcomment-scraper-api-rest-binance-proxies-card.webp",12,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},"ProxyHat Team","proxyhat-team","The ProxyHat editorial team covers proxies, web scraping, and data extraction.",[40],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},4,"guides-developpeurs","Guides Développeurs","Guides Développeurs | Blog ProxyHat","Tutoriels de code et guides SDK pour intégrer des proxies dans vos applications.",[],{"fr":13,"pt":48,"ko":49,"ru":50,"en":51,"zh":52,"x-default":51},"\u002Fpt\u002Fblog\u002Fcomo-raspar-api-binance-proxies","\u002Fko\u002Fblog\u002Fbinance-rest-api-proxy-scraping","\u002Fru\u002Fblog\u002Fkak-skrejpit-binance-rest-api-proksi","\u002Fblog\u002Fscrape-binance-rest-api-proxies","\u002Fcn\u002Fblog\u002Fbinance-rest-api-proxy-scraping-guide",{"tr":54,"fr":13,"ja":55,"pt":48,"ko":49,"pl":56,"es":57,"ru":50,"en":51,"zh":52,"it":58,"de":59},"\u002Ftr\u002Fblog\u002Fbinance-rest-api-proxy-tarama","\u002Fja\u002Fblog\u002Fbinance-api-scraping-proxy","\u002Fpl\u002Fblog\u002Fjak-scrapowac-rest-api-binance-proxy","\u002Fes\u002Fblog\u002Fscrapear-api-binance-proxies","\u002Fit\u002Fblog\u002Fscraping-binance-rest-api-con-proxy","\u002Fde\u002Fblog\u002Fbinance-rest-api-mit-proxies-scrapen",81,[62,78,94,110],{"id":63,"slug":64,"title":65,"excerpt":66,"featured_image_url":67,"featured_image_alt":68,"card_image_url":69,"og_image_url":70,"published_at":71,"updated_at":71,"content_updated_at":72,"reading_time_minutes":34,"is_featured":28,"indexable":4,"views":73,"author":74,"categories":75,"tags":77},176,"got-scraping-nodejs-proxy-residentiel-1","Guide got-scraping avec Node.js : proxies résidentiels et header generator","Apprenez à utiliser got-scraping avec Node.js pour des requêtes HTTP qui ressemblent à un vrai navigateur, avec rotation de proxies résidentiels ProxyHat, hooks de retry et patterns de production.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fgot-scraping-nodejs-proxy-residentiel-1-master.webp","got-scraping in Node.js: A Developer's Guide with Residential Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fgot-scraping-nodejs-proxy-residentiel-1-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fgot-scraping-nodejs-proxy-residentiel-1-og.webp","2026-08-04T16:05:06+00:00","2026-10-03T08:29:58+00:00",121,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[76],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],{"id":79,"slug":80,"title":81,"excerpt":82,"featured_image_url":83,"featured_image_alt":84,"card_image_url":85,"og_image_url":86,"published_at":87,"updated_at":87,"content_updated_at":88,"reading_time_minutes":34,"is_featured":28,"indexable":28,"views":89,"author":90,"categories":91,"tags":93},175,"rotation-proxies-colly-golang-1","Rotation de proxies dans Colly : guide complet pour le web scraping en Go","Apprenez à implémenter une rotation de proxies dans Colly avec des proxies résidentiels ProxyHat. Couvre proxy.RoundRobinProxySwitcher, SetProxyFunc, sessions collantes, et patterns de production pour le scraping à grande échelle.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Frotation-proxies-colly-golang-1-master.webp","Rotating Proxies in Colly: A Framework-Idiomatic Guide for Go Developers","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Frotation-proxies-colly-golang-1-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Frotation-proxies-colly-golang-1-og.webp","2026-08-04T10:05:34+00:00","2026-10-03T23:53:00+00:00",71,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[92],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],{"id":95,"slug":96,"title":97,"excerpt":98,"featured_image_url":99,"featured_image_alt":100,"card_image_url":101,"og_image_url":102,"published_at":103,"updated_at":103,"content_updated_at":104,"reading_time_minutes":34,"is_featured":28,"indexable":4,"views":105,"author":106,"categories":107,"tags":109},195,"scraper-api-bybit-v5-proxys-rotatifs","Collecter des données de marché crypto avec des proxys rotatifs : rate limits, géoblocages et pagination (exemple Bybit V5)","Guide développeur pour scraper les endpoints \u002Fv5\u002Fmarket\u002F de Bybit avec proxys rotatifs : orderbook, tickers, kline. Code Node.js et Python, gestion des rate limits et sessions sticky.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fscraper-api-bybit-v5-proxys-rotatifs-master.webp","How to Scrape the Bybit V5 Market API with Rotating Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fscraper-api-bybit-v5-proxys-rotatifs-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Fscraper-api-bybit-v5-proxys-rotatifs-og.webp","2026-08-03T16:09:16+00:00","2026-10-04T01:29:51+00:00",86,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[108],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],{"id":111,"slug":112,"title":113,"excerpt":114,"featured_image_url":115,"featured_image_alt":116,"card_image_url":117,"og_image_url":118,"published_at":119,"updated_at":119,"content_updated_at":120,"reading_time_minutes":34,"is_featured":28,"indexable":28,"views":121,"author":122,"categories":123,"tags":125},172,"utiliser-proxy-swift-urlsession","Utiliser un proxy en Swift avec URLSession : guide développeur iOS et macOS","Guide pratique pour configurer des proxies résidentiels, datacenter et SOCKS5 dans URLSession sur iOS et macOS, avec authentification, géo-ciblage, async\u002Fawait et bonnes pratiques de production.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Futiliser-proxy-swift-urlsession-master.webp","Using Proxies in Swift: A Code-First Guide to URLSession, SOCKS5 & Residential IPs","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Futiliser-proxy-swift-urlsession-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Ffr\u002Futiliser-proxy-swift-urlsession-og.webp","2026-07-26T16:03:44+00:00","2026-10-03T08:57:48+00:00",230,{"name":36,"slug":37,"bio":38,"avatar_url":14,"website_url":14,"social_links":14},[124],{"id":41,"slug":42,"name":43,"description":14,"meta_title":44,"meta_description":45,"parent_id":14},[],[]]