

در وب اسکریپینگ یکی از دلایل اصلی بلاک شدن درخواستها، استفاده از User-Agentهای ضعیف یا ناپایدار است. در این مقاله به صورت عملی و گامبهگام یاد میگیرید چگونه در محیط Node.js برای کتابخانههای متداول user-agent تعریف، آن را بچرخانید (rotate) و در مقیاس بزرگ مدیریت کنید. مثالها با node-fetch، axios، superagent، got و request-promise هستند و برای هر قطعه کد توضیح ورودی، خروجی و نکات مهم داده شده است.
User-Agent یک رشته در هدر HTTP است که مشخص میکند درخواست از چه مرورگر/سیستمعاملی میآید. وقتی از مقدار پیشفرض برخی کلاینتهای Node.js استفاده کنید (مثلاً "node-fetch") سرور بهراحتی تشخیص میدهد درخواست از یک کتابخانه است و ممکن است آن را مسدود کند. یک Fake User-Agent یعنی جایگزینی رشتهای واقعگرایانه که شبیه به مرورگرهای رایج است تا احتمال تشخیص ربات کاهش یابد.
نکته فنی: فقط تغییر User-Agent کافی نیست — هدرهای دیگر (Accept, Accept-Language, Sec-* و غیره) هم نقش دارند. در ادامه به این موارد هم میپردازیم.
ایده کلی: در گزینههای درخواست (options) یک شیء headers بسازید و کلید 'User-Agent' را ست کنید. خروجی هر درخواست معمولاً پاسخ سرور است و شما میتوانید با endpointهایی مثل httpbin بررسی کنید هدر ارسال شده چیست.
مثال با node-fetch — ورودی: url و options با header؛ خروجی: پاسخ JSON از سرور:
import fetch from 'node-fetch';
(async () => {
const url = 'https://httpbin.org/headers';
const options = {
method: 'GET',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36'
}
};
try {
const res = await fetch(url, options);
const data = await res.json();
console.log(data); // مشاهده هدرهای ارسالی
} catch (err) {
console.error('request error', err);
}
})();توضیح: ما options.headers میسازیم و به تابع fetch پاس میدهیم. پاسخ JSON شامل هدرهای دریافتی سرور است تا مطمئن شویم مقدار ارسال شده درست است.
مثال خلاصه با axios (ورودی: url، options؛ خروجی: response.data):
const axios = require('axios');
(async () => {
const url = 'https://httpbin.org/headers';
const options = {
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36'
}
};
try {
const response = await axios.get(url, options);
console.log(response.data);
} catch (error) {
console.error('error', error);
}
})();برای superagent از متد set استفاده کنید؛ برای got و request-promise نیز مشابه است: در options شیء headers قرار دهید.
ایده کلی: نگه داشتن یک لیست از UAهای معتبر و انتخاب تصادفی یا الگوریتمی از بین آنها برای هر درخواست. این کار باعث میشود ترافیک شما شبیه کاربران مختلف به نظر برسد و احتمال بلاک شدن کاهش یابد.
نمونه اولیه: استفاده از پکیج random-useragent یا لیست محلی. ورودی: لیست UA؛ خروجی: UA انتخابشده.
import fetch from 'node-fetch';
import randomUserAgent from 'random-useragent';
const userAgents = [
'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) AppleWebKit/605.1.15 Version/14.0.3 Mobile/15E148 Safari/604.1',
'Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)'
];
function getRandomUserAgent(list) {
const idx = Math.floor(Math.random() * list.length);
return list[idx];
}
(async () => {
const url = 'https://httpbin.org/headers';
const headers = { 'User-Agent': randomUserAgent.getRandom(userAgents) || getRandomUserAgent(userAgents) };
const res = await fetch(url, { method: 'GET', headers });
console.log(await res.json());
})();نکات عملی:
در پروژههای بزرگ ساخت و بهروزرسانی دستی لیست UA مقیاسپذیر نیست. یک روش بهتر استفاده از یک API مرکزی است که فهرستی از UAهای بهروز را برمیگرداند. در متن منبع از یک سرویس یاد شده که دو endpoint دارد: دریافت لیست User-Agents و دریافت مجموعه هدرهای کامل (browser headers).
مثال ساده برای دریافت لیست UA از یک API (ورودی: API key؛ خروجی: آرایه UA):
// دریافت لیست User-Agent از API
import fetch from 'node-fetch';
const SCRAPEOPS_API_KEY = 'YOUR_API_KEY';
const apiUrl = `http://headers.scrapeops.io/v1/user-agents?api_key=${SCRAPEOPS_API_KEY}`;
async function getUserAgentList() {
const res = await fetch(apiUrl);
const json = await res.json();
return json.result || [];
}
// استفاده
(async () => {
const list = await getUserAgentList();
console.log('fetched', list.length, 'user-agents');
})();توضیح: تابع getUserAgentList یک درخواست ساده GET میزند و آرایهای از رشتههای UA برمیگرداند. در صورت خطا باید retry یا fallback داشته باشید (مثلاً لیست محلی).
الگوریتم پیشنهادی برای استفاده در اسکریپرهای بزرگ:
بسیاری از سیستمهای ضدربات به دنبال تناقض بین User-Agent و سایر هدرها هستند؛ مثلاً اگر User-Agent مربوط به Chrome روی macOS باشد ولی sec-ch-ua-platform یا Accept-Language مناسب نباشد، رفتار مشکوک میشود. بنابراین برای افزایش موفقیت بهتر است مجموعه کامل هدرهای مرورگر را شبیهسازی کنید.
مثال هدرهای معمول یک 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) AppleWebKit/537.36 Chrome/99.0.4844.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Sec-Fetch-Site: none
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate, brنکات امنیتی و بهترین روشها:
بهجای ساخت دستی مجموعه هدرها میتوانید از یک endpoint مخصوص هدرهای مرورگر استفاده کنید. نمونه کد برای دریافت و استفاده از یک هدر تصادفی:
// دریافت هدرهای آماده (browser headers)
import fetch from 'node-fetch';
const SCRAPEOPS_API_KEY = 'YOUR_API_KEY';
const headersUrl = `http://headers.scrapeops.io/v1/browser-headers?api_key=${SCRAPEOPS_API_KEY}`;
async function getHeadersList() {
const res = await fetch(headersUrl);
const json = await res.json();
return json.result || [];
}
function pickRandom(list) {
return list[Math.floor(Math.random() * list.length)];
}
(async () => {
const headerList = await getHeadersList();
const headers = pickRandom(headerList); // headers یک شیء کامل مانند { 'user-agent': '...', 'accept': '...', ... }
// استفاده در درخواست
const target = 'https://httpbin.org/headers';
const res = await fetch(target, { method: 'GET', headers });
console.log(await res.json());
})();توضیح: این رویکرد باعث میشود هدرها نه تنها realistic باشند بلکه بهروزرسانیشده نیز باشند. همیشه مراقب محدودیت درخواست (rate limit) برای endpoint API باشید و کلید API را امن نگه دارید.
نکات کلیدی برای تولید (production):
یک الگوی ساده برای جریان اجرا در ابتدای فرآیند:
// الگوی کلی (pseudo-production)
import fetch from 'node-fetch';
async function bootstrap() {
const headerList = await getHeadersList(); // از قبل تعریف شده
for (const url of ['https://example.com/a', 'https://example.com/b']) {
const headers = pickRandom(headerList);
try {
const res = await fetch(url, { method: 'GET', headers });
if (res.status === 200) {
const data = await res.text();
// پردازش داده
} else if (res.status === 429) {
// rate limited — backoff
} else {
// لاگ خطا و تحلیل
}
} catch (err) {
// retry logic یا لاگ
}
// تأخیر تصادفی بین درخواستها
await new Promise(r => setTimeout(r, 500 + Math.random() * 1500));
}
}
bootstrap();توضیح: در این الگو مدیریت وضعیتها (200, 429, 5xx) و تاخیر بین درخواستها اهمیت بالایی دارد تا الگوهای رباتمانند ایجاد نشود.
مدیریت User-Agentها و هدرهای مرورگر بخش حیاتی از طراحی یک اسکریپر قابل اعتماد است. مراحل عملی خلاصه شده:
با رعایت این اصول، احتمال بلاک شدن بهشدت کاهش پیدا میکند و پایداری اسکریپر شما بهتر خواهد شد.


