

در وب اسکریپینگ یکی از دلایل رایج بلاک شدن، استفاده از user-agents نامناسب یا نبودن آنهاست. در این مقاله به صورت گامبهگام نشان میدهم چگونه در جاوا با کتابخانههای OkHttp و Apache HttpClient هدر User-Agent را تنظیم کنید، چگونه آنها را بچرخانید (rotate) و چگونه با استفاده از یک API مرکزی هزاران User-Agent و مجموعهی کامل هدرهای مرورگر را مدیریت کنید. مخاطب این راهنما یک توسعهدهنده پایتون در سطح متوسط است که میخواهد مفاهیم و مثالهای عملی وب اسکریپینگ را ببیند.
User-Agent رشتهای است که مرورگر یا کلاینت به سرور میفرستد تا نوع مرورگر، سیستمعامل و گاهی نسخهها را معرفی کند. بسیاری از سایتها رفتار متفاوتی برای مرورگرهای واقعی و رباتها دارند؛ ارسال User-Agent خالی یا پیشفرض کتابخانهها معمولاً شما را زود شناسایی و بلاک میکند.
مثال سادهای از User-Agent واقعی:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36اگر درخواست شما User-Agent نداشته باشد یا مقدار نادقیق بفرستد، سیستمهای ضدربات به سرعت مشکوک میشوند.
ایده کلی: هنگام ساختن درخواست، هدر User-Agent را اضافه کنید. در OkHttp این کار با متد addHeader روی Request.Builder انجام میشود.
کد نمونه (Java):
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class FakeUserAgents {
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://httpbin.org/headers")
.addHeader("User-Agent",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36")
.build();
Response response = client.newCall(request).execute();
System.out.println("Response body: " + response.body().string());
}
}توضیح:
نکات خطبهخط: ابتدا کلاینت ساخته میشود؛ سپس Request.Builder با URL مقداردهی میشود؛ متد addHeader هدر را اضافه میکند؛ در نهایت درخواست ساخته و اجرا میشود.
ایده کلی مشابه است، اما در Apache HttpClient متد معادل setHeader روی سازندهی درخواست استفاده میشود (در کدهای async از SimpleRequestBuilder استفاده شده است).
کد نمونه (Java async):
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import java.util.concurrent.Future;
public class FakeUserAgentsHttpClient {
public static void main(String[] args) throws Exception {
CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
client.start();
SimpleHttpRequest request = SimpleRequestBuilder.get("http://httpbin.org/headers")
.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 Chrome/38.0.2125.111 Safari/537.36")
.build();
Future future = client.execute(request, null);
SimpleHttpResponse response = future.get();
System.out.println("Response body: " + response.getBodyText());
client.close();
}
} توضیحات:
ایده کلی: یک لیست از User-Agentها نگه دارید و برای هر درخواست یکی را بهصورت تصادفی یا بر اساس الگو انتخاب کنید. مزیت: الگوی رفتاری طبیعیتری ایجاد میکند؛ عیب: باید لیست را بهروز نگه دارید.
کد نمونه (Java با انتخاب تصادفی):
import java.util.Random;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class RotatingUserAgents {
public static String[] userAgents = new String[]{
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/93.0.4577.82 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 Version/14.0.3 Mobile/15E148 Safari/604.1",
"Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)"
};
public static String getRandomUserAgent(String[] userAgents) {
int rnd = new Random().nextInt(userAgents.length);
return userAgents[rnd];
}
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://httpbin.org/headers")
.addHeader("User-Agent", getRandomUserAgent(userAgents))
.build();
Response response = client.newCall(request).execute();
System.out.println("Response body: " + response.body().string());
}
}نکات عملی برای رتِیت و چرخش:
برای توسعهدهندگان پایتون: معادل ساده با کتابخانه requests به این شکل است:
import random
import requests
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 ...)',
]
headers = {'User-Agent': random.choice(user_agents)}
resp = requests.get('http://httpbin.org/headers', headers=headers)
print(resp.text)ساخت و بهروز نگه داشتن فهرست بزرگی از User-Agentها هزینهبر است. راه بهتر، استفاده از یک سرویس یا API (مثلاً سرویس ScrapeOps Fake User-Agent API) برای گرفتن لیستی بهروز وقتی اسکراپر شروع به کار میکند است. مزیت: اتوماتیک بودن و کمتر شدن نگهداری؛ معایب: نیاز به کلید API، محدودیت نرخ و وابستگی به یک سرویس بیرونی.
الگوی عملی:
نمونهای از فراخوانی API و پردازش پاسخ با OkHttp (جاوا):
// اسکلت کد: فراخوانی URL API و تبدیل JSON به List
// در عمل: مقادیر مانند SCRAPEOPS_API_KEY و مدیریت خطا/رتری را اضافه کنید نکات عملی پیرامون API:
وبسایتهای پیشرفتهتر نه تنها به User-Agent نگاه میکنند، بلکه مجموعهای از هدرها را که مرورگر واقعی ارسال میکند بررسی میکنند (مثل sec-ch-ua، Accept-Language، Accept-Encoding و... ). ارسال تنها User-Agent در بسیاری از موارد کافی است، اما ارسال مجموعهای از هدرهای هماهنگ با آن User-Agent احتمال شناسایی را کاهش میدهد.
نمونه هدرها (مثال Chrome روی macOS):
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,...
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: documentمیتوانید چنین مجموعهای از هدرها را دستی بسازید، اما بهتر است از یک سرویس بهروز یا دیتابیس از هدرهای شبیهسازی شده استفاده کنید تا مطابقت بین User-Agent و بقیه هدرها حفظ شود.
پس از گرفتن یک مجموعه هدر از API یا ساختن دستی، باید تمام جفتهای header:value را به سازنده درخواست اضافه کنید:
Request.Builder rb = new Request.Builder().url("http://httpbin.org/headers");
// فرض کنید headersMap یک Map از هدرهای شبیهسازی شده است
headersMap.forEach((k,v) -> rb.addHeader(k, v));
Request request = rb.build(); همین رویکرد را میتوانید برای Apache HttpClient با setHeader یا setHeaders انجام دهید.
تنظیم User-Agent در OkHttp و Apache HttpClient ساده و مؤثر است: کافی است هنگام ساختن درخواست هدر مناسب را اضافه کنید. برای افزایش موفقیت و کاهش ریسک بلاک شدن، بهتر است User-Agentها را بچرخانید، مجموعه کامل هدرهای مرورگر را شبیهسازی کنید و در صورت امکان از یک منبع بهروز (مثل ScrapeOps Fake User-Agent / Fake Browser Headers API) برای مدیریت فهرستها استفاده کنید. در نهایت، مدیریت صحیح کلاینتها، کش کردن لیستها، و پیادهسازی استراتژیهای retry و backoff برای پایداری اسکریپر حیاتیاند.


