

ارسال فرمها (form submission) یکی از پایهایترین عملیات در وب است و در اتوماسیون، تست و وب اسکریپینگ کاربرد فراوان دارد. در این مقاله قدمبهقدم روشهای مختلف ارسال فرم در محیط NodeJS را بررسی میکنیم: از درخواستهای ساده HTTP با Axios و node-fetch تا اتوماسیون مرورگر با Puppeteer و Playwright و روشهای اسکریپ با Cheerio. در پایان باید بتوانید برای هر سناریو روش مناسب، نکات امنیتی، و تکنیکهای افزایش پایداری را انتخاب کنید.
یک فرم HTML به طور معمول شامل فیلدهای ورودی، دکمهها و گاهی تگهای خاص برای آپلود فایل و CSRF token است. سرور معمولاً دادهها را از طریق HTTP POST یا GET دریافت میکند — POST برای ارسال داده در body مناسبتر و امنتر است.
مثال ساده HTML فرم (برای فهم ساختار):
<form action='/submit' method='post'>
<label for='username'>Username:</label>
<input type='text' id='username' name='username' />
<label for='password'>Password:</label>
<input type='password' id='password' name='password' />
<input type='submit' value='Submit' />
</form>
نکته: وقتی فرم بهصورت multipart/form-data ارسال میشود (مثلاً آپلود فایل)، باید headerها و بادی را به شکل صحیح تنظیم کنید تا سرور فایل را دریافت کند.
Axios یک کتابخانهٔ محبوب برای HTTP در NodeJS است که API ساده و امکاناتی مثل interceptors، timeout و پشتیبانی از JSON را فراهم میکند.
const axios = require('axios');
const url = 'https://example.com/api/login';
const formData = { username: 'user123', password: 'secret' };
axios.post(url, formData)
.then(response => {
console.log('Status:', response.status);
console.log('Body:', response.data);
})
.catch(err => {
console.error('Request failed:', err.message);
});
توضیح: ورودی این تابع url و formData است. خروجی در response قرار دارد. هر خط کد به طور خلاصه:
axios.interceptors.request.use(config => {
// اینجا میتوانید توکن احراز هویت یا user-agent را به همهٔ درخواستها اضافه کنید
config.headers.Authorization = `Bearer ${getToken()}`;
config.headers['User-Agent'] = 'MyScraper/1.0';
return config;
}, err => Promise.reject(err));
// سپس همان axios.post را فراخوانی کنید
نکتهٔ عملی: از interceptor برای مرکزی کردن مدیریت توکن، تلاش مجدد روی خطاهای 401 یا اضافه کردن اطلاعات لاگ استفاده کنید.
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
const url = 'https://example.com/upload';
const form = new FormData();
form.append('file', fs.createReadStream('/path/to/file'));
form.append('description', 'my file');
axios.post(url, form, { headers: form.getHeaders(), maxContentLength: Infinity })
.then(res => console.log('Uploaded:', res.status))
.catch(err => console.error('Upload error:', err.message));
توضیح: FormData یک استریم میسازد و form.getHeaders() هدرهای مناسب multipart را فراهم میکند. برای فایلهای بزرگ از stream و تنظیم مناسب maxContentLength استفاده کنید.
node-fetch پیادهسازیای شبیه fetch مرورگر در NodeJS است؛ سبک و مناسب برای کارهای ساده و همزمانی با Promise.all.
const fetch = require('node-fetch');
async function submitForm(username, password) {
const res = await fetch('https://example.com/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
if (!res.ok) throw new Error(`Status ${res.status}`);
return res.text();
}
async function main() {
const users = [ ['u1','p1'], ['u2','p2'], ['u3','p3'] ];
const promises = users.map(([u,p]) => submitForm(u,p));
const results = await Promise.allSettled(promises);
console.log(results);
}
main();
نکتهها: باید وضعیت HTTP را دستی بررسی کنید چون node-fetch بهطور پیشفرض خطا برای 4xx/5xx پرتاب نمیکند. برای بارهای بالاتر، محدودیت همزمانی (pooling) یا صفبندی لازم است.
برای فرمهایی که با جاوااسکریپت بهطور داینامیک ساخته میشوند یا دارای کنترلهای پیچیدهاند، بهتر است مرورگر را شبیهسازی کنید. Puppeteer به شما اجازه میدهد صفحه را بارگذاری، المانها را پیدا، پر و فرم را submit کنید.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com/login', { waitUntil: 'networkidle2' });
await page.type("input[name='username']", 'myuser');
await page.type("input[name='password']", 'mypassword');
await page.click("button[type='submit']");
// اگر فرم با AJAX ارسال میشود، منتظر پاسخ سرور یا تغییر DOM باشید
await page.waitForSelector('#welcome', { timeout: 5000 }).catch(()=>{});
await browser.close();
})();
توضیح: در این مثال ورودیها و کلیک شبیه رفتار کاربر انجام میشود. از waitForSelector برای همگامسازی با المانهایی که بعداً بارگذاری میشوند استفاده کنید.
// داخل context صفحه اجرا میشود
await page.evaluate(async () => {
const formData = new FormData(document.querySelector('form'));
const res = await fetch('/api/submit', { method: 'POST', body: formData });
return res.json();
});
مزیت: اجرای کد در فضای صفحه باعث میشود تمام کوکیها، توکنها و هدرهای مورد نیاز بهطور خودکار لحاظ شوند. معایب: پیدا کردن خطاها کمی سختتر است و نیاز به serialize کردن نتایج دارید.
Playwright مشابه Puppeteer است اما پشتیبانی رسمی از Chromium، Firefox و WebKit را دارد — برای تست و اسکریپینگ cross-browser مناسب است.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com/login');
await page.fill("input[name='username']", 'demo');
await page.fill("input[name='password']", 'demo');
await page.click("button[type='submit']");
await browser.close();
})();
برای دیباگ میتوانید headless: false یا slowMo را فعال کنید تا گامها آهسته اجرا شوند و رفتار را ببینید.
اگر هدف فقط خواندن و ارسال فرم (بدون اجرای JS پیچیده) باشد، ترکیب Axios و Cheerio بسیار سبک و سریع است.
const axios = require('axios');
const cheerio = require('cheerio');
axios.get('https://example.com/login')
.then(res => {
const $ = cheerio.load(res.data);
const form = $('form').first();
const data = {};
form.find('input').each((i, el) => {
const name = $(el).attr('name');
if (name) data[name] = $(el).val() || '';
});
console.log('Parsed form data:', data);
});
کاربرد: گرفتن مقادیر hidden مانند CSRF token و سپس ارسال آنها با یک POST ساده.
NightmareJS برای اتوماسیونهایی که به render واقعی صفحه و تعاملات ساده نیاز دارند مناسب است؛ سینتکس آن زنجیروار (chain) است و استفادهٔ سریعی دارد.
const Nightmare = require('nightmare');
const nightmare = Nightmare({ show: false });
nightmare
.goto('https://example.com/login')
.type('#username', 'practice')
.type('#password', 'pass')
.click('#login button')
.wait('#welcome')
.end()
.then(() => console.log('Submitted'))
.catch(err => console.error(err));
نکته CSRF: ابتدا صفحه را بارگذاری کرده و مقدار توکن را استخراج کنید، سپس آن را در درخواست ارسال قرار دهید.
برای فرمهای ساده و APIها، Axios یا node-fetch کافی و سریع است. برای فرمهای دینامیک یا نیاز به تعامل با جاوااسکریپت صفحه، از Puppeteer یا Playwright استفاده کنید. برای اسکریپینگ سبکِ HTML بهصورت سرور-به-سرور، ترکیب Axios و Cheerio مناسب است. در نهایت، همیشه مدیریت خطا، زمانبندی مناسب، و رعایت قوانین سایت را در طراحی اسکریپ خود لحاظ کنید.
برای پیادهسازی عملی: 1) با یک فرم ساده شروع کنید، 2) خطاها و timeout را اضافه کنید، 3) اگر نیاز به اجرای جاوااسکریپت صفحه دارید به سراغ Puppeteer/Playwright بروید، و 4) در مراحل بعد پراکسی، لاگ و مانیتورینگ را اضافه کنید.

