بازگشت به وبلاگ

چقدر ترافیک GB Playwright، Puppeteer و requests برای 1000 صفحه مصرف می‌کند: محاسبه برای پروکسی

در این مقاله بررسی می‌کنیم که Playwright، Puppeteer و requests در هنگام پارس کردن 1000 صفحه چه مقدار ترافیک واقعی مصرف می‌کنند و چگونه می‌توان بدون از دست دادن داده‌ها، مصرف ترافیک پروکسی را کاهش داد.

📅۲۷ شهریور ۱۴۰۵

اگر شما برای ترافیک پروکسی بر اساس GB پرداخت می‌کنید، تفاوت بین مرورگر headless و یک کلاینت HTTP معمولی می‌تواند 15-20 برابر بیشتر از یک دیتاست مشابه از 1000 صفحه هزینه داشته باشد. در این مقاله — اندازه‌گیری‌های واقعی مصرف ترافیک برای Playwright، Puppeteer و کتابخانه Python requests، کد برای آزمایش‌ها و روش‌های عملی برای کاهش حجم داده‌ها بدون از دست دادن محتوا ارائه شده است.

چرا مصرف ترافیک برای پارس کردن حیاتی است

بیشتر ارائه‌دهندگان پروکسی، از جمله استخرهای مقیم و موبایل، ترافیک را بر اساس GB محاسبه می‌کنند، نه بر اساس تعداد درخواست‌ها. این بدان معناست که ابزاری که با آن سایت را پارس می‌کنید، به طور مستقیم بر روی بودجه پروژه تأثیر می‌گذارد. مرورگر headless صفحه را به طور کامل بارگذاری می‌کند: HTML، CSS، JavaScript، تصاویر، فونت‌ها، اسکریپت‌های تحلیلی، بنرهای تبلیغاتی و ردیاب‌ها. کلاینت HTTP مانند requests تنها آنچه را که به وضوح درخواست کرده‌اید دانلود می‌کند — معمولاً این یک سند HTML خالص است.

تفاوت به ویژه در مقیاس قابل توجه است. اگر شما کارت‌های محصول را در Wildberries یا Ozon پارس می‌کنید، قیمت‌های رقبای خود را جمع‌آوری می‌کنید یا نتایج Google را نظارت می‌کنید، حجم 1000 صفحه یک نرمال روزانه برای یک اسکریپت است. هنگامی که با چند صد هزار صفحه در ماه کار می‌کنید، صرفه‌جویی در ترافیک به یک هزینه قابل توجه تبدیل می‌شود، به ویژه اگر از پروکسی‌های مقیم استفاده شود که هزینه GB آن‌ها بیشتر از دیتاسنترها است.

پیچیدگی اضافی این است که سایت‌های مدرن به طور فعال در برابر ربات‌ها محافظت می‌شوند: رندرینگ JavaScript، رفتار ماوس، fingerprint canvas را بررسی می‌کنند. این باعث می‌شود که توسعه‌دهندگان از درخواست‌های ساده HTTP به مرورگرهای کامل مانند Playwright یا Puppeteer که در ترافیک بسیار بیشتر هستند، منتقل شوند. درک اعداد دقیق به محاسبه بودجه پروکسی و انتخاب ابزار مناسب برای وظیفه خاص کمک می‌کند.

روش اندازه‌گیری ترافیک

برای مقایسه عادلانه، من از یک لیست یکسان از 1000 URL استفاده کردم — کارت‌های محصولات با پیچیدگی متوسط با تصاویر، اسکریپت‌های تحلیلی و چندین ویجت خارجی (ساختار معمول برای سایت‌های تجارت الکترونیک). اندازه‌گیری ترافیک از طریق مانیتور سیستم شبکه و ابزارهای داخلی لاگ‌گذاری درخواست‌ها در هر ابزار انجام شد.

شرایط مهم آزمایش:

  • کش مرورگر خاموش است — هر صفحه "از صفر" بارگذاری می‌شود، همانطور که در هنگام کار با چرخش پروکسی با IP‌های مختلف اتفاق می‌افتد
  • حالت headless در تمام آزمایش‌های مرورگر فعال است — اینگونه است که بیشتر اسکریپت‌های تولیدی کار می‌کنند
  • بدون مسدود کردن منابع در سناریوی پایه — برای نشان دادن مصرف "خالص" بدون بهینه‌سازی‌ها
  • یک شبکه و یک مجموعه صفحه یکسان برای هر سه ابزار

