خانه/مقالات/گام‌به‌گام: ساخت و سفارشی‌سازی پروکسی با Node-Unblocker برای وب اسکریپینگ
برنامه نویسی
اتوماسیون
پروکسی و چرخش IP
برگشت به صفحه مقاله ها
گام‌به‌گام: ساخت و سفارشی‌سازی پروکسی با Node-Unblocker برای وب اسکریپینگ

گام‌به‌گام: ساخت و سفارشی‌سازی پروکسی با Node-Unblocker برای وب اسکریپینگ

در این راهنمای فارسی و فنی یاد می‌گیرید چگونه با Node-Unblocker یک پروکسی شخصی برای وب اسکریپینگ بسازید، آن را مستقر کنید، یک شبکهٔ پراکسی بسازید و با استفاده از میان‌افزارها درخواست‌ها و پاسخ‌ها را سفارشی‌سازی و بهینه کنید. همچنین بهترین‌روش‌های امنیتی، مقیاس‌پذیری و نکات عیب‌یابی مطرح شده‌اند.
امیر حسین حسینیان
امیر حسین حسینیان
1404-09-21

مقدمه

اگر می‌خواهید درخواست‌های وب‌اسکریپ خود را از آی‌پی محلی جدا کنید، از فیلترها و بلوک‌ها فرار کنید یا به محتوای جغرافیایی محدود دسترسی یابید، داشتن یک پروکسی شخصی بسیار مفید است. در این مقاله به صورت عملی و فنی گام‌به‌گام می‌سازیم، استقرار می‌کنیم، شبکه‌ای از پراکسی‌ها می‌سازیم و قابلیت‌های سفارشی‌سازی Node-Unblocker را برای بهبود عملیات وب اسکریپینگ بررسی می‌کنیم.

پس از خواندن این مقاله باید بتوانید یک سرور Node-Unblocker را راه‌اندازی کنید، آن را در محیط ابری مستقر کنید، یک شبکه پراکسی بسازید، و با استفاده از میان‌افزارها (middlewares) رفتار درخواست‌ها و پاسخ‌ها را کنترل و بهینه کنید.

چیست و چرا Node-Unblocker؟

Node-Unblocker یک کتابخانهٔ Node.js است که روی Express سوار می‌شود و وظیفهٔ proxying و بازنویسی صفحات از راه دور را بر عهده دارد. این ابزار برای مواردی مثل:

  • پنهان‌سازی هویت واقعی هنگام مرور وب،
  • وب اسکریپ کردن بدون مواجهه با محدودیت‌های آی‌پی،
  • دسترسی به محتوای جغرافیایی محدود،

مناسب است. Node-Unblocker به‌صورت REST عمل می‌کند: شما آدرس هدف را به انتهای /proxy/ اضافه می‌کنید و سرور محتوای هدف را با استفاده از آی‌پی سرور دریافت و به‌صورت استریم به کلاینت بازمی‌گرداند.

راه‌اندازی ابتدایی: نصب و ایجاد سرور

اگر با Express آشنا هستید، راه‌اندازی سرور سریع است. ابتدا وابستگی‌ها را نصب می‌کنیم.

npm init -y
npm install unblocker express

نکته: نسخهٔ Node را در محیط تولید مشخص کنید (مثلاً در package.json) تا رفتارهای متفاوت نسخه‌ها مشکلات بعدی ایجاد نکنند.

نمونهٔ app.js (شرح خط‌به‌خط)

در پوشهٔ پروژه یک فایل app.js بسازید. مثال زیر نسخهٔ مرتب و مدرن با const است:

// app.js
const express = require('express');
const Unblocker = require('unblocker');

const app = express();

// ایجاد نمونهٔ Unblocker و تعیین پیش‌شمارهٔ مسیر proxy
const unblocker = new Unblocker({
  prefix: '/proxy/' // درخواست‌ها به شکل /proxy/https://target.example.com ارسال می‌شوند
});

// فعال‌سازی middleware پروکسی
app.use(unblocker);

// مدیریت WebSocket یا تغییر پروتکل (برای مثال در استفاده از upgrade)
app.listen(process.env.PORT || 8080).on('upgrade', unblocker.onUpgrade);

console.log('Node Unblocker Server Running On Port:', process.env.PORT || 8080);

شرح مختصر نقش قطعات مهم:

  • خط اول: بارگذاری express که به عنوان وب‌سرور استفاده می‌شود.
  • خط دوم: بارگذاری unblocker (کتابخانه‌ای که عملیات proxying را انجام می‌دهد).
  • prefix: تعیین مسیر پایه‌ای که درخواست‌ها به سرور هدف ارجاع داده می‌شوند (مثلاً /proxy/).
  • app.use(unblocker): وصل‌کردن unblocker به چرخهٔ درخواست‌های Express.
  • on('upgrade', unblocker.onUpgrade): برای پشتیبانی از WebSocket یا تغییرات پروتکل مهم است؛ اگر از اتصالات بلندمدت یا وب‌سوکت استفاده می‌کنید این را فعال نگه دارید.

تست محلی

برای اجرای محلی:

node app.js

و مثال تست با curl (در ترمینال):

curl http://localhost:8080/proxy/https://www.example.com

در این حالت سرور هدف، آی‌پیِ ماشین میزبان Node-Unblocker را می‌بیند. اگر روی لوکال اجرا می‌کنید، تغییری در آی‌پی رخ نمی‌دهد؛ برای تغییر آی‌پی باید سرور را در هاست ریموت مستقر کنید.

استقرار سرور: آماده‌سازی برای Deploy

برای استقرار در سرویس‌هایی مانند Heroku باید package.json را به‌درستی تنظیم کنید تا پلتفرم بداند چگونه برنامه را اجرا کند. مثال:

{
  "name": "proxy-server",
  "version": "1.0.0",
  "main": "app.js",
  "private": true,
  "engines": {
    "node": "16.x"
  },
  "dependencies": {
    "express": "^4.17.1",
    "unblocker": "^2.3.0"
  },
  "scripts": {
    "start": "node app.js"
  }
}

یک .gitignore پایه هم بسازید تا node_modules، لاگ‌ها و فایل‌های محیطی را خارج کنید:

# Dependencies
node_modules

# yarn error logs
yarn-error.log

# Environment variables
.env*
!.env*.example

# Code coverage
coverage

دستورهای پایه برای گیت و استقرار در Heroku (یا مشابه):

git init
heroku git:remote -a your-app-name
git add .
git commit -am "first deploy"
git push heroku master

نکتهٔ مهم: سرویس‌هایی مثل Heroku یا هر VPS، آی‌پی عمومی را ارائه می‌دهند که سرور هدف آن را می‌بیند. برخی هاست‌ها آی‌پی متغیر دارند یا محدودیت‌های رایگان اعمال می‌کنند؛ قبل از مقیاس‌دهی این موارد را بررسی کنید.

ایجاد شبکهٔ پراکسی (Proxy Network)

برای شکستِ نرخ‌محدودکننده‌ها و توزیع ترافیک، می‌توانید چندین سرور Node-Unblocker در مناطق جغرافیایی مختلف مستقر کنید و در کلاینت‌ها هر درخواست را از یک سرور تصادفی بفرستید.

دو روش اصلی برای استفاده از سرورهای Unblocker در کلاینت‌ها وجود دارد:

  • ارسال مستقیم به URL شکل http://proxy-server/proxy/https://target (روش ساده و امن برای اکثر حالات).
  • استفاده از سرور به‌عنوان HTTP proxy (در صورتی که سرور و تنظیمات محیط آن این حالت را پشتیبانی کند) و تنظیم proxies در کتابخانه‌هایی مثل requests.

مثال: چرخش پراکسی‌ها با Python requests

این مثال مشابه ورودی اولیه است؛ ما فهرستی از آدرس‌های سرورهای Unblocker را می‌سازیم و آن‌ها را به‌صورت چرخان برای هر درخواست انتخاب می‌کنیم.

import requests
from itertools import cycle

# فهرست سرورهای Node-Unblocker (می‌تواند آدرس‌های کامل پروکسی یا آدرس‌های /proxy/ باشد)
proxies_list = [
  "http://100.200.30.30:8080",
  "http://100.200.30.31:8080",
  "http://100.200.30.32:8080",
]

proxy_cycle = cycle(proxies_list)

target = 'https://www.example.com'

