[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-pl-jak-scrapowac-rest-api-binance-proxy":3},{"success":4,"payload":5,"related":59,"errors":123},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":11,"og_description":12,"og_image_url":15,"faq_json":16,"key_takeaways":14,"allow_index":26,"noindex_google_only":26,"allow_follow":4,"published_at":27,"updated_at":27,"content_updated_at":28,"featured_image_url":29,"featured_image_alt":30,"card_image_url":31,"reading_time_minutes":32,"author":33,"categories":37,"tags":44,"alternates":45,"locale_paths":52,"views":58},194,"jak-scrapowac-rest-api-binance-proxy","Jak scrapować REST API Binance z proxy — przewodnik dla programistów","Kompletny przewodnik po pobieraniu publicznych danych rynkowych z REST API Binance z wykorzystaniem rotacyjnych proxy. Przykłady kodu w Python i Node.js, limit wag, sesje sticky i strategie omijania blokad IP.","\u003Ch2>Jak scrapować REST API Binance z proxy — wprowadzenie\u003C\u002Fh2>\n\u003Cp>Binance udostępnia publiczne endpointy REST API do pobierania danych rynkowych w czasie rzeczywistym — świece (klines), księga zleceń (depth) i tickery. Dla quant-developerów i inżynierów danych kryptowalutowych te endpointy to podstawowe źródło do budowy historycznych zbiorów cen i orderbooków. Problem pojawia się przy skalowaniu: Binance stosuje limit oparty na \u003Cstrong>wadze\u003C\u002Fstrong> (weight) na adres IP — około 6000 wag\u002Fmin — a jego przekroczenie prowadzi do błędów 429, a następnie do banów IP (HTTP 418). W tym przewodniku pokazujemy, jak scrapować REST API Binance z proxy, rozpraszając wagę na wiele adresów IP przy użyciu \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">ProxyHat\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Cblockquote>\u003Cstrong>Ważne o zgodności:\u003C\u002Fstrong> Ten artykuł dotyczy wyłącznie \u003Cem>publicznych\u003C\u002Fem> danych rynkowych z publicznych endpointów Binance. Przestrzegaj \u003Ca href=\"https:\u002F\u002Fwww.binance.com\u002Fen\u002Fterms\" rel=\"noopener noreferrer\">warunków korzystania z Binance\u003C\u002Fa> oraz dokumentacji API. Preferuj oficjalny dostęp API, gdy wymaga tego umowa. Nie pobieraj danych prywatnych ani nie obchodź mechanizmów autoryzacji.\u003C\u002Fp>\u003C\u002Fblockquote>\n\n\u003Ch2>Architektura limitów wagowych Binance — dlaczego problem w ogóle istnieje\u003C\u002Fh2>\n\u003Cp>Binance nie ogranicza liczby żądań, ale \u003Cstrong>sumy wag\u003C\u002Fstrong> przypisanych do endpointów. Każde żądanie zużywa określoną wagę z budżetu IP. Gdy budżet zostanie wyczerpany, serwer zwraca \u003Ccode>429 Too Many Requests\u003C\u002Fcode>. Kontynuowanie żądań po 429 prowadzi do tymczasowego bana — \u003Ccode>418\u003C\u002Fcode> — z nagłówkiem \u003Ccode>Retry-After\u003C\u002Fcode> określającym czas trwania bana.\u003C\u002Fp>\n\u003Cp>Budżet wynosi około \u003Cstrong>6000 wag na minutę\u003C\u002Fstrong> na adres IP. Kluczowy nagłówek odpowiedzi to \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode>, który informuje o aktualnie zużytej wadze w ostatnich 60 sekundach. Monitorowanie tego nagłówka to podstawa skutecznego throttlingu.\u003C\u002Fp>\n\n\u003Ch3>Mapa kluczowych endpointów publicznych\u003C\u002Fh3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>Endpoint\u003C\u002Fth>\u003Cth>Opis\u003C\u002Fth>\u003Cth>Waga (domyślna)\u003C\u002Fth>\u003Cth>Kluczowe parametry\u003C\u002Fth>\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>\u003Ccode>GET \u002Fapi\u002Fv3\u002Fklines\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Świece OHLCV\u003C\u002Ftd>\u003Ctd>1–2 (zależnie od limit)\u003C\u002Ftd>\u003Ctd>symbol, interval, limit (max 1000)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>\u003Ccode>GET \u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Księga zleceń\u003C\u002Ftd>\u003Ctd>5–20 (zależnie od limit: 5, 10, 20, 50, 100, 500, 1000)\u003C\u002Ftd>\u003Ctd>symbol, limit\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>\u003Ccode>GET \u002Fapi\u002Fv3\u002Fticker\u002F24hr\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Statystyki 24h\u003C\u002Ftd>\u003Ctd>1 (pojedynczy symbol), 40 (wszystkie)\u003C\u002Ftd>\u003Ctd>symbol (opcjonalny)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>\u003Ccode>GET \u002Fapi\u002Fv3\u002Fticker\u002Fprice\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Aktualna cena\u003C\u002Ftd>\u003Ctd>1 (pojedyńczy), 2 (wszystkie)\u003C\u002Ftd>\u003Ctd>symbol (opcjonalny)\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Cp>Dlaczego \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode> z wysokim limitem wyczerpuje budżet w minuty? Przy limicie \u003Ccode>1000\u003C\u002Fcode> waga wynosi 20. Polling co 1 sekundę = 20 wag\u002Fs = 1200 wag\u002Fmin — to 20% budżetu na jeden symbol. Przy 10 parach i pollingu co 500 ms zużywasz \u003Cstrong>2400 wag\u002Fs\u003C\u002Fstrong>, czyli budżet 6000 znika w ~2,5 sekundy. Bez rotacji IP jest to niepraktyczne.\u003C\u002Fp>\n\n\u003Ch2>Geo-split Binance.com vs Binance.US i HTTP 451\u003C\u002Fh2>\n\u003Cp>Binance operuje osobnymi domenami dla różnych jurysdykcji. Użytkownicy z USA próbujący dostać się do \u003Ccode>api.binance.com\u003C\u002Fcode> mogą otrzymać \u003Ccode>451 Unavailable For Legal Reasons\u003C\u002Fcode>. Rotacyjne proxy residential z geo-targetingiem \u003Ccode>-country-US\u003C\u002Fcode> pozwalają na dostęp z amerykańskich adresów IP, ale należy pamiętać, że \u003Ccode>api.binance.us\u003C\u002Fcode> to osobne API z własnymi limitami. Używaj geo-targetowania zgodnie z obowiązującymi przepisami.\u003C\u002Fp>\n\n\u003Ch2>Konfiguracja ProxyHat — rotacja IP i sesje sticky\u003C\u002Fh2>\n\u003Cp>ProxyHat oferuje rotacyjne proxy residential przez bramkę \u003Ccode>gate.proxyhat.com\u003C\u002Fcode>. HTTP działa na porcie \u003Ccode>8080\u003C\u002Fcode>, SOCKS5 na \u003Ccode>1080\u003C\u002Fcode>. Parametry geo-targeting i sesji przekazywane są w nazwie użytkownika:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Rotacja per-request: \u003Ccode>http:\u002F\u002Fuser:pass@gate.proxyhat.com:8080\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>Geo-targeting US: \u003Ccode>http:\u002F\u002Fuser-country-US:pass@gate.proxyhat.com:8080\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>Sesja sticky: \u003Ccode>http:\u002F\u002Fuser-sid-abc123:pass@gate.proxyhat.com:8080\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>Geo + miasto: \u003Ccode>http:\u002F\u002Fuser-country-DE-region-state_of_berlin-city-berlin:pass@gate.proxyhat.com:8080\u003C\u002Fcode>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Sprawdź dostępne lokalizacje na stronie \u003Ca href=\"\u002Fpl\u002Flocations\">\u002Fpl\u002Flocations\u003C\u002Fa> oraz cennik na \u003Ca href=\"\u002Fpl\u002Fpricing\">\u002Fpl\u002Fpricing\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch2>Przykład 1: Python requests — rotacja IP per-request (surowe proxy)\u003C\u002Fh2>\n\u003Cp>Poniższy przykład pobiera świece z \u003Ccode>\u002Fapi\u002Fv3\u002Fklines\u003C\u002Fcode>, rotując IP przy każdym żądaniu. Zawiera obsługę nagłówka \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode>, exponential backoff przy 429 i circuit breaker przy 418.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import requests\nimport time\nimport random\nimport logging\nfrom typing import Optional\n\nlogging.basicConfig(level=logging.INFO, format=&quot;%(asctime)s [%(levelname)s] %(message)s&quot;)\nlogger = logging.getLogger(&quot;binance-scraper&quot;)\n\nPROXY_URL = &quot;http:\u002F\u002Fuser:pass@gate.proxyhat.com:8080&quot;\nBASE_URL = &quot;https:\u002F\u002Fapi.binance.com&quot;\n\ndef fetch_klines(symbol: str, interval: str = &quot;1m&quot;, limit: int = 1000,\n                 max_retries: int = 5) -&gt; Optional[list]:\n    &quot;&quot;&quot;Pobiera klines z rotacją IP i weight-aware throttling.&quot;&quot;&quot;\n    url = f&quot;{BASE_URL}\u002Fapi\u002Fv3\u002Fklines&quot;\n    params = {&quot;symbol&quot;: symbol, &quot;interval&quot;: interval, &quot;limit&quot;: limit}\n    proxies = {&quot;http&quot;: PROXY_URL, &quot;https&quot;: PROXY_URL}\n\n    for attempt in range(max_retries):\n        try:\n            resp = requests.get(url, params=params, proxies=proxies, timeout=15)\n\n            # Monitoruj zużytą wagę\n            used_weight = int(resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, 0))\n            logger.info(f&quot;{symbol} attempt={attempt} weight={used_weight} status={resp.status_code}&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 received, sleeping {retry_after}s&quot;)\n                time.sleep(retry_after + random.uniform(0.5, 1.5))\n                continue\n\n            if resp.status_code == 418:\n                logger.error(&quot;IP banned (418). Rotating to next IP...&quot;)\n                time.sleep(60 + random.uniform(10, 30))\n                continue\n\n            resp.raise_for_status()\n\n            # Proactive throttle: jeśli waga &gt; 5000, odczekaj\n            if used_weight &gt; 5000:\n                sleep_time = (used_weight - 5000) \u002F 100  # ~0.1s per 100 wagi powyżej 5000\n                time.sleep(sleep_time)\n\n            return resp.json()\n\n        except requests.RequestException as e:\n            backoff = (2 ** attempt) + random.uniform(0, 1)\n            logger.warning(f&quot;Request error: {e}, backing off {backoff:.1f}s&quot;)\n            time.sleep(backoff)\n\n    return None\n\n# Pobierz 1000 świec 1m dla BTCUSDT\ndata = fetch_klines(&quot;BTCUSDT&quot;, &quot;1m&quot;, 1000)\nif data:\n    print(f&quot;Pobrano {len(data)} świec&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Przykład 2: ProxyHat SDK — rotacja IP per-request\u003C\u002Fh2>\n\u003Cp>ProxyHat SDK upraszcza zarządzanie proxy, automatyzując rotację i ponowne próby. Poniżej to samo zadanie co w Przykładzie 1, ale z użyciem SDK:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>from proxyhat import ProxyHatClient\nimport logging\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(&quot;proxyhat-binance&quot;)\n\n# Inicjalizacja klienta ProxyHat\nclient = ProxyHatClient(\n    host=&quot;gate.proxyhat.com&quot;,\n    port=8080,\n    username=&quot;user&quot;,\n    password=&quot;pass&quot;,\n    rotate_every_request=True,  # rotacja IP przy każdym żądaniu\n)\n\nBASE_URL = &quot;https:\u002F\u002Fapi.binance.com&quot;\n\ndef fetch_klines_sdk(symbol: str, interval: str = &quot;1m&quot;, limit: int = 1000) -&gt; list:\n    &quot;&quot;&quot;Pobiera klines używając ProxyHat SDK z automatyczną rotacją IP.&quot;&quot;&quot;\n    url = f&quot;{BASE_URL}\u002Fapi\u002Fv3\u002Fklines&quot;\n    params = {&quot;symbol&quot;: symbol, &quot;interval&quot;: interval, &quot;limit&quot;: limit}\n\n    response = client.get(url, params=params, timeout=15)\n\n    used_weight = int(response.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, 0))\n    logger.info(f&quot;{symbol} weight={used_weight} status={response.status_code}&quot;)\n\n    if response.status_code == 429:\n        retry_after = int(response.headers.get(&quot;Retry-After&quot;, 5))\n        logger.warning(f&quot;Rate limited, retrying after {retry_after}s&quot;)\n        return client.get_with_retry(url, params=params, retries=3,\n                                     backoff_base=retry_after)\n\n    response.raise_for_status()\n    return response.json()\n\n# Backfill wielu par\nsymbols = [&quot;BTCUSDT&quot;, &quot;ETHUSDT&quot;, &quot;BNBUSDT&quot;, &quot;SOLUSDT&quot;, &quot;XRPUSDT&quot;]\nfor sym in symbols:\n    klines = fetch_klines_sdk(sym, &quot;1m&quot;, 1000)\n    logger.info(f&quot;{sym}: {len(klines)} świec&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Przykład 3: Sticky session — paginated klines backfill\u003C\u002Fh2>\n\u003Cp>Backfill historycznych danych wymaga wielu stronicowanych żądań. Sticky session utrzymuje ten sam IP dla całej paginacji, co zapobiega rotacji w środku sekwencji i zmniejsza ryzyko 429 na pojedynczym IP.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import requests\nimport time\nimport logging\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(&quot;klines-backfill&quot;)\n\nBASE_URL = &quot;https:\u002F\u002Fapi.binance.com&quot;\nSESSION_ID = &quot;backfill-btc-001&quot;\n\n# Sticky session — ten sam IP przez całą sekwencję\nPROXY_URL = f&quot;http:\u002F\u002Fuser-sid-{SESSION_ID}:pass@gate.proxyhat.com:8080&quot;\nproxies = {&quot;http&quot;: PROXY_URL, &quot;https&quot;: PROXY_URL}\n\ndef backfill_klines(symbol: str, interval: str, start_time_ms: int,\n                    end_time_ms: int, max_calls: int = 1000) -&gt; list:\n    &quot;&quot;&quot;Paginated backfill klines używając sticky session.&quot;&quot;&quot;\n    all_klines = []\n    current_start = start_time_ms\n    calls = 0\n\n    while current_start &lt; end_time_ms and calls &lt; max_calls:\n        params = {\n            &quot;symbol&quot;: symbol,\n            &quot;interval&quot;: interval,\n            &quot;startTime&quot;: current_start,\n            &quot;endTime&quot;: end_time_ms,\n            &quot;limit&quot;: 1000,\n        }\n\n        resp = requests.get(f&quot;{BASE_URL}\u002Fapi\u002Fv3\u002Fklines&quot;, params=params,\n                            proxies=proxies, timeout=15)\n        used_weight = int(resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, 0))\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 at call {calls}, sleeping {retry_after}s&quot;)\n            time.sleep(retry_after + 1)\n            continue\n\n        if resp.status_code != 200:\n            logger.error(f&quot;HTTP {resp.status_code}: {resp.text[:200]}&quot;)\n            time.sleep(2)\n            continue\n\n        batch = resp.json()\n        if not batch:\n            break\n\n        all_klines.extend(batch)\n        # Następny start = timestamp ostatniej świecy + 1ms\n        current_start = batch[-1][0] + 1\n        calls += 1\n\n        # Weight-aware throttle\n        if used_weight &gt; 4500:\n            sleep_sec = max(1, (used_weight - 4500) \u002F 200)\n            logger.info(f&quot;Weight {used_weight}, throttling {sleep_sec:.1f}s&quot;)\n            time.sleep(sleep_sec)\n        else:\n            time.sleep(0.1)  # minimalny delay\n\n        if calls % 50 == 0:\n            logger.info(f&quot;{symbol}: {len(all_klines)} klines, calls={calls}&quot;)\n\n    return all_klines\n\n# Backfill 30 dni BTCUSDT 1m\nimport datetime\nend_ms = int(datetime.datetime(2024, 1, 1).timestamp() * 1000)\nstart_ms = int(datetime.datetime(2023, 12, 1).timestamp() * 1000)\n\nklines = backfill_klines(&quot;BTCUSDT&quot;, &quot;1m&quot;, start_ms, end_ms)\nprint(f&quot;Łącznie pobrano: {len(klines)} świec&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Przykład 4: Python httpx — concurrency z async i rotacją IP\u003C\u002Fh2>\n\u003Cp>Dla pobierania wielu par jednocześnie, httpx z async pozwala na kontrolowaną współbieżność z osobnym limiterem:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import httpx\nimport asyncio\nimport logging\nfrom typing import Optional\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(&quot;async-binance&quot;)\n\nBASE_URL = &quot;https:\u002F\u002Fapi.binance.com&quot;\nPROXY_URL = &quot;http:\u002F\u002Fuser:pass@gate.proxyhat.com:8080&quot;\n\n# Limit współbieżności — nie więcej niż 10 jednoczesnych żądań\nsemaphore = asyncio.Semaphore(10)\n\nclass WeightTracker:\n    &quot;&quot;&quot;Śledzi zużycie wagi w oknie 1-minutowym.&quot;&quot;&quot;\n    def __init__(self, max_weight: int = 5500):\n        self.max_weight = max_weight\n        self.current_weight = 0\n\n    async def check_and_wait(self, client: httpx.AsyncClient):\n        if self.current_weight &gt;= self.max_weight:\n            wait = 60  # odczekaj pełne okno\n            logger.info(f&quot;Weight {self.current_weight}, waiting {wait}s&quot;)\n            await asyncio.sleep(wait)\n            self.current_weight = 0\n\n    def update(self, weight_header: str):\n        if weight_header:\n            self.current_weight = int(weight_header)\n\nweight_tracker = WeightTracker(max_weight=5500)\n\nasync def fetch_ticker(client: httpx.AsyncClient, symbol: str) -&gt; Optional[dict]:\n    async with semaphore:\n        await weight_tracker.check_and_wait(client)\n\n        url = f&quot;{BASE_URL}\u002Fapi\u002Fv3\u002Fticker\u002F24hr&quot;\n        params = {&quot;symbol&quot;: symbol}\n\n        try:\n            resp = await client.get(url, params=params, timeout=15)\n            weight_tracker.update(resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&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;{symbol}: 429, sleeping {retry_after}s&quot;)\n                await asyncio.sleep(retry_after)\n                return None\n\n            resp.raise_for_status()\n            data = resp.json()\n            logger.info(f&quot;{symbol}: price={data[&apos;lastPrice&apos;]} weight={weight_tracker.current_weight}&quot;)\n            return data\n\n        except Exception as e:\n            logger.error(f&quot;{symbol}: {e}&quot;)\n            return None\n\nasync def main():\n    symbols = [&quot;BTCUSDT&quot;, &quot;ETHUSDT&quot;, &quot;BNBUSDT&quot;, &quot;SOLUSDT&quot;, &quot;XRPUSDT&quot;,\n               &quot;ADAUSDT&quot;, &quot;DOGEUSDT&quot;, &quot;AVAXUSDT&quot;, &quot;LINKUSDT&quot;, &quot;DOTUSDT&quot;]\n\n    async with httpx.AsyncClient(\n        proxy=PROXY_URL,\n        limits=httpx.Limits(max_connections=20, max_keepalive_connections=10)\n    ) as client:\n        tasks = [fetch_ticker(client, sym) for sym in symbols]\n        results = await asyncio.gather(*tasks, return_exceptions=True)\n\n    successful = [r for r in results if r is not None and isinstance(r, dict)]\n    print(f&quot;Pobrano {len(successful)}\u002F{len(symbols)} tickerów&quot;)\n\nasyncio.run(main())\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Przykład 5: Node.js axios — rotacja IP i exponential backoff\u003C\u002Fh2>\n\u003Cp>Dla ekosystemu JavaScript\u002FTypeScript, poniższy przykład używa axios z HttpsProxyAgent i implementuje exponential backoff:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>const axios = require(&apos;axios&apos;);\nconst { HttpsProxyAgent } = require(&apos;https-proxy-agent&apos;);\nconst pLimit = require(&apos;p-limit&apos;);\n\nconst PROXY_URL = &apos;http:\u002F\u002Fuser:pass@gate.proxyhat.com:8080&apos;;\nconst BASE_URL = &apos;https:\u002F\u002Fapi.binance.com&apos;;\nconst proxyAgent = new HttpsProxyAgent(PROXY_URL);\n\n\u002F\u002F Limit współbieżności: max 5 jednoczesnych\nconst limit = pLimit(5);\n\n\u002F\u002F Weight tracker\nlet currentWeight = 0;\n\nasync function fetchDepth(symbol, limitParam = 100) {\n  const url = `${BASE_URL}\u002Fapi\u002Fv3\u002Fdepth`;\n  const params = { symbol, limit: limitParam };\n\n  for (let attempt = 0; attempt &lt; 5; attempt++) {\n    try {\n      const resp = await axios.get(url, {\n        params,\n        httpsAgent: proxyAgent,\n        timeout: 15000,\n        headers: { &apos;User-Agent&apos;: &apos;MarketDataBot\u002F1.0&apos; },\n      });\n\n      currentWeight = parseInt(resp.headers[&apos;x-mbx-used-weight-1m&apos;] || &apos;0&apos;, 10);\n      console.log(`${symbol} weight=${currentWeight} status=${resp.status}`);\n\n      \u002F\u002F Proactive throttle\n      if (currentWeight &gt; 5000) {\n        const sleepMs = Math.max(1000, (currentWeight - 5000) * 10);\n        console.log(`Throttling ${sleepMs}ms`);\n        await new Promise(r =&gt; setTimeout(r, sleepMs));\n      }\n\n      return resp.data;\n    } catch (err) {\n      if (err.response) {\n        const status = err.response.status;\n        const retryAfter = err.response.headers[&apos;retry-after&apos;];\n\n        if (status === 429) {\n          const wait = (parseInt(retryAfter || &apos;5&apos;, 10)) * 1000;\n          console.warn(`${symbol}: 429, waiting ${wait}ms`);\n          await new Promise(r =&gt; setTimeout(r, wait + 500));\n          continue;\n        }\n\n        if (status === 418) {\n          console.error(`${symbol}: IP banned (418). Waiting 120s.`);\n          await new Promise(r =&gt; setTimeout(r, 120000));\n          continue;\n        }\n      }\n\n      \u002F\u002F Exponential backoff\n      const backoff = Math.pow(2, attempt) * 1000 + Math.random() * 500;\n      console.warn(`${symbol}: attempt ${attempt}, backoff ${backoff}ms, error: ${err.message}`);\n      await new Promise(r =&gt; setTimeout(r, backoff));\n    }\n  }\n  return null;\n}\n\nasync function main() {\n  const symbols = [&apos;BTCUSDT&apos;, &apos;ETHUSDT&apos;, &apos;BNBUSDT&apos;, &apos;SOLUSDT&apos;, &apos;XRPUSDT&apos;];\n\n  const tasks = symbols.map(sym =&gt;\n    limit(() =&gt; fetchDepth(sym, 100))\n  );\n\n  const results = await Promise.allSettled(tasks);\n  const successful = results.filter(r =&gt; r.status === &apos;fulfilled&apos; &amp;&amp; r.value !== null);\n  console.log(`Pobrano ${successful.length}\u002F${symbols.length} orderbooków`);\n}\n\nmain().catch(console.error);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Przykład 6: curl — szybkie testowanie proxy\u003C\u002Fh2>\n\u003Cp>Najprostszy sposób na weryfikację działania proxy:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># Test połączenia przez proxy HTTP\n\ncurl -x http:\u002F\u002Fuser:pass@gate.proxyhat.com:8080 \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fticker\u002Fprice?symbol=BTCUSDT&quot; \\\n  -H &quot;Accept: application\u002Fjson&quot; \\\n  -D -\n\n# Test geo-targeting US\ncurl -x http:\u002F\u002Fuser-country-US:pass@gate.proxyhat.com:8080 \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fticker\u002Fprice?symbol=BTCUSDT&quot;\n\n# Test SOCKS5\ncurl -x socks5:\u002F\u002Fuser:pass@gate.proxyhat.com:1080 \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fdepth?symbol=BTCUSDT&amp;limit=100&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Kiedy WebSocket bije REST polling\u003C\u002Fh2>\n\u003Cp>Binance oferuje publiczne strumienie WebSocket (\u003Ccode>wss:\u002F\u002Fstream.binance.com:9443\u003C\u002Fcode>) dla klines, depth i tickerów. Kiedy warto ich używać zamiast REST?\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Depth w czasie rzeczywistym: \u003Ccode>wss:\u002F\u002Fstream.binance.com:9443\u002Fws\u002Fbtcusdt@depth\u003C\u002Fcode> aktualizuje orderbook z opóźnieniem &lt;50ms, podczas gdy REST polling co 1s zużywa 20 wag\u002Fs.\u003C\u002Fli>\n\u003Cli>Ciągłe klines: strumień \u003Ccode>@kline_1m\u003C\u002Fcode> eliminuje potrzebę pollingu \u003Ccode>\u002Fapi\u002Fv3\u002Fklines\u003C\u002Fcode> dla danych live.\u003C\u002Fli>\n\u003Cli>Ticker all-market: \u003Ccode>!ticker@arr\u003C\u002Fcode> dostarcza tickery wszystkich par w jednym strumieniu, oszczędzając setki żądań REST.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>REST pozostaje lepszy dla: \u003Cem>backfill\u003C\u002Fem> danych historycznych (WebSocket nie wysyła danych z przeszłości), jednorazowych zapytań i operacji wymagających deterministycznych odpowiedzi.\u003C\u002Fp>\n\n\u003Ch2>Najczęstsze błędy i przypadki brzegowe\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Ignorowanie nagłówka X-MBX-USED-WEIGHT-1M: to jedyny sposób na proaktywne throttle. Bez monitorowania wagi, 429 jest nieuniknione.\u003C\u002Fli>\n\u003Cli>Zbyt wysoki limit na \u002Fapi\u002Fv3\u002Fdepth: limit=1000 kosztuje 20 wag. Przy 10 parach i pollingu co 500ms = 2400 wag\u002Fs — budżet 6000 znika w 2,5s.\u003C\u002Fli>\n\u003Cli>Brak Retry-After przy 429: kontynuacja żądań po 429 prowadzi do 418 (ban IP). Zawsze szanuj nagłówek Retry-After.\u003C\u002Fli>\n\u003Cli>Sticky session dla pollingu: sticky session przy ciągłym pollingu depth = ten sam IP zużywa pełny budżet. Rotacja per-request jest lepsza dla pollingu, sticky — dla paginacji.\u003C\u002Fli>\n\u003Cli>Brak User-Agent: Binance może odrzucać żądania bez poprawnego nagłówka User-Agent.\u003C\u002Fli>\n\u003Cli>HTTP 451: geo-blokada. Użyj geo-targeting lub przełącz na \u003Ccode>api.binance.us\u003C\u002Fcode> jeśli dotyczy.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2>ProxyHat vs inne typy proxy — porównanie\u003C\u002Fh2>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\u003Cth>Cecha\u003C\u002Fth>\u003Cth>Residential (ProxyHat)\u003C\u002Fth>\u003Cth>Datacenter\u003C\u002Fth>\u003Cth>Mobile\u003C\u002Fth>\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\u003Ctd>Wykrywalność przez Binance\u003C\u002Ftd>\u003Ctd>Niska\u003C\u002Ftd>\u003Ctd>Wysoka\u003C\u002Ftd>\u003Ctd>Bardzo niska\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Koszt\u003C\u002Ftd>\u003Ctd>Średni\u003C\u002Ftd>\u003Ctd>Niski\u003C\u002Ftd>\u003Ctd>Wysoki\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Rotacja IP\u003C\u002Ftd>\u003Ctd>Per-request lub sticky\u003C\u002Ftd>\u003Ctd>Manualna\u003C\u002Ftd>\u003Ctd>Per-request\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Geo-targeting\u003C\u002Ftd>\u003Ctd>Kraj + miasto\u003C\u002Ftd>\u003Ctd>Ograniczony\u003C\u002Ftd>\u003Ctd>Kraj\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Niezawodność dla API Binance\u003C\u002Ftd>\u003Ctd>Wysoka\u003C\u002Ftd>\u003Ctd>Średnia (ryzyko bana)\u003C\u002Ftd>\u003Ctd>Wysoka\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Cp>Residential proxy z ProxyHat to optymalny wybór dla scrapowania Binance — niska wykrywalność, pełna rotacja i geo-targeting. Zobacz \u003Ca href=\"\u002Fpl\u002Fuse-cases\u002Fweb-scraping\">przypadek użycia web scraping\u003C\u002Fa> oraz \u003Ca href=\"\u002Fpl\u002Fuse-cases\u002Fserp-tracking\">SERP tracking\u003C\u002Fa> dla więcej scenariuszy.\u003C\u002Fp>\n\n\u003Ch2>Najlepsze praktyki produkcyjne\u003C\u002Fh2>\n\u003Col>\n\u003Cli>Monitoruj X-MBX-USED-WEIGHT-1M przy każdym żądaniu i throttle proaktywnie przy &gt;5000.\u003C\u002Fli>\n\u003Cli>Używaj rotacji per-request dla pollingu depth\u002Fticker i sticky session dla paginacji klines.\u003C\u002Fli>\n\u003Cli>Implementuj exponential backoff z jitter przy 429\u002F418\u002Ftimeout.\u003C\u002Fli>\n\u003Cli>Ogranicz współbieżność do 5–20 jednoczesnych żądań w zależności od budżetu wagi.\u003C\u002Fli>\n\u003Cli>Loguj zużycie wagi do metryk (Prometheus\u002FDatadog) dla alertowania.\u003C\u002Fli>\n\u003Cli>Preferuj WebSocket dla danych live, REST dla backfill.\u003C\u002Fli>\n\u003Cli>Respektuj robots.txt i ToS Binance — publiczne dane rynkowe tylko.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Ch2>Kluczowe wnioski\u003C\u002Fh2>\n\u003Cblockquote>\n\u003Cul>\n\u003Cli>Limit Binance to waga, nie liczba żądań — około 6000 wag\u002Fmin na IP. Monitoruj \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Rotacja residential proxy ProxyHat rozprasza wagę na wiele IP, eliminując ryzyko 429\u002F418.\u003C\u002Fli>\n\u003Cli>Sesje sticky (\u003Ccode>-sid-abc123\u003C\u002Fcode>) są optymalne dla paginacji klines — stabilny IP przez całą sekwencję.\u003C\u002Fli>\n\u003Cli>Geo-targeting \u003Ccode>-country-US\u003C\u002Fcode> omija HTTP 451 przy dostępie z USA.\u003C\u002Fli>\n\u003Cli>WebSocket bije REST polling dla danych live (depth, klines, tickery).\u003C\u002Fli>\n\u003Cli>Zgodność: tylko publiczne dane rynkowe, przestrzegaj ToS i limitów wagowych.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fblockquote>\n\n\u003Cp>Zacznij zbierać dane rynkowe Binance bez blokad IP — sprawdź \u003Ca href=\"\u002Fpl\u002Fpricing\">cennik ProxyHat\u003C\u002Fa> i skonfiguruj pierwsze proxy w kilka minut. Pełna dokumentacja dostępna jest na \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">docs.proxyhat.com\u003C\u002Fa>.\u003C\u002Fp>","Jak scrapować REST API Binance z proxy | ProxyHat","Przewodnik jak scrapować REST API Binance z proxy: limity wag, rotacja IP, sesje sticky i omijanie blokad 429\u002F418. Przykłady Python i Node.js.","\u002Fpl\u002Fblog\u002Fjak-scrapowac-rest-api-binance-proxy",null,"https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fjak-scrapowac-rest-api-binance-proxy-og.webp",[17,20,23],{"question":18,"answer":19},"Dlaczego scrapowanie REST API Binance z proxy jest ważne dla użytkowników proxy?","Binance stosuje limit oparty na wadze (weight), nie na liczbie żądań. Endpoint \u002Fapi\u002Fv3\u002Fdepth z limitem 1000 kosztuje 20 wag — polling 10 par co 500ms zużywa 2400 wag\u002Fs, wyczerpując budżet 6000 w 2,5 sekundy. Bez rotacji IP serwer zwraca 429, a następnie 418 (ban IP). Rotacyjne proxy residential rozpraszają wagę na wiele IP, umożliwiając skalowanie zbierania danych bez blokad.",{"question":21,"answer":22},"Który typ proxy najlepiej działa do scrapowania REST API Binance?","Rotacyjne proxy residential są optymalne do scrapowania REST API Binance. Mają niską wykrywalność (są trudniejsze do zidentyfikowania jako datacenter), pełną rotację IP per-request lub sesje sticky dla paginacji, oraz geo-targeting na poziomie kraju i miasta. Proxy datacenter są tańsze, ale mają wysoką wykrywalność i ryzyko bana. Proxy mobile są najbardziej niezawodne, ale najdroższe. ProxyHat oferuje residential przez gate.proxyhat.com:8080 (HTTP) i :1080 (SOCKS5).",{"question":24,"answer":25},"Jak uniknąć blokad przy scrapowaniu REST API Binance?","Aby uniknąć blokad: (1) monitoruj nagłówek X-MBX-USED-WEIGHT-1M i throttle proaktywnie przy wadze >5000; (2) używaj rotacji IP per-request dla pollingu i sesji sticky dla paginacji; (3) implementuj exponential backoff z jitter przy 429; (4) zawsze szanuj nagłówek Retry-After — kontynuacja żądań po 429 prowadzi do 418; (5) ogranicz współbieżność do 5–20 jednoczesnych żądań; (6) preferuj WebSocket dla danych live zamiast REST polling.",false,"2026-08-03T10:04:04+00:00","2026-10-03T08:29:51+00:00","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fjak-scrapowac-rest-api-binance-proxy-master.webp","How to Scrape the Binance REST API with Proxies: A Developer Guide","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fjak-scrapowac-rest-api-binance-proxy-card.webp",12,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},"ProxyHat Team","proxyhat-team","The ProxyHat editorial team covers proxies, web scraping, and data extraction.",[38],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},4,"developer-guides","Przewodniki dla programistów","Przewodniki dla programistów 124; ProxyHat Blog","Poradniki kodowe i przewodniki SDK do integracji proxy z aplikacjami.",[],{"fr":46,"en":47,"pt":48,"ko":49,"ru":50,"zh":51,"x-default":47},"\u002Ffr\u002Fblog\u002Fcomment-scraper-api-rest-binance-proxies","\u002Fblog\u002Fscrape-binance-rest-api-proxies","\u002Fpt\u002Fblog\u002Fcomo-raspar-api-binance-proxies","\u002Fko\u002Fblog\u002Fbinance-rest-api-proxy-scraping","\u002Fru\u002Fblog\u002Fkak-skrejpit-binance-rest-api-proksi","\u002Fcn\u002Fblog\u002Fbinance-rest-api-proxy-scraping-guide",{"tr":53,"fr":46,"en":47,"ja":54,"pt":48,"ko":49,"pl":13,"es":55,"ru":50,"zh":51,"it":56,"de":57},"\u002Ftr\u002Fblog\u002Fbinance-rest-api-proxy-tarama","\u002Fja\u002Fblog\u002Fbinance-api-scraping-proxy","\u002Fes\u002Fblog\u002Fscrapear-api-binance-proxies","\u002Fit\u002Fblog\u002Fscraping-binance-rest-api-con-proxy","\u002Fde\u002Fblog\u002Fbinance-rest-api-mit-proxies-scrapen",81,[60,76,92,108],{"id":61,"slug":62,"title":63,"excerpt":64,"featured_image_url":65,"featured_image_alt":66,"card_image_url":67,"og_image_url":68,"published_at":69,"updated_at":69,"content_updated_at":70,"reading_time_minutes":32,"is_featured":26,"indexable":4,"views":71,"author":72,"categories":73,"tags":75},176,"got-scraping-nodejs-proxy","got-scraping w Node.js: kompletny przewodnik po proxy i header generator","got-scraping to biblioteka HTTP dla Node.js oparta na got, zaprojektowana do scrapingu. Dowiedz się, jak łączyć ją z residential proxy ProxyHat, konfigurować header generator i unikać blokad na dużą skalę.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fgot-scraping-nodejs-proxy-master.webp","got-scraping in Node.js: A Developer's Guide with Residential Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fgot-scraping-nodejs-proxy-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fgot-scraping-nodejs-proxy-og.webp","2026-08-04T16:05:06+00:00","2026-10-03T08:57:48+00:00",120,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[74],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],{"id":77,"slug":78,"title":79,"excerpt":80,"featured_image_url":81,"featured_image_alt":82,"card_image_url":83,"og_image_url":84,"published_at":85,"updated_at":85,"content_updated_at":86,"reading_time_minutes":32,"is_featured":26,"indexable":26,"views":87,"author":88,"categories":89,"tags":91},175,"rotacja-proxy-w-colly-1","Rotacja Proxy w Colly: Kompletny Przewodnik dla Programistów Go","Praktyczny przewodnik po rotacji proxy w frameworku Colly dla Go. Dowiedz się, jak skonfigurować RoundRobinProxySwitcher, geo-targeting i wzorce produkcyjne z residential proxy.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Frotacja-proxy-w-colly-1-master.webp","Rotating Proxies in Colly: A Framework-Idiomatic Guide for Go Developers","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Frotacja-proxy-w-colly-1-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Frotacja-proxy-w-colly-1-og.webp","2026-08-04T10:05:34+00:00","2026-10-03T08:29:56+00:00",71,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[90],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],{"id":93,"slug":94,"title":95,"excerpt":96,"featured_image_url":97,"featured_image_alt":98,"card_image_url":99,"og_image_url":100,"published_at":101,"updated_at":101,"content_updated_at":102,"reading_time_minutes":32,"is_featured":26,"indexable":4,"views":103,"author":104,"categories":105,"tags":107},195,"jak-scrapowac-bybit-v5-api-proxy","Pobieranie danych rynkowych krypto z rotującymi proxy (przykład: API rynku Bybit V5)","Przewodnik dla programistów: pobieraj dane orderbook, tickers i kline z Bybit V5 Market API z rotującymi proxy ProxyHat. Gotowe przykłady w Python i Node.js, obsługa limitów, geo-blokad i sesji sticky.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fjak-scrapowac-bybit-v5-api-proxy-master.webp","How to Scrape the Bybit V5 Market API with Rotating Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fjak-scrapowac-bybit-v5-api-proxy-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fjak-scrapowac-bybit-v5-api-proxy-og.webp","2026-08-03T16:09:16+00:00","2026-10-04T01:29:51+00:00",86,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[106],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],{"id":109,"slug":110,"title":111,"excerpt":112,"featured_image_url":113,"featured_image_alt":114,"card_image_url":115,"og_image_url":116,"published_at":117,"updated_at":117,"content_updated_at":70,"reading_time_minutes":32,"is_featured":26,"indexable":4,"views":118,"author":119,"categories":120,"tags":122},172,"uzywanie-proxy-w-swift-urlsession","Używanie proxy w Swift z URLSession — przewodnik dla programistów iOS i macOS","Kompletny przewodnik po konfiguracji proxy w Swift z URLSession: HTTP\u002FHTTPS, SOCKS5, autoryzacja, geo-targeting, async\u002Fawait i wskazówki produkcyjne.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fuzywanie-proxy-w-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\u002Fpl\u002Fuzywanie-proxy-w-swift-urlsession-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fpl\u002Fuzywanie-proxy-w-swift-urlsession-og.webp","2026-07-26T16:03:44+00:00",230,{"name":34,"slug":35,"bio":36,"avatar_url":14,"website_url":14,"social_links":14},[121],{"id":39,"slug":40,"name":41,"description":14,"meta_title":42,"meta_description":43,"parent_id":14},[],[]]