این رویکرد اعداد قابل مقایسه‌ای را ارائه می‌دهد که می‌توانید به مورد خود اعمال کنید — با ضرب کردن در تعداد صفحات در پروژه خود و تقسیم بر حجم تعرفه پروکسی.

requests: حداقل مصرف ترافیک

کتابخانه requests در Python تنها بدنه پاسخ HTTP را دانلود می‌کند — آنچه را که به وضوح درخواست کرده‌اید. هیچ JavaScript، هیچ تصویری، هیچ درخواست اضافی به CDN. وزن متوسط یک صفحه HTML از کارت تجارت الکترونیک در آزمایش من حدود 180-250 KB HTML فشرده نشده بود.

import requests

proxies = {
    "http": "http://user:pass@proxy_host:port",
    "https": "http://user:pass@proxy_host:port",
}

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}

total_bytes = 0
urls = load_urls_from_file("urls.txt")  # لیست 1000 لینک

for url in urls:
    response = requests.get(url, headers=headers, proxies=proxies, timeout=15)
    total_bytes += len(response.content)

print(f"مجموع دانلود شده: {total_bytes / 1024 / 1024:.2f} مگابایت")

در 1000 صفحه، مصرف نهایی 190-230 مگابایت بود — یعنی کمتر از 0.25 GB. این اقتصادی‌ترین گزینه است، اما یک محدودیت بحرانی دارد: اگر سایت محتوا را از طریق JavaScript (React، Vue، بارگذاری دینامیک قیمت‌ها) رندر کند، requests یک چارچوب خالی از صفحه بدون داده‌های مورد نیاز دریافت می‌کند. برای HTML ایستا یا سایت‌هایی با SSR این انتخاب ایده‌آل از نظر نسبت ترافیک به نتیجه است.

Puppeteer: وزن headless Chrome چقدر است

Puppeteer یک موتور واقعی Chromium را کنترل می‌کند، بنابراین صفحه را به طور کامل بارگذاری می‌کند: HTML، CSS، فونت‌ها، تصاویر، اسکریپت‌های ردیابی، iframe‌های تبلیغاتی. حتی در حالت headless، مرورگر تمام درخواست‌های شبکه‌ای را که یک کاربر معمولی در Chrome انجام می‌دهد، انجام می‌دهد.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: 'new',
    args: ['--proxy-server=http://proxy_host:port']
  });

  const page = await browser.newPage();
  await page.authenticate({ username: 'user', password: 'pass' });

  let totalBytes = 0;
  page.on('response', async (response) => {
    try {
      const buffer = await response.buffer();
      totalBytes += buffer.length;
    } catch (e) {}
  });

  const urls = require('./urls.json'); // 1000 لینک

  for (const url of urls) {
    await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
  }

  console.log(`مجموع ترافیک: ${(totalBytes / 1024 / 1024).toFixed(2)} مگابایت`);
  await browser.close();
})();

در آزمایش من، وزن متوسط یک صفحه از طریق Puppeteer حدود 2.8-4.5 مگابایت بود، بسته به تعداد تصاویر و اسکریپت‌های خارجی. در 1000 صفحه، این نتیجه 3.1-4.2 GB بود — 15-18 برابر بیشتر از requests. بخش عمده‌ای از ترافیک را تصاویر (معمولاً 40-55% وزن صفحه) و اسکریپت‌های خارجی تحلیلی، تبلیغاتی و ویجت‌های چت (20-30%) می‌گیرند.

Playwright: ترافیک در مرورگرهای مختلف

Playwright به طور مشابه عمل می‌کند، اما از سه موتور — Chromium، Firefox و WebKit پشتیبانی می‌کند. مصرف ترافیک بین آن‌ها متفاوت است: WebKit در حالت headless به طور سنتی کمی اقتصادی‌تر است به دلیل پردازش متفاوت محتوای رسانه‌ای، در حالی که Firefox گاهی داده‌های بیشتری را به دلیل تفاوت در کش کردن منابع بین درخواست‌ها بارگذاری می‌کند.

from playwright.sync_api import sync_playwright

total_bytes = 0

def handle_response(response):
    global total_bytes
    try:
        body = response.body()
        total_bytes += len(body)
    except Exception:
        pass

with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=True,
        proxy={"server": "http://proxy_host:port", "username": "user", "password": "pass"}
    )
    page = browser.new_page()
    page.on("response", handle_response)

    urls = load_urls_from_file("urls.txt")
    for url in urls:
        page.goto(url, wait_until="networkidle", timeout=30000)

    print(f"مجموع ترافیک: {total_bytes / 1024 / 1024:.2f} مگابایت");
    browser.close()

در Chromium از طریق Playwright، نتیجه نزدیک به Puppeteer بود — 2.9-4.3 GB بر روی 1000 صفحه، که منطقی است، زیرا هر دو ابزار از یک موتور یکسان استفاده می‌کنند. در WebKit، مصرف 10-15% کمتر بود، حدود 2.6-3.7 GB، و در Firefox — کمی بیشتر، 3.3-4.6 GB. تفاوت به دلیل تفاوت در پردازش فونت‌ها، رمزگشایی تصاویر و رفتار استک شبکه هر موتور مرورگر توضیح داده می‌شود.

جدول مقایسه: GB بر روی 1000 صفحه

در زیر جدول خلاصه‌ای از تمام گزینه‌های آزمایش شده، با گرد کردن به محدوده‌های عملی ارائه شده است. اعداد برای یک صفحه متوسط تجارت الکترونیک با تصاویر و مجموعه‌ای معمول از اسکریپت‌های خارجی معتبر است — در سایت‌های خبری یا لندینگ‌هایی با ویدیو، مصرف بیشتر خواهد بود.

ابزار ترافیک بر روی 1000 صفحه رندرینگ JS دور زدن تشخیص ربات‌ها
requests (Python) 0.19-0.23 GB خیر ضعیف
Playwright (WebKit) 2.6-3.7 GB بله متوسط
Puppeteer (Chromium) 3.1-4.2 GB بله متوسط
Playwright (Chromium) 2.9-4.3 GB بله خوب
Playwright (Firefox) 3.3-4.6 GB بله متوسط

نتیجه کلیدی: اگر سایت نیاز به رندرینگ JavaScript برای دریافت داده‌های مورد نیاز ندارد، requests 15-20 برابر در مقایسه با هر راه‌حل مرورگری ترافیک را صرفه‌جویی می‌کند. اما اگر محتوا به صورت دینامیک بارگذاری می‌شود یا سایت به طور فعال رفتار مرورگر را بررسی می‌کند — باید برای ترافیک رندرینگ مرورگر هزینه کنید.

چگونه مصرف ترافیک را 5-10 برابر کاهش دهیم

حتی اگر به یک مرورگر کامل نیاز دارید، می‌توانید مصرف ترافیک را به طور چشمگیری کاهش دهید، بدون اینکه داده‌های مورد نیاز را از دست بدهید. در اینجا روش‌های عملی وجود دارد که من بر روی همان مجموعه از 1000 صفحه آزمایش کردم.

1. مسدود کردن تصاویر، فونت‌ها و رسانه. تصاویر معمولاً بیش از نیمی از وزن صفحه را تشکیل می‌دهند و برای پارس کردن داده‌های متنی به آن‌ها نیاز نیست.

await page.route('**/*', (route) => {
  const type = route.request().resourceType();
  if (['image', 'font', 'media'].includes(type)) {
    route.abort();
  } else {
    route.continue();
  }
});

این روش در Playwright و Puppeteer به طور یکسان کار می‌کند و ترافیک را بدون از دست دادن HTML و داده‌های متنی 40-60% کاهش می‌دهد.

2. مسدود کردن دامنه‌های خارجی. شبکه‌های تبلیغاتی، تحلیل، ویجت‌های چت اسکریپت‌ها و تصاویر خود را بارگذاری می‌کنند که به آن‌ها نیاز ندارید. می‌توانید درخواست‌ها را بر اساس دامنه فیلتر کنید و تنها منبع اصلی و CDN آن را نگه دارید.

3. استفاده از "domcontentloaded" به جای "networkidle". انتظار برای بارگذاری کامل شبکه باعث می‌شود که مرورگر منتظر تمام درخواست‌های پس‌زمینه، از جمله تحلیل و بارگذاری تنبل باشد. اگر داده‌ها زودتر در DOM ظاهر شوند — تغییر به یک رویداد زودتر، پارس کردن را تسریع می‌کند و بارگذاری‌های اضافی را کاهش می‌دهد.

4. کش کردن منابع استاتیک بین درخواست‌ها. اگر سایت از یکسان CSS/JS در تمام صفحات استفاده کند، کش مرورگر فعال (برخلاف شرایط آزمایش ما) در هنگام مرور تعداد زیادی URL از یک دامنه، حجم قابل توجهی را صرفه‌جویی می‌کند.

5. رویکرد ترکیبی. بسیاری از تیم‌ها ابتدا requests را امتحان می‌کنند و فقط اگر داده‌ها کافی نباشند — به صفحات خاص از طریق Playwright یا Puppeteer منتقل می‌شوند. این ترکیبی از مصرف پایه پایین ترافیک با امکان رندرینگ در جایی که واقعاً نیاز است، است.

با مسدود کردن منابع به طور صحیح، مصرف ترافیک Puppeteer و Playwright از 3-4 GB به 0.6-1.2 GB در 1000 صفحه کاهش می‌یابد — تفاوت به طور قابل توجهی در مقایسه با requests کمتر می‌شود، در حالی که امکان کار با رندرینگ JS و حفاظت ضد ربات حفظ می‌شود.

چگونه پروکسی مناسب برای حجم ترافیک انتخاب کنیم

محاسبه ترافیک به طور مستقیم بر انتخاب نوع پروکسی تأثیر می‌گذارد. برای درخواست‌های HTTP سبک از طریق requests در سایت‌های استاتیک، پروکسی‌های دیتاسنتر بسیار مناسب هستند — آن‌ها سریع، ارزان از نظر ترافیک و کافی هستند اگر سایت سیگنال‌های رفتاری را بررسی نکند.

اگر وظیفه نیاز به رندرینگ کامل از طریق Playwright یا Puppeteer برای دور زدن سیستم‌های ضد ربات دارد — به عنوان مثال، هنگام جمع‌آوری قیمت‌ها در بازارها یا نظارت بر نتایج موتورهای جستجو — منطقی‌تر است که از پروکسی‌های مقیم استفاده کنید. آن‌ها کمتر بر اساس شهرت IP مسدود می‌شوند، که در زمانی که هر درخواست "وزن" چند مگابایت دارد و جمع‌آوری مجدد داده‌ها به دلیل مسدود شدن هزینه‌بر است، حیاتی است.

برای سناریوهایی که سایت به طور خاص تطابق IP و user-agent را بررسی می‌کند (خدمات بانکی، برنامه‌ها با تأیید هویتی موبایلی)، باید پروکسی‌های موبایل را در نظر بگیرید — با وجود هزینه بالاتر ترافیک، آن‌ها حداکثر اعتماد به نفس IP را فراهم می‌کنند و تعداد درخواست‌های تکراری به دلیل مسدود شدن را به حداقل می‌رسانند.

راهنمای عملی: حجم ترافیک را با فرمول "وزن یک صفحه × تعداد صفحات × ضریب تکرار به دلیل خطاها و مسدود شدن" محاسبه کنید و GB نهایی را با تعرفه ارائه‌دهنده مقایسه کنید. بهینه‌سازی منابع، که در بالا توضیح داده شده است، معمولاً صرفه‌جویی بیشتری نسبت به انتخاب نوع پروکسی ارزان‌تر فراهم می‌کند — اما ترکیب ابزار صحیح و پروکسی صحیح حداکثر تأثیر را دارد.

نتیجه‌گیری

requests همچنان اقتصادی‌ترین ابزار از نظر ترافیک است — حدود 0.2 GB بر روی 1000 صفحه، اما برای سایت‌های با محتوای دینامیک مناسب نیست. Puppeteer و Playwright رندرینگ کامل و دور زدن بهتر حفاظت را ارائه می‌دهند، اما مصرف ترافیک به 3-4.5 GB بر روی همان 1000 صفحه افزایش می‌یابد. مسدود کردن تصاویر، فونت‌ها و دامنه‌های خارجی این فاصله را 3-5 برابر کاهش می‌دهد، در حالی که داده‌های مورد نیاز را حفظ می‌کند.

قبل از راه‌اندازی پارسینگ مقیاس بزرگ، حجم ترافیک مورد انتظار را با توجه به ابزار انتخاب شده محاسبه کنید و آن را در بودجه پروکسی لحاظ کنید. اگر وظیفه نیاز به رندرینگ JavaScript و مقاومت در برابر سیستم‌های ضد ربات دارد، با اجرای آزمایشی بر روی مجموعه کوچکی از صفحات از طریق پروکسی‌های مقیم شروع کنید — این به شما امکان می‌دهد تا مصرف واقعی GB را قبل از راه‌اندازی بر روی حجم کامل داده‌ها به دقت ارزیابی کنید.