for i in range(10):
    proxy = next(proxy_cycle)
    print('using proxy:', proxy)

    # اگر سرور شما به‌عنوان HTTP proxy کار می‌کند:
    proxies = { 'http': proxy, 'https': proxy }
    try:
        r = requests.get(target, proxies=proxies, timeout=15)
        print('status', r.status_code)
    except requests.RequestException as e:
        print('request failed:', e)

توضیحات ورودی‌ها/خروجی‌ها و نکات:

  • proxies_list: لیستی از آدرس‌های سرورهای Unblocker؛ اگر از روش مسیر /proxy/ استفاده می‌کنید، می‌توانید به‌جای proxies از ساختن URL کامل استفاده کنید.
  • هر درخواست به‌وسیلهٔ یک سرور متفاوت فرستاده می‌شود؛ باید timeouts، retry و خطایابی را حتماً اعمال کنید.
  • در production از pooling، تست سلامت (health check) و حد همزمانی برای هر سرور استفاده کنید تا از از کار افتادن سرورها جلوگیری شود.

سفارشی‌سازی با میان‌افزارها (Middlewares)

قابلیت قوی Node-Unblocker استفاده از میان‌افزارها برای دستکاری درخواست‌ها و پاسخ‌ها است. این موضوع به‌ویژه در وب اسکریپینگ با اهداف زیر مفید است:

  • اعمال هدرهای امن و استاندارد (مانند user-agent برای کاهش ریسک بلاک شدن)،
  • حذف یا اصلاح اسکریپ‌های جاوااسکریپت که مانع بارگذاری می‌شوند،
  • افزودن مکانیزم logging یا تغییر مسیر برای مدیریت session و کوکی‌ها.

مثال: Request Middleware برای تنظیم User-Agent

یک میان‌افزار ساده که هدر user-agent را برای هر درخواست تنظیم می‌کند:

// در app.js
function setUserAgent(data) {
  // data.url و data.headers در شی داده ورودی موجود هستند
  data.headers['user-agent'] = 'Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148';
}

const unblocker = new Unblocker({
  prefix: '/proxy/',
  requestMiddleware: [ setUserAgent ]
});

شرح:

  • ورودی: تابع میان‌افزار یک شی data می‌گیرد که شامل حداقل url و headers است.
  • خروجی: میان‌افزار می‌تواند هدرها، پارامترها یا سایر فیلدها را تغییر دهد؛ تغییرات قبل از ارسال درخواست به هدف اعمال می‌شوند.
  • می‌توانید شرطی بنویسید تا تنها برای دامنه‌های خاص User-Agent را تغییر دهید (مثلاً گوگل یا سایت‌های حساس).
function setUserAgentForGoogle(data) {
  if (/^https?:\/\/([\w.-]+\.)?google\.com\//i.test(data.url)) {
    data.headers['user-agent'] = 'Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148';
  }
}

مثال: Response Middleware برای اصلاح محتوای HTML (استریم)

گاهی لازم است بخش‌هایی از HTML پاسخ را اصلاح یا حذف کنیم (مثلاً اسکریپ‌هایی که BrowserCheck اجرا می‌کنند). برای پاسخ‌های متنی بهتر است از استریم استفاده کنیم تا حافظهٔ سرور بیرون نریزد.

const { Transform } = require('stream');

function replaceSnippet(config) {
  return function(data) {
    // data.contentType و data.stream در شی داده موجود است
    if (config.processContentTypes.includes(data.contentType)) {
      data.stream = data.stream.pipe(new Transform({
        decodeStrings: false,
        transform(chunk, encoding, next) {
          const updated = chunk.toString().replace(config.searchFor, config.replaceWith);
          this.push(updated, 'utf8');
          next();
        }
      }));
    }
  };
}

const unblockerWithReplace = new Unblocker({
  prefix: '/proxy/',
  responseMiddleware: [ replaceSnippet({
    processContentTypes: [ 'text/html' ],
    searchFor: /]*>\s*BrowserCheck\.testForCookies\(\)\s*<\/script>/i,
    replaceWith: ''
  }) ]
});

نکات مهم و محدودیت‌ها:

  • تعویض بر پایهٔ استریم حافظه را بهینه می‌کند، اما اگر الگو شما ممکن است بین مرزهای chunk جدا شود (دو بخش از یک الگو در دو chunk بیاید)، باید یا باکت‌کنید یا از parserهای HTML استفاده کنید.
  • پردازش استریم برای فایل‌های باینری (تصاویر، ویدیو) ممنوع است — همیشه content-type را بررسی کنید.
  • تعویض‌های سنگین متن می‌تواند CPU-bound شود؛ در مقیاس‌پذیری این را برآورد و تست کنید.

امنیت، قابلیت اطمینان و بهترین روش‌ها

  • هرگز سرور Unblocker را به‌صورت عمومی و بدون احراز هویت در دسترس نگذارید؛ یک پراکسی باز به سرعت برای سوءاستفاده استفاده می‌شود. از توکن‌های ساده، Basic auth، یا لیست آی‌پی برای محدودسازی دسترسی استفاده کنید.
  • متغیرهای محیطی (مانند کلیدها و رمزها) را در فایل کد نگه ندارید؛ از سرویس‌های مدیریت راز یا متغیرهای محیطی استفاده کنید.
  • زمان‌بندی و محدودیت نرخ (rate limiting) را روی سرور اعمال کنید تا از مصرف منابع جلوگیری شود.
  • برای پایداری از مانیتورینگ و health checks استفاده کنید؛ سرورهایی که پاسخ نمی‌دهند را از چرخهٔ انتخاب پراکسی حذف کنید.
  • درخواست‌ها را لاگ کنید اما اطلاعات حساس (توکن، کوکی) را ماسک کنید تا داده‌های حساس در لاگ ذخیره نشود.
  • به قوانین سایت‌ها، شرایط خدمات و مسائل اخلاقی و حقوقی احترام بگذارید؛ برخی سایت‌ها اسکریپ را منع می‌کنند یا داده‌ها دارای محدودیت حقوقی هستند.

عملکرد و مقیاس‌پذیری

  • Node-Unblocker جریان داده را به‌صورت استریم منتقل می‌کند که از بافرکردن کامل محتوا جلوگیری می‌کند و تا حد زیادی کارایی را حفظ می‌کند.
  • با افزایش همزمانی، I/O و پهنای‌باند تبدیل به گلوگاه می‌شود؛ برای کارهای مقیاس‌پذیر، روی لایه شبکه (سرعت NIC)، محدودیت‌های همزمانی Node.js و تنظیمات سیستم عامل تمرکز کنید.
  • برای ترافیک سنگین از چندین سرور در مناطق مختلف استفاده کنید و از load balancer یا روتینگ هوشمند برای توزیع بار بهره ببرید.

عیب‌یابی متداول

  • خطای CORS: وقتی از مرورگر به /proxy/ درخواست می‌دهید ممکن است با مشکلات CORS مواجه شوید؛ در بسیاری از موارد استفاده از سرور میانی (backend) برای فراخوانی مناسب‌تر است.
  • اشکال TLS/HTTPS: اگر هدف گواهی‌نامهٔ نامعتبر داشته باشد، اطمینان حاصل کنید که رفتار پیش‌فرض TLS را تغییر ندهید مگر با دانش کامل؛ غیرفعال کردن اعتبارسنجی گواهی ریسک امنیتی است.
  • وب‌سوکت‌ها: اگر هدف از وب‌سوکت استفاده می‌کند حتماً onUpgrade را ثبت کنید.
  • خطاهای chunked یا نیمه‌کاره: برای عملیات روی متن از parser یا جمع‌آوری کامل در صورت کوچک بودن پاسخ استفاده کنید.

جمع‌بندی

Node-Unblocker ابزار ساده و سریع برای ساخت پروکسی شخصی و بهبود تجربهٔ وب اسکریپینگ است. با راه‌اندازی پایه، استقرار در سرور ریموت و به‌کارگیری میان‌افزارها می‌توانید رفتار درخواست‌ها و پاسخ‌ها را کنترل کرده و یک زیرساخت پراکسی قابل‌تعمیم بسازید. نکات کلیدی که باید همیشه رعایت کنید عبارت‌اند از: محافظت از پراکسی (احراز هویت)، مدیریت نرخ و خطا، استفاده از health checks برای شبکهٔ پراکسی و هوشمندسازی استراتژی چرخش پراکسی‌ها.

اگر قصد تولید حجم بالای اسکریپ دارید، مرحلهٔ بعدی طراحی pipeline تست سلامت و مانیتورینگ، و ارزیابی هزینه‌ها و سیاست‌های سرویس‌دهندهٔ میزبانی است.

مقاله‌های مرتبط