خانه/مقالات/اسکریپینگ فرم‌ها با requests در پایتون
برنامه نویسی
سلنیوم
beautifulsoup
برگشت به مقاله‌ها

اسکریپینگ فرم‌ها با requests در پایتون

اسکریپینگ فرم‌ها با requests در پایتون
این مقاله راهنمای عملی و فنیِ اسکریپینگ فرم‌ها با کتابخانهٔ requests در پایتون است: از ارسال GET/POST و آپلود فایل تا مدیریت جلسه، استخراج CSRF با BeautifulSoup، ترکیب با Selenium برای فرم‌های جاوااسکریپتی و نکات امنیتی، retry و rate limiting را پوشش می‌دهد؛ همراه نمونه‌کدهای واضح و توصیه‌های اخلاقی.
آسان اسکریپ آسان اسکریپ
1405-05-18

مقدمه

در این مقاله قدم‌به‌قدم یاد می‌گیرید چطور فرم‌های وب را با کتابخانهٔ requests در پایتون به‌صورت برنامه‌ریزی‌شده ارسال کنید. تمرکز روی نمونه‌های عملی، نکات امنیتی، مدیریت نشست (session)، استخراج فیلدهای مخفی مثل CSRF، آپلود فایل و راهکارهایی برای فرم‌های مبتنی بر جاوااسکریپت است. در پایان شما قادر خواهید بود فرم‌های ساده تا پیچیده را با رعایت بهترین‌روش‌ها و خطایابی مناسب خودکار کنید.

شروع سریع (TL;DR)

برای ارسال فرم ساده از requests.post استفاده کنید و داده‌ها را به صورت دیکشنری در پارامتر data قرار دهید. برای نگهداری کوکی‌ها و reuse اتصال‌ها از requests.Session بهره ببرید. همواره timeout و retry مناسب تنظیم کنید و فیلدهای مخفی یا توکن‌های CSRF را پیش از ارسال استخراج کنید.

ارسال فرم‌های ساده: GET و POST

ایدهٔ کلی: فرم‌هایی که از GET استفاده می‌کنند داده‌ها را در query string می‌فرستند و فرم‌های POST داده‌ها را در بدنهٔ درخواست قرار می‌دهند.

import requests

# GET: ارسال پارامترها در URL
url = 'https://example.com/search'
params = {'query': 'python requests'}
response = requests.get(url, params=params, timeout=10)
print(response.status_code)
print(response.text[:200])

شرح: ورودی‌ها عبارتند از url و دیکشنری params. خروجی یک شیء Response است؛ با response.text یا response.json() می‌توانید محتوا را بخوانید.

# POST: ارسال فرم در بدنه
url = 'https://example.com/login'
data = {'username': 'alice', 'password': 's3cr3t'}
response = requests.post(url, data=data, timeout=10)
if response.status_code == 200:
    print('Sent, response length:', len(response.content))
else:
    print('Failed:', response.status_code)

نکته: برای APIهایی که انتظار JSON دارند از پارامتر json=... استفاده کنید تا requests خودکار Content-Type را تنظیم کند.

هدرها، کوکی‌ها و آپلود فایل

بعضی فرم‌ها برای پذیرفتن درخواست به هدرها یا کوکی‌های خاص نیاز دارند (مثلاً User-Agent یا Referer). همچنین برای ارسال فایل باید از پارامتر files استفاده شود.

# اضافه کردن هدر و کوکی
url = 'https://example.com/submit'
headers = {'User-Agent': 'Mozilla/5.0', 'Referer': 'https://example.com/form'}
cookies = {'session_id': 'abcd1234'}
response = requests.post(url, data={'field': 'value'}, headers=headers, cookies=cookies)
print(response.status_code)

# آپلود فایل
url = 'https://example.com/upload'
with open('document.pdf', 'rb') as f:
    files = {'file': ('document.pdf', f, 'application/pdf')}
    response = requests.post(url, files=files)
    print(response.status_code)

توضیح: پارامتر files یک دیکشنری است که هر مقدار می‌تواند تاپل (نام فایل, file-object, mime-type) باشد. استفاده از with تضمین می‌کند فایل به درستی بسته شود.

مدیریت جلسه، تایم‌اوت و استراتژی retry

برای نگهداری کوکی‌ها و reuse ارتباط TCP، از requests.Session استفاده کنید. همچنین برای پایداری شبکه تایم‌اوت و مکانیزم retry لازم است.

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()
session.headers.update({'User-Agent': 'Mozilla/5.0'})

# تنظیم Retry روی آداپتر
retry_strategy = Retry(total=5, backoff_factor=0.3,
                       status_forcelist=[429, 500, 502, 503, 504])
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount('https://', adapter)
session.mount('http://', adapter)

try:
    resp = session.post('https://example.com/form', data={'a': 'b'}, timeout=10)
    resp.raise_for_status()
except requests.exceptions.RequestException as e:
    print('Request failed:', e)
else:
    print('OK', resp.status_code)

شرح: Retry تعیین می‌کند در چه شرایطی درخواست تکرار شود و backoff_factor تأخیر را افزایش می‌دهد. همیشه timeout تنظیم کنید تا اسکریپت شما در حالت تعلیق نماند.

استخراج CSRF و فیلدهای مخفی

