مقدمه
در این راهنمای عملی برای توسعهدهندههای پایتون، تکنیکها و تصمیمهایی را میبینیم که هزینههای یک پروژه وب اسکریپینگ را به شکل چشمگیری کاهش میدهد. در پایان این مطلب شما میآموزید چگونه بین درخواست HTTP و مرورگر headless تصمیم بگیرید، نوع و مدل قیمتگذاری پروکسی مناسب را انتخاب کنید، پهنای باند و تعداد درخواستها را کم کنید و زیرساخت را بهینهسازی و پایش کنید.
درک انواع هزینهها
هزینههای اسکریپینگ را میتوان به سه دسته اصلی تقسیم کرد:
- محاسباتی: مصرف CPU و RAM برای پارسینگ، اجرای جاوااسکریپت و پردازش داده.
- پهنای باند: حجم داده انتقالی که خصوصا در مدلهای پرداخت بر اساس ترافیک مهم است.
- زیرساخت: هزینه سرورها، ذخیرهسازی، نگهداری و توسعه و نگهداری کد.
پیش از شروع، محدوده پروژه، فرکانس بهروزرسانی، حجم داده و نیاز به geo-targeting را مشخص کنید تا راهکارها را متناسب انتخاب کنید.
روش 1: استفاده از درخواستهای HTTP به جای مرورگرهای headless
اگر صفحه فقط HTML یا JSON ساده برمیگرداند، استفاده از HTTP requests بسیار سبکتر و ارزانتر از اجرای یک مرورگر headless است. مرورگرها مانند Selenium یا Playwright زمانی لازماند که محتوای صفحه با جاوااسکریپت رندر میشود یا نیاز به تعامل (کلیک، فرم) دارید.
مزایا و محدودیتها:
- مزایا: مصرف منابع کمتر، نگهداری سادهتر، سرعت بالاتر.
- محدودیت: نمیتوانند همیشه محتوای رندرشده توسط جاوااسکریپت را بدست آورند.
نمونه ساده درخواست با requests (ورودی: url، خروجی: شیء response):
import requests
url = 'https://example.com'
sess = requests.Session()
resp = sess.get(url, timeout=10)
if resp.status_code == 200:
html = resp.text
# پردازش html با پارسر مناسب
else:
# هندل خطا
print('status', resp.status_code)توضیح خط به خط: requests.Session اتصال را نگه میدارد، get صفحه را میگیرد، بررسی وضعیت انجام میشود و سپس متن HTML برای پارسینگ آماده میشود.
اگر مجبور به استفاده از مرورگر headless هستید، سعی کنید بار اضافی مثل تصاویر و فونتها را غیرفعال کنید تا هزینه کاهش یابد. مثال کاهش لود تصاویر در Selenium:
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--blink-settings=imagesEnabled=false')
# اجرای مرورگر با گزینهها
driver = webdriver.Chrome(options=options)
driver.get('about:blank')
# سپس url هدف را باز کنیدتوضیح: با اضافه کردن آرگومان، مرورگر تصاویر را لود نمیکند که پهنای باند و زمان بارگذاری را کاهش میدهد. توجه داشته باشید که غیرفعالسازی جاوااسکریپت ممکن است محتوای مورد نیاز را از بین ببرد.
روش 2: انتخاب نوع پروکسی مناسب
اگر پروژه شامل تعداد زیاد درخواست یا نیاز به geo-targeting است، پروکسی ضروری است. سه مدل قیمتگذاری رایج:
- پرداخت به ازای IP
- پرداخت به ازای گیگابایت
- پرداخت به ازای درخواست موفق
چه زمانی کدام مدل؟
- اگر احتمال بلاک شدن کم است و IPهای محدود کافیاند، مدل پرداخت به ازای IP اقتصادی است.
- اگر تعداد زیادی درخواست کوچک دارید، پرداخت به ازای GB ممکن است مناسبتر باشد.
- اگر بسیاری از درخواستها ممکن است شکست بخورند، پرداخت به ازای درخواست موفق هزینه هدررفته را کاهش میدهد.
انواع پروکسیها و کاربردشان:
- Datacenter: سریع و ارزان، مناسب سایتهای ساده، اما قابلشناساییتر.
- Residential: سختتر قابل بلاک شدن، مناسب سایتهای حساس، هزینه و تاخیر بالاتر.
- Mobile: شبیه ترافیک موبایل، بسیار مقاوم در برابر بلاک، گران و کندتر.
نکته عملی: ابتدا اولویتهای پروژه (پهنای باند، تعداد درخواست، تنوع IP) را مشخص کنید و سپس مدل و نوع پروکسی را انتخاب کنید.
روش 3: پیدا کردن ارائهدهنده مناسب پروکسی
پس از تعیین نوع پروکسی، ارائهدهنده را بر اساس معیارهای زیر مقایسه کنید: قیمت واقعی در بار واقعی، پایداری، نرخ خطا، پشتیبانی و مدل قیمتگذاری. اختلاف قیمت بین ارائهدهندگان برای عملکرد مشابه میتواند بسیار زیاد باشد؛ تست در محیط واقعی ضروری است.
نمونه ساده برای درخواست به یک «پروکسی-اجرتور» (ورودی: api_key و url، خروجی: محتوای پروکسی شده):
import requests
AGG_URL = 'PROXY_AGGREGATOR_ENDPOINT' # آدرس را با مقدار ارائهدهنده جایگزین کنید
params = {'api_key': 'YOUR_API_KEY', 'url': 'http://target.example.com'}
resp = requests.get(AGG_URL, params=params, timeout=15)
print('status', resp.status_code)
print('body length', len(resp.content))توضیح: این کد یک درخواست به سرویس اجرتور میزند که خودش بهترین پروکسی را انتخاب میکند. ورودیها api_key و url هدفاند، خروجی محتوا و وضعیت HTTP است. همیشه مقادیر timeout و هندلینگ خطا را اضافه کنید.
روش 4: محدود کردن تعداد درخواستها
دو عامل اصلی هزینه را کاهش دهید: تعداد درخواستها و پهنای باند.
بیشترین داده در هر درخواست: در صورتی که صفحه لیست آیتمها (مثلاً صفحه نتایج جستجو) چندین رکورد را برمیگرداند، از آن استفاده کنید تا به جای ضربه زدن به هر صفحه آیتم، چندین داده را در یک درخواست بگیرید. دنبال پارامترهایی مثل results_per_page یا limit باشید.
اسکرول بینهایت: اگر سایت از infinite scroll استفاده میکند، ابتدا بررسی کنید آیا API داخلی برای دریافت داده وجود دارد. در صورت نبود API، از مرورگر headless برای اسکرول اتومات و سپس استخراج HTML استفاده کنید، اما تنها وقتی که ناگزیر هستید.
کشینگ و conditional requests: از If-Modified-Since و هدرهای ETag استفاده کنید تا تنها در صورت تغییر محتوا صفحه را دانلود کنید.
نمونه ریت لیمیت و ریترای منطقی با requests و urllib3:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[429,500,502,503,504])
session.mount('https://', HTTPAdapter(max_retries=retries))
resp = session.get('https://example.com/api', timeout=10)
توضیح: ورودی URL و session، خروجی response. Retry با backoff از ارسال سریع و پیدرپی درخواستهای ناموفق جلوگیری میکند که هم بلاک شدن را کم میکند و هم هزینههای اضافی را کاهش میدهد.
روش 5: کاهش پهنای باند
اگر هزینه بر اساس ترافیک است، این روشها مؤثرند:
- چک کردن هدر Last-Modified با یک درخواست HEAD قبل از GET کامل.
- درخواست فشردهشده با Accept-Encoding: gzip.
- استفاده از API در صورت وجود به جای دانلود کل صفحات HTML.
نمونه بررسی Last-Modified:
import requests
url = 'https://target.example.com/page'
head = requests.head(url, timeout=8)
if 'Last-Modified' in head.headers:
print('last-modified:', head.headers['Last-Modified'])
else:
print('no last-modified header')
توضیح: این کد فقط هدرها را میگیرد؛ ورودی url، خروجی هدرها است. اگر صفحه تغییر نکرده باشد میتوانید از GET صرفنظر کنید.
نمونه درخواست با فشردهسازی gzip:
import requests
headers = {'Accept-Encoding': 'gzip'}
resp = requests.get('https://target.example.com/api', headers=headers, timeout=10)
print('content len', len(resp.content))
توضیح: با قراردادن هدر، سرور ممکن است پاسخ فشرده برگرداند که حجم داده را کاهش میدهد. کتابخانه requests به صورت خودکار فشردهسازی را مدیریت میکند.
نمونه کار با API به جای صفحات کامل (الگو):
import requests
API_URL = 'API_ENDPOINT' # آدرس API هدف
params = {'q': 'search term', 'limit': 100}
resp = requests.get(API_URL, params=params, timeout=10)
if resp.ok:
data = resp.json()
# پردازش ساختاریافته داده
توضیح: API معمولاً خروجی ساختاریافته (مثلاً JSON) میدهد که پارسینگ و مصرف منابع را کاهش میدهد.
روش 6: استفاده از سرویس ابری ارزانتر و بهینهسازی زیرساخت
مقایسه عمومی سرویسها: AWS، Azure، GCP نامهای شناختهشدهای هستند که مدل pay-as-you-go دارند؛ در مقابل DigitalOcean و Vultr نرخهای سادهتر و برای بارهای ثابت اغلب ارزانترند. برای کاهش هزینهها:
- از instanceهای سبکتر و بهینه استفاده کنید.
- در صورت امکان از spot/low-priority instances یا سرورهای bare-metal ارزان استفاده کنید.
- وظایف زمانبندیشده را در ساعات کمهزینه اجرا کنید و از autoscaling هوشمند بهره ببرید.
- از کانتینرها و توزیع بار برای استفاده بهتر از منابع استفاده کنید.
همچنین برای پروژههای کوچک، VPS یا سرورهای bare-bones میتواند هزینهها را پایین بیاورد. همیشه محاسبه هزینه شبکه و storage را جداگانه انجام دهید زیرا این موارد میتوانند هزینه اصلی باشند.
روش 7: پایش، لاگینگ و تحلیل هزینه
پایش بهموقع نشاندهنده موارد زیر است:
- نوسان غیرمنتظره در نرخ درخواست یا خطاها
- افزایش مصرف CPU یا شبکه
- نقاطی که درخواستها بدون بازده بالا هزینهبر هستند
ابزارها و تکنیکها:
- آنالیز لاگ: لاگهای درخواست/پاسخ برای نرخ خطا و الگوهای شکست.
- متریکهای عملکرد: CPU، حافظه و ترافیک شبکه.
- پیگیری هزینه: استفاده از گزارشهای billing یا ابزارهای اختصاصی برای شناسایی تراکنشهای پرهزینه.
- فریمورکها: فریمورکهایی مثل Scrapy قابلیت مانیتورینگ و آمار داخلی دارند که در بهینهسازی مفیدند.
نکته عملی: داشبوردها و آلارمها برای افزایش غیرمنتظره هزینه یا نرخ خطا بسازید تا سریع واکنش دهید و از هدررفت پول جلوگیری کنید.
جمعبندی
چند نکته عملی که باید همراه داشته باشید:
- هرگاه ممکن است از HTTP requests ساده استفاده کنید و مرورگر headless را فقط در موارد لازم بکار ببرید.
- بر اساس اولویت پروژه (پهنای باند، تعداد درخواست، یا تنوع IP) نوع و مدل قیمتگذاری پروکسی را انتخاب کنید.
- قبل از دانلود کامل صفحه، از هدرها و APIها استفاده کنید تا پهنای باند را کاهش دهید.
- از retry منطقی، rate limiting و کشینگ بهره ببرید تا درخواستهای اضافی حذف شوند.
- پایش مستمر و تحلیل هزینه را نادیده نگیرید؛ سریعترین راه برای جلوگیری از صورتحساب ناخواسته، دیدهبانی است.
با ترکیب این روشها میتوانید هزینههای پروژه اسکریپینگ را کاهش دهید و در عین حال کیفیت و پایداری استخراج داده را حفظ کنید.





