Szybka odpowiedź
Jak korzystać z rotującego proxy w Node.js?
Z fetch stwórz undici ProxyAgent dla http://gw.crawlrelay.com:7777 i przekaż go jako dispatcher. Z axios lub got przekaż agenta proxy jak https-proxy-agent lub hpagent i ustaw proxy: false w axios. CrawlRelay proxy rezydencjalne odczytują kraj i sesję z nazwy użytkownika, z 0,50 USD/GB. Płatne kryptowalutą, bez KYC.
Konfiguracja Node.js w skrócie
| fetch / undici | new ProxyAgent({ uri, token }), potem fetch(url, { dispatcher }) |
|---|---|
| axios | httpsAgent: new HttpsProxyAgent(url) i proxy: false |
| got | agent: { https: new HttpsProxyAgent({ proxy }) } z hpagent |
| SOCKS5 | socks-proxy-agent z URL socks5h:// na porcie 7778 |
| Nowe IP przy każdym żądaniu | Nowy agent lub nowy identyfikator sesji przy każdym żądaniu; połączenia w puli zachowują swoje wyjście |
| Format modułu | Przykładami są moduły ES (.mjs lub "type": "module") z top-level await |
Jak korzystać z proxy z fetch w Node?
Globalny fetch w Node oparty jest na undici, ale domyślnie nie odczytuje HTTP_PROXY ani HTTPS_PROXY. Zainstaluj undici i przekaż ProxyAgent jako dispatcher. Pole token wysyła poświadczenia jako nagłówek Proxy-Authorization, więc hasło nigdy nie pojawia się w URL, który mógłby być logowany.
import { ProxyAgent, fetch } from "undici";
const credentials = Buffer.from("USERNAME-country-us:PASSWORD").toString("base64");
const dispatcher = new ProxyAgent({
uri: "http://gw.crawlrelay.com:7777",
token: `Basic ${credentials}`,
});
const res = await fetch("https://api.ipify.org?format=json", {
dispatcher,
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
await dispatcher.close();Jak korzystać z proxy z axios?
Nie polegaj na wbudowanej opcji proxy w axios dla stron HTTPS: ona wysyła żądanie do proxy bez tunelu CONNECT, co wiele proxy odrzuca. Wyłącz tę opcję proxy: false i przekaż agenta, który otwiera właściwy tunel.
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://USERNAME-country-de:[email protected]:7777");
const client = axios.create({ httpsAgent: agent, httpAgent: agent, proxy: false, timeout: 30000 });
const { data } = await client.get("https://api.ipify.org?format=json");
console.log(data.ip);Jak korzystać z proxy z got?
got używa jednego agenta na protokół. hpagent stosuje się do http.Agent Node: keep-alive jest wyłączony, chyba że przekażesz keepAlive: true. Zostaw wyłączone lub ustaw keepAlive: false jak poniżej, gdy chcesz, by każde żądanie miało nowe połączenie, a więc zwykle nowe wyjście.
import got from "got";
import { HttpsProxyAgent } from "hpagent";
const proxy = "http://USERNAME-country-fr:[email protected]:7777";
const body = await got("https://api.ipify.org", {
agent: { https: new HttpsProxyAgent({ proxy, keepAlive: false }) },
timeout: { request: 30000 },
retry: { limit: 2, statusCodes: [429, 502, 503, 504] },
}).text();
console.log(body);Jak używać SOCKS5 w Node.js?
Użyj socks-proxy-agent ze schematem socks5h://, by nazwa hosta była rozwiązywana na wyjściu. Działa to z modułami http i https Node oraz każdą biblioteką akceptującą agenta.
import https from "node:https";
import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://USERNAME-country-gb:[email protected]:7778");
const req = https.get("https://api.ipify.org", { agent, timeout: 30000 }, (res) => {
let body = "";
res.on("data", (chunk) => (body += chunk));
res.on("end", () => console.log(res.statusCode, body));
});
req.on("timeout", () => req.destroy(new Error("timeout after 30 s")));
req.on("error", (err) => console.error(err.code, err.message));Jak ograniczyć równoległość na hosta bez biblioteki?
Promise.all na ponad 10 000 URL otwiera 10 000 żądań jednocześnie. Mały limiter na hostname utrzymuje każdą stronę na umiarkowanym poziomie, podczas gdy cały crawl działa równolegle. Poniższa wersja nie ma zależności i działa z dowolnym klientem powyżej.
import { ProxyAgent, fetch } from "undici";
const PER_HOST = 4;
const active = new Map();
const waiting = new Map();
const dispatcher = new ProxyAgent("http://USERNAME-country-us:[email protected]:7777");
async function withHostSlot(url, task) {
const host = new URL(url).hostname;
while ((active.get(host) ?? 0) >= PER_HOST) {
await new Promise((resolve) => {
if (!waiting.has(host)) waiting.set(host, []);
waiting.get(host).push(resolve);
});
}
active.set(host, (active.get(host) ?? 0) + 1);
try {
return await task();
} finally {
active.set(host, active.get(host) - 1);
waiting.get(host)?.shift()?.();
}
}
const urls = ["https://example.com/", "https://example.org/", "https://example.net/"];
const results = await Promise.all(
urls.map((url) =>
withHostSlot(url, async () => {
const res = await fetch(url, { dispatcher, signal: AbortSignal.timeout(30000) });
return [url, res.status, (await res.arrayBuffer()).byteLength];
}).catch((err) => [url, err.name, 0])
)
);
console.table(results);
await dispatcher.close();Dlaczego czasem dostaję to samo IP dwa razy albo ECONNRESET?
Agenci tworzą pule połączeń, a połączenie w puli zachowuje wyjście, z którym zostało otwarte. Aby uzyskać nowe IP przy każdym żądaniu, stwórz nowego agenta na żądanie i zamknij go potem, wyłącz keep-alive w agencie lub dodaj unikalny -session-<id> w nazwie użytkownika żądania.
ECONNRESET i socket hang up zazwyczaj wynikają z ponownego użycia gniazda w puli, które zostało już zamknięte przez drugą stronę lub z utraty wyjścia. Powtórz żądania GET raz na nowym połączeniu. Strona o resetowaniu połączeń ](/docs/errors/connection-reset/) wyjaśnia szczegóły.
Node.js i proxy: pytania
Czy fetch w Node.js obsługuje HTTP_PROXY?
Nie domyślnie w wersjach, na których działają dziś większość projektów: globalny fetch ignoruje zmienne środowiskowe proxy, chyba że przekażesz dispatcher. Użyj undici ProxyAgent jak pokazano wyżej lub ustaw globalnego dispatchera undici setGlobalDispatcher() jeśli każde żądanie w procesie ma używać proxy.
Dlaczego axios nie działa z HTTPS przez proxy?
Wbudowana opcja proxy w axios wysyła żądania HTTPS do proxy w formacie, który wiele proxy odrzuca, zamiast otworzyć tunel CONNECT. Wyłącz proxy: false i przekaż HttpsProxyAgent jako httpsAgent. Żądanie przechodzi przez właściwy tunel, a TLS pozostaje między Twoim kodem a stroną.
Jak wysyłać zapytania z różnych krajów z jednego procesu Node.js?
Utwórz jednego agenta na kraj, każdy z własną nazwą użytkownika, np. USERNAME-country-de lub USERNAME-country-jp, i wybieraj agenta na żądanie. Agenci są tani, a ich rozdzielenie pozwala także rozdzielić pule połączeń i wyjścia.
Jaki timeout ustawić w Node.js?
Zawsze ustaw timeout: AbortSignal.timeout(30000) dla fetch, timeout: 30000 dla axios, timeout: { request: 30000 } dla got. Trzydzieści sekund pasuje do stron HTML; dla wolnych celów i mobilnych proxy 4G daj do 60 sekund i spróbuj ponownie raz na nowym połączeniu zamiast czekać dłużej.
Podłącz swojego crawlera Node.js
5,94 USD dla 10 GB, 0,50 USD/GB od 50 GB.