اغلب فرم‌ها توکن‌هایی مثل CSRF دارند که باید قبل از ارسال استخراج شوند. پیاده‌سازی معمول این است که ابتدا صفحهٔ فرم را با GET بگیرید و سپس با کتابخانه‌ای مثل BeautifulSoup فیلدهای مخفی را بخوانید.

import requests
from bs4 import BeautifulSoup

url = 'https://example.com/form_page'
resp = requests.get(url, timeout=10)
soup = BeautifulSoup(resp.text, 'html.parser')
# پیدا کردن همه inputهای hidden
hidden = {inp['name']: inp.get('value', '')
          for inp in soup.find_all('input', {'type': 'hidden'}) if inp.has_attr('name')}
# آماده‌سازی data
data = hidden
data.update({'username': 'bob', 'password': 'pw'})
# ارسال فرم
submit_url = soup.find('form')['action'] if soup.find('form') else url
response = requests.post(submit_url, data=data)
print(response.status_code)

نکتهٔ عملی: گاهی فیلدهای CSRF در متادیتا یا جاوااسکریپت تعبیه شده‌اند؛ بدقت HTML و درخواست‌های شبکه را در DevTools بررسی کنید.

فرم‌های جاوااسکریپتی و ترکیب Selenium با requests

اگر فرم یا فیلدها با جاوااسکریپت ساخته می‌شوند، requests به‌تنهایی کافی نیست. گزینهٔ معمول ترکیب Selenium برای اجرای جاوااسکریپت و گرفتن کوکی‌ها/توکن‌ها و سپس استفاده از requests.Session برای ارسال نهایی است.

# نمونهٔ سادهٔ انتقال کوکی از Selenium به requests
from selenium import webdriver
import requests

driver = webdriver.Chrome()
driver.get('https://example.com/login')
# ... پر کردن فرم و لاگین در Selenium ...
# گرفتن کوکی‌ها
cookies = driver.get_cookies()  # لیستی از دیکشنری‌ها
session = requests.Session()
for c in cookies:
    session.cookies.set(c['name'], c['value'])
# حالا با session می‌توانیم درخواست‌های requests را بزنیم
resp = session.get('https://example.com/dynamic_form')
print(resp.status_code)
driver.quit()

توضیح: با این روش از قدرت رندرینگ Selenium برای دریافت توکن‌ها و از کارایی requests برای ارسال دسته‌ای بهره می‌بریم.

حل CAPTCHA و ملاحظات اخلاقی

CAPTCHA به‌صراحت برای جلوگیری از خودکارسازی ساخته شده است. هرگز بدون اجازه کوشش به دور زدن CAPTCHA نکنید. در پروژه‌های مجاز می‌توان از سرویس‌های ثالث برای حل CAPTCHA استفاده کرد، اما هزینه، تاخیر و ریسک‌های قانونی/اخلاقی را در نظر بگیرید.

# الگوی کلی: ارسال تصویر یا sitekey به سرویس حل CAPTCHA (نمایشی)
# اگر دسترسی و اجازه دارید، باید API سرویس را طبق مستندات آن استفاده کنید.

نکتهٔ مهم: همواره مستندات سایت هدف و قوانین حاکم را بررسی کنید و برای دسترسی‌های خودکار از مالک سایت کسب اجازه نمایید.

نکات عملی و عیب‌یابی (Troubleshooting)

  • Element Not Found: ممکن است selector اشتباه باشد یا عنصر پس از بارگذاری AJAX ساخته شود — از waits یا بررسی شبکه استفاده کنید.
  • Form Not Submitting: آدرس action، فیلدهای ارسالی یا توکن‌ها ناقص‌اند؛ درخواست‌های شبکه در DevTools را بازسازی کنید.
  • Timeouts و Network Errors: timeout منطقی تعیین کنید و از retry/HTTPAdapter استفاده کنید.
  • Rate Limiting و Throttling: برای جلوگیری از بن شدن IP از تأخیر بین درخواست‌ها (time.sleep) یا صف‌بندی استفاده کنید.
# مثال سادهٔ rate limiting
import time
for i in range(5):
    r = requests.post('https://example.com/submit', data={'i': i})
    print(r.status_code)
    time.sleep(1.5)  # صبر بین درخواست‌ها

بهترین‌روش‌ها

  • هرگز کلیدها یا رمزها را هاردکُد نکنید؛ از متغیرهای محیطی یا vault استفاده کنید.
  • همواره از HTTPS استفاده کنید تا داده‌های حساس رمزنگاری شوند.
  • منطق retry با backoff و لاگ دقیق پیاده‌سازی کنید تا خطاها قابل تحلیل باشند.
  • قبل از اسکریپ‌کردن، شرایط استفاده و robots.txt سایت را بررسی کنید و در صورت نیاز از صاحب سایت اجازه بگیرید.

جمع‌بندی

ارسال فرم‌ها با requests در پایتون از موارد پایه تا پیچیده قابل انجام است: فرم‌های ساده را با post و get می‌فرستیم، برای فیلدهای مخفی از BeautifulSoup استفاده می‌کنیم، برای فرم‌های جاوااسکریپتی ترکیب Selenium و requests مناسب است و برای پایداری از Session، timeout و retry بهره می‌بریم. همواره ملاحظات امنیتی، قانونی و اخلاقی را رعایت کنید.

اگر می‌خواهید، می‌توانم یک قالب آمادهٔ اسکریپت برای یک فرم خاص شما بسازم یا در مورد استخراج دقیق CSRF از صفحهٔ هدف کمک کنم.

مطالب مرتبط

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