

در این مقاله قدمبهقدم یاد میگیریم چگونه در پروژههای Java که از OkHttp یا Apache HttpClient برای وب اسکریپینگ استفاده میکنند، پراکسی را یکپارچه کنیم و روشهای مختلف چرخش (rotate) پراکسی را پیادهسازی کنیم. در پایان این مطلب شما با سه فرم رایج پراکسی (لیست IP، دروازه/گِیتوی و API پراکسی) آشنا میشوید، نحوهٔ احراز هویت پراکسی را میدانید و مثالهای عملی و نکات مربوط به مانیتورینگ، امنیت و مدیریت خطا را خواهید دید.
ایدهٔ کلی: یک نمونهٔ Proxy از بستهٔ java.net میسازیم و آن را به OkHttpClient.Builder میدهیم تا هر درخواست از طریق آن پراکسی ارسال شود. این روش برای لیست سادهٔ پراکسی یا گیتویهایی که آدرس ثابت دارند مناسب است.
مراحل عملی:
مثال ساده (OkHttp):
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttpProxyExample {
public static void main(String[] args) throws Exception {
String proxyHost = "111.43.105.50";
int proxyPort = 9091;
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
OkHttpClient client = new OkHttpClient.Builder()
.proxy(proxy)
.readTimeout(30, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder()
.url("https://httpbin.org/ip")
.build();
Response response = client.newCall(request).execute();
System.out.println("Response body: " + response.body().string());
response.close();
}
}توضیح اجزای مهم:
نکات عملی و بهترینروشها: همیشه response.close() را فراخوانی کنید تا منابع آزاد شوند. از متغیرهای محیطی یا سرویسهای امن برای نگهداری host/port ناتیفیکیشن استفاده کنید، نه قرار دادن credentialها در کد.
ایدهٔ کلی مشابه است ولی در Apache HttpClient معمولاً یک HttpHost برای پراکسی میسازیم و آن را به builder میدهیم.
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
public class ApacheProxyExample {
public static void main(String[] args) throws Exception {
HttpHost proxyHost = new HttpHost("http", "proxy.example.com", 80);
CloseableHttpAsyncClient client = HttpAsyncClients.custom()
.setProxy(proxyHost)
.build();
client.start();
var request = SimpleRequestBuilder.get("https://httpbin.org/ip").build();
SimpleHttpResponse response = client.execute(request, null).get();
System.out.println("Response body: " + response.getBodyText());
client.close();
}
}توضیح: HttpHost نشاندهندهٔ scheme/host/port پراکسی است و setProxy آن را به کلاینت متصل میکند.
بسیاری از پراکسیها نیاز به username/password دارند. در OkHttp با یک Authenticator و در Apache با یک CredentialsProvider این کار انجام میشود. توجه کنید که پاسخهای پراکسی معمولاً کد وضعیت 407 (Proxy Authentication Required) برمیگردانند؛ در برخی منابع 401 ذکر شده اما برای پراکسی، 407 رایجتر است.
مثال احراز هویت در OkHttp:
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.TimeUnit;
import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
public class OkHttpAuthProxy {
public static void main(String[] args) throws Exception {
String proxyHost = "example.com";
int proxyPort = 80;
String username = "USERNAME";
String password = "PASSWORD";
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
Authenticator authenticator = new Authenticator() {
@Override
public Request authenticate(Route route, Response response) {
String credential = Credentials.basic(username, password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
};
OkHttpClient client = new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator(authenticator)
.readTimeout(30, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url("https://httpbin.org/ip").build();
Response response = client.newCall(request).execute();
System.out.println("Response body: " + response.body().string());
response.close();
}
}توضیح خطبهخط:
مثال معادل در Apache HttpClient با CredentialsProvider (خطوط اصلی):
HttpHost proxyHost = new HttpHost("http", proxyHostname, proxyPort);
CredentialsProvider credsProvider = CredentialsProviderBuilder.create()
.add(new AuthScope(proxyHostname, proxyPort), BRIGHTDATA_USERNAME, BRIGHTDATA_PASSWORD.toCharArray())
.build();
CloseableHttpAsyncClient client = HttpAsyncClients.custom()
.setProxy(proxyHost)
.setDefaultCredentialsProvider(credsProvider)
.build();نکات امنیتی: هرگز نامکاربری/رمز را مستقیم در سورس کنترل نگه ندارید؛ از متغیرهای محیطی، فایلهای پیکربندی با مجوز محدود یا سرویسهای محرمانه (vault) استفاده کنید. همچنین همیشه کانکشن HTTPS را بین شما و سرویس پراکسی حفظ کنید تا credentials در شبکه لو نرود.
سه روش مرسوم برای دسترسی به پراکسی وجود دارد:
ایدهٔ کلی: یک لیست از URLهای پراکسی دارید (مثلاً scheme://username:password@host:port) و برای هر درخواست یکی را بهصورت تصادفی یا با استراتژی Round-Robin انتخاب میکنید.
نمونهٔ ساده برای انتخاب تصادفی و استفادهٔ OkHttp:
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
public class ProxyRotation {
static String[] proxyList = {
"http://username:password@85.237.57.198:20000",
"http://username:password@85.237.57.198:21000",
"http://username:password@85.237.57.198:22000",
"http://username:password@85.237.57.198:23000"
};
static String getRandomProxy(String[] list) {
int rnd = new Random().nextInt(list.length);
return list[rnd];
}
public static void main(String[] args) throws Exception {
URL proxyUrl = new URL(getRandomProxy(proxyList));
String userInfo = proxyUrl.getUserInfo(); // username:password
int idx = userInfo.indexOf(":");
String proxyHost = proxyUrl.getHost();
int proxyPort = proxyUrl.getPort();
String username = userInfo.substring(0, idx);
String password = userInfo.substring(idx + 1);
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
Authenticator authenticator = new Authenticator() {
@Override
public Request authenticate(Route route, Response response) {
return response.request().newBuilder()
.header("Proxy-Authorization", Credentials.basic(username, password))
.build();
}
};
OkHttpClient client = new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator(authenticator)
.readTimeout(30, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url("https://httpbin.org/ip").build();
Response response = client.newCall(request).execute();
System.out.println("Response body: " + response.body().string());
response.close();
}
}محدودیتها و توصیهها:
ایدهٔ کلی: ارائهدهنده یک آدرس ثابت و جزئیات ورود به شما میدهد و خودش مدیریت استخر پراکسی را انجام میدهد. شما فقط یک پراکسی کانفیگ میکنید و درخواستها را از طریق آن میفرستید.
مزایا:
معایب:
مثال ادغام BrightData (OkHttp):
// ساخت Proxy با hostname و port گیتوی و قرار دادن نام کاربری/پسورد در هدر
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("zproxy.lum-superproxy.io", 22225));
// سپس همان الگوی Authenticator برای اضافه کردن Proxy-Authorization و ساخت OkHttpClient استفاده میشود.نکات عملی: هنگام استفاده از gateway، بررسی کنید که ارائهدهنده قابلیتهایی مثل sticky sessions (برای حفظ session با یک IP) یا پارامترهای منطقه/ISP را ارائه میدهد یا خیر.
ایدهٔ کلی: بهجای ارسال درخواست مستقیم به سایت هدف از طرف شما، شما یک درخواست به API ارائهدهندهٔ پراکسی میزنید (معمولاً شامل آدرس هدف و کلید API) و آنها محتوای HTML را برای شما بازمیگردانند. این روش مدیریتیترین فرم است.
مثال ساده با OkHttp (ارسال URL هدف به API پراکسی):
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ScrapeOpsProxyAPI {
public static void main(String[] args) throws Exception {
String SCRAPEOPS_API_KEY = "your_api_key";
String targetUrl = "https://httpbin.org/ip";
String proxyAPIUrl = String.format("https://proxy.scrapeops.io/v1?api_key=%s&url=%s", SCRAPEOPS_API_KEY, targetUrl);
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url(proxyAPIUrl).build();
Response response = client.newCall(request).execute();
System.out.println("Response body: " + response.body().string());
response.close();
}
}مزایا: سادهترین پیادهسازی، ارائهدهنده مسئول تمامی پیچیدگیهای چرخش، ریت لیمیت و header management است.
معایب و احتیاطها: این روش به معنی فرستادن URL هدف و محتوا به سرویس سوم شخص است؛ از نظر حریم خصوصی و قوانین ممکن است محدودکننده باشد. بعلاوه باید به نرخ استفاده و هزینه توجه کنید.
خلاصهٔ عملی: برای شروع سریع و ساده از Proxy Gateway یا Proxy API استفاده کنید؛ اگر به کنترل بیشتری نیاز دارید و میخواهید هزینه را کاهش دهید، از لیست پراکسی با سیستم مانیتورینگ و چرخش استفاده کنید. در هر حالت احراز هویت را با مکانیزم امن پیادهسازی کنید و هشدارها، timeouts و retryهای مناسب را اضافه نمایید. بهعلاوه مانیتورینگ پیوستهٔ کیفیت پراکسیها برای پایدار نگه داشتن اسکریپرهای تولیدی ضروری است.
اگر سوال خاصی در مورد یک سناریو دارید (مثلاً اسکریپ کردن سایت خاصی با نیاز به login یا با استفاده از پراکسی موبایل)، بگویید تا مثال اختصاصیتر و تنظیمات بهینه ارائه شود.

