مقدمه
در این راهنمای عملی میخوانید چگونه فرمهای وب را با پایتون ارسال کنید و از روشهای مختلف برای سناریوهای واقعی استفاده کنید: درخواستهای ساده HTTP، پارس کردن فرمها، اتوماسیون کامل مرورگر و راهکارهای همزمان. فرض میکنیم شما توسعهدهندهای با دانش متوسط پایتون هستید و دنبال جزئیات فنی، نمونه کد و نکات عملی برای تولید اسکریپهای قابلاعتماد هستید.
در پایان این مقاله شما خواهید دانست چه زمانی از requests استفاده کنید، چه زمانی به سراغ ابزارهای مرورگر مانند Selenium یا Playwright بروید، و چطور با مشکلات رایج مثل CSRF، فایلآپلود، احراز هویت و همزمانی برخورد کنید.
درک کلی: ارسال فرمهای HTML
فرمهای HTML از عناصر مختلفی تشکیل شدهاند: input، select، textarea و دکمهها. معمولاً فرمها با متد POST دادهها را در بدنهٔ درخواست میفرستند؛ این روش نسبت به GET امنتر و مناسبتر برای اطلاعات حساس است. بسیاری از فرمها همچنین توکنهای پنهان (مثلاً CSRF) یا هدرهای سفارشی انتظار دارند که بدون آنها درخواست رد میشود.
برای اسکریپ کردن فرمها باید سه کار اصلی انجام دهید: 1) شناسایی فیلدها و آدرس action فرم، 2) آمادهسازی دادهها و هدرها، 3) ارسال درخواست و بررسی پاسخ.
روشهای اصلی در پایتون
requests برای درخواستهای HTTP ساده و کنترل کوکیها با Session.
BeautifulSoup + requests برای استخراج فرم و توکنها.
Selenium یا Playwright برای فرمهای داینامیک که با جاوااسکریپت ساخته میشوند.
Mechanize برای تعامل شبیه به مرورگر با فرمهای ساده (قدیمیتر اما سبک).
Scrapy برای پروژههای ساختیافتهٔ اسکریپینگ با پشتیبانی از FormRequest و pipelines.
httpx و ترکیب آن با asyncio یا trio برای ارسالهای همزمان و مقیاسپذیر.
Requests و مدیریت Session
برای فرمهای سادهای که نیاز به اجرأ جاوااسکریپت ندارند، requests سریعترین و سادهترین انتخاب است. با Session میتوان کوکیها و هدرها را بین درخواستها حفظ کرد.
نمونه: ارسال POST با requests.Session و بررسی متن پاسخ.
import requests
url = 'https://example.com/login'
headers = {
'User-Agent': 'Mozilla/5.0',
'Content-Type': 'application/x-www-form-urlencoded'
}
form_data = {
'username': 'student',
'password': 'Password123'
}
session = requests.Session()
response = session.post(url, data=form_data, headers=headers, timeout=10)
if response.status_code == 200:
if "Congratulations" in response.text:
print("User logged in successfully!")
else:
print("Failed to log in: response OK but expected content missing")
else:
print(f"Failed to submit form. Status code: {response.status_code}")توضیح کد: ورودیها آدرس url، دیکشنری form_data و headers است؛ خروجی یک Response است که وضعیت و متن پاسخ را دارد. نکات خطبهخط: ایجاد Session برای مدیریت کوکی، ارسال post(...)، تعیین timeout جهت جلوگیری از بلوکه شدن اسکریپت، و بررسی کد وضعیت و محتوای پاسخ.
احراز هویت و ارسال فایل با Requests
برای Basic Auth از پارامتر auth استفاده کنید و برای توکنها، آنها را در هدر Authorization: Bearer ... قرار دهید. برای فایلها باید از پارامتر files استفاده کنید تا multipart/form-data ساخته شود.
# Basic Auth
from requests.auth import HTTPBasicAuth
resp = requests.post('https://example.com/secure-form', data=form_data,
auth=HTTPBasicAuth('user', 'pass'))
# Token-based
headers['Authorization'] = f"Bearer {os.getenv('AUTH_TOKEN')}"
resp = requests.post('https://example.com/api', data=form_data, headers=headers)
# File upload
files = {'file': open('invoice.xlsx', 'rb')}
resp = requests.post('https://example.com/upload', files=files, data={'field1':'value1'})نکات: همیشه فایلها را با حالت باینری باز کنید، و پس از ارسال آنها را ببندید یا از ساختار with استفاده کنید. توکنها را در متغیرهای محیطی نگه دارید، نه در کد.
پارس کردن فرم با BeautifulSoup
اگر فرم شامل توکنهای پنهان است یا آدرس action نسبی دارد، ابتدا صفحه را با requests.get بگیرید و سپس با BeautifulSoup فیلدها را استخراج کنید.
import requests
from bs4 import BeautifulSoup
url = 'https://example.com/login'
resp = requests.get(url)
soup = BeautifulSoup(resp.text, 'html.parser')
form = soup.find('form')
form_data = {}
for input_tag in form.find_all('input'):
name = input_tag.get('name')
if not name:
continue
value = input_tag.get('value', '')
form_data[name] = value
# پر کردن فیلدها
form_data['username'] = 'practice'
form_data['password'] = 'SuperSecretPassword!'
# محاسبهٔ آدرس action کامل
action = form.get('action')
if not action.startswith('http'):
action = requests.compat.urljoin(url, action)
resp2 = requests.post(action, data=form_data)
print(resp2.status_code)
توضیح: این الگو به شما اجازه میدهد همهٔ فیلدهای پنهان (مثل CSRF) را استخراج کنید و مطمئن شوید همهٔ پارامترهای مورد نیاز ارسال میشوند.
اتوماسیون مرورگر با Selenium
برای فرمهایی که با جاوااسکریپت ساخته یا وِریفای میشوند، از Selenium استفاده کنید. Selenium عناصر را همانند کاربر واقعی پیدا میکند و برای تعامل با popupها، iframeها و انتظارها مناسب است.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
try:
driver.get('https://practice.example.com/login')
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, 'username')))
driver.find_element(By.ID, 'username').send_keys('practice')
driver.find_element(By.ID, 'password').send_keys('SuperSecretPassword!')
driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]').click()
# Wait for a success element
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '.dashboard')))
finally:
driver.quit()
توضیح: از WebDriverWait و شرایط صریح استفاده کنید تا به جای sleepهای خام، به صورت ایمن روی وجود یا کلیکپذیری عناصر صبر کنید. برای اجرای headless، پارامترهای مربوطه را به options اضافه کنید.
Playwright برای headless و چند-مرورگری
Playwright مدرن است و پشتیبانی از Chromium/Firefox/WebKit را با API یکپارچه میدهد؛ برای اسکریپینگ فرمهای پیچیده و تست کراس-براوزر گزینهٔ مناسبی است.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto('https://demo.example.com/login')
page.fill("input[name='username']", 'demo')
page.fill("input[name='password']", 'demo')
page.click("button[type='submit']")
# منتظر یک سلکتور موفقیت باشید
page.wait_for_selector('.welcome')
browser.close()
نکته: Playwright سریع و قابلاعتماد است؛ برای اشکالزدایی میتوانید headless=False و slow_mo استفاده کنید.
Mechanize برای فرمهای ساده
Mechanize رابطی شبیه مرورگر فراهم میکند و برای فرمهای ساده و سایتهای بدون جاوااسکریپت مناسب است. اگر نیاز دارید خیلی سبک و بدون درگیری WebDriver باشید، مناسب است.
import mechanize
br = mechanize.Browser()
br.open('https://practice.example.com/login')
br.select_form(nr=0)
br['username'] = 'practice'
br['password'] = 'SuperSecretPassword!'
resp = br.submit()
print(resp.read().decode('utf-8'))
محدودیت: Mechanize جاوااسکریپت را اجرا نمیکند و در مواجهه با فرمهای داینامیک یا محافظتشده مناسب نیست.
Scrapy: فرمها در پروژههای اسکریپینگ ساختاریافته
برای پروژههای بزرگ با نیاز به pipeline و مدیریت درخواستها، از Scrapy و FormRequest.from_response استفاده کنید.
import scrapy
class FormSpider(scrapy.Spider):
name = 'form_spider'
start_urls = ['https://practice.example.com/login']
def parse(self, response):
formdata = {'username': 'practice', 'password': 'SuperSecretPassword!'}
yield scrapy.FormRequest.from_response(response, formdata=formdata, callback=self.after_login)
def after_login(self, response):
if b'authentication failed' in response.body:
self.logger.error('Login failed')
return
self.logger.info('Successfully logged in and submitted the form')
مزیت Scrapy مدیریت خودکار نرخ درخواست، میانجیها (middlewares) و pipelines برای پردازش داده است.
HTTPX و کار با همزمانی (asyncio / trio)
برای مقیاسپذیری و همزمانی از httpx استفاده کنید. این کتابخانه هم synchronous و هم async با API شبیه requests ارائه میدهد. ترکیب با trio یا asyncio برای ارسالهای همزمان مفید است.
# نمونه با httpx + asyncio
import httpx
import asyncio
async def submit_form():
async with httpx.AsyncClient() as client:
resp = await client.post('https://example.com/login', data={'username':'student','password':'Password123'}, timeout=10)
print(resp.status_code)
asyncio.run(submit_form())
برای حجم بالای همزمانی، trio میتواند کارآمدتر باشد اما پیچیدگی کدنویسی افزایش مییابد. همیشه از محدودیتهای سرور و سیاستهای سایت آگاه باشید.
نکات عملی، امنیت و بهترینروشها
همیشه از هدر مناسب مثل User-Agent استفاده کنید و توکنها را در محیط اجرا (env vars) نگهدارید.
از زمانسنجیهای هوشمند (exponential backoff) و retry برای خطاهای موقتی استفاده کنید؛ از بستههایی مثل tenacity میتوان بهره برد.
برای ارسال فایلها و دادههای حساس از TLS/HTTPS استفاده کنید و گواهیها را اعتبارسنجی نمایید.
برای سایتهایی با محدودیت درخواست یا CAPTCHA از پراکسیها، مدیرت نرخ (rate limiting) و سرویسهای خبره استفاده کنید، اما همیشه سیاستهای سایت را مراعات کنید.
اگر فرمها شامل CSRF هستند، ابتدا صفحه را GET کنید و توکن را استخراج کنید؛ سپس توکن را همراه فرم ارسال کنید.
برای اشکالزدایی: لاگینگ دقیق، ذخیرهٔ هدرها و پاسخها و اجرای headful (non-headless) برای مشاهدهٔ رفتار مرورگر مفید است.
جمعبندی
انتخاب ابزار وابسته به پیچیدگی فرم و نیازهای پروژه است: برای فرمهای ساده requests و BeautifulSoup کفایت میکنند؛ برای فرمهای جاوااسکریپتی به Selenium یا Playwright نیاز دارید؛ برای پروژههای مقیاسپذیر و همزمان httpx و ترکیب با asyncio یا trio مناسباند. همیشه به امنیت، مدیریت خطا و احترام به قوانین سایت توجه کنید تا اسکریپهای پایدار و اخلاقی بسازید.





