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

چگونه ترافیک پارسر را بدون از دست دادن داده‌ها ۵ برابر کاهش دهیم: ۷ روش برای مهندسان داده

ما ۷ روش عملی را بررسی می‌کنیم که به کاهش حجم ترافیک پارسر تا ۵ برابر بدون از دست دادن کیفیت و کامل بودن داده‌های جمع‌آوری شده کمک می‌کند.

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

هر مگابایت اضافی ترافیک پارسر به معنای پرداخت به ارائه‌دهنده پروکسی یا خطر رسیدن به محدودیت‌ها و دریافت بن بر اساس IP است. اگر شما قیمت‌ها را از Wildberries، Ozon جمع‌آوری می‌کنید یا آگهی‌ها را در Avito از طریق صدها آدرس پروکسی رصد می‌کنید، صرفه‌جویی در ترافیک به طور مستقیم بر بودجه پروژه تأثیر می‌گذارد. در این مقاله، تکنیک‌های فنی مشخصی را بررسی می‌کنیم که به کاهش حجم داده‌های منتقل شده به میزان 4-5 برابر کمک می‌کند در حالی که جامعیت و دقت اطلاعات استخراج شده حفظ می‌شود.

چرا ترافیک پارسر بر بودجه تأثیر می‌گذارد

اکثر ارائه‌دهندگان پروکسی هزینه پروکسی‌های مقیم و موبایل را بر اساس حجم گیگابایت‌های منتقل شده محاسبه می‌کنند، نه بر اساس زمان استفاده. اگر پارسر شما صفحه محصول Wildberries را به طور کامل بارگذاری کند — با تصاویر، اسکریپت‌های توصیه، ردیاب‌های تحلیلی و فونت‌ها — شما برای هر کارت 2-3 مگابایت پرداخت می‌کنید، در حالی که واقعاً به 15-20 کیلوبایت متن نیاز دارید: نام، قیمت، امتیاز، موجودی.

در مقیاس‌گذاری تا 50,000-100,000 کارت در روز، تفاوت بین «بارگذاری همه» و «بارگذاری فقط موارد ضروری» به ده‌ها گیگابایت ترافیک اضافی روزانه تبدیل می‌شود. این نه تنها هزینه‌های پروکسی را افزایش می‌دهد، بلکه بار اضافی بر روی وب‌سایت هدف ایجاد می‌کند که احتمال قرار گرفتن تحت حفاظت ضد ربات و دریافت CAPTCHA یا بن موقت IP را افزایش می‌دهد. بهینه‌سازی ترافیک به معنای صرفه‌جویی در هزینه و کاهش خطر مسدود شدن است.

یک اثر سوم نیز وجود دارد: هر چه داده‌های کمتری در یک درخواست منتقل شود، درخواست سریع‌تر انجام می‌شود. این امکان را فراهم می‌کند که همزمانی را افزایش دهیم — تعداد بیشتری از رشته‌ها را با همان تعداد پروکسی‌ها بدون تجاوز از محدودیت‌های سرعت که مرورگرهای ضد شناسایی مانند Dolphin Anty یا AdsPower در هنگام کار با جلسات تعیین می‌کنند، راه‌اندازی کنیم.

روش 1: مسدود کردن تصاویر، CSS و فونت‌ها

اگر پارسر از طریق مرورگر بدون سر (headless) (Playwright، Puppeteer، Selenium) کار می‌کند — سریع‌ترین راه برای کاهش ترافیک به میزان 2-3 برابر — مسدود کردن بارگذاری منابع استاتیک است که بر داده‌ها در DOM تأثیر نمی‌گذارد. تصاویر محصولات، فونت‌های وب‌سایت، ویدیوها و استایل‌های CSS تا 70% وزن صفحه را تشکیل می‌دهند، اما هیچ نقشی در استخراج متن و ویژگی‌ها ندارند.

from playwright.sync_api import sync_playwright

def block_heavy_resources(route, request):
    if request.resource_type in ["image", "media", "font", "stylesheet"]:
        route.abort()
    else:
        route.continue_()

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.route("**/*", block_heavy_resources)
    page.goto("https://example.com/product/123")
    html = page.content()
    browser.close()

منطق مشابهی در Puppeteer از طریق page.setRequestInterception(true) و در Selenium از طریق تنظیم پروفایل Chrome با پارامتر profile.managed_default_content_settings.images: 2 پیاده‌سازی می‌شود. در عمل، این یک تنظیم به تنهایی بین 50% تا 70% ترافیک را در هنگام پارس کردن بازارهای آنلاین که صفحات آنها با محتوای بصری و بنرهای تبلیغاتی پر شده‌اند، کاهش می‌دهد.

روش 2: درخواست‌های HTTP به جای مرورگر کامل

بسیاری از افراد از Selenium یا Playwright در جاهایی استفاده می‌کنند که نیازی به آن نیست. اگر صفحه نیاز به اجرای JavaScript برای رندر کردن داده‌ها ندارد (این را می‌توان به راحتی با باز کردن «مشاهده کد صفحه» به جای DevTools بررسی کرد)، بسیار به صرفه‌تر است که HTML را به طور مستقیم از طریق کتابخانه‌های requests یا httpx در Python دریافت کنید. چنین درخواستی وزنش کیلوبایت است، نه مگابایت، زیرا رندرینگ موتور مرورگر، فراخوانی‌های شبکه برای ردیاب‌ها و منابع ثانویه را به همراه ندارد.

import httpx

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
    "Accept-Encoding": "gzip, br",
    "Accept": "text/html,application/xhtml+xml"
}

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

with httpx.Client(headers=headers, proxies=proxies, http2=True) as client:
    response = client.get("https://example.com/catalog/item/456")
    print(len(response.content), "بایت دریافت شد")

انتقال از شبیه‌سازی مرورگر به درخواست‌های HTTP مستقیم در جایی که وب‌سایت HTML آماده را بدون رندرینگ کلاینت ارائه می‌دهد، ترافیک را 3-8 برابر کاهش می‌دهد. نکته تنها این است که این درخواست‌ها به راحتی از کاربر واقعی متمایز می‌شوند، بنابراین برای وب‌سایت‌هایی با حفاظت ضد ربات سخت، بهتر است این روش را با پروکسی‌های مقیم با کیفیت ترکیب کنید که IPهای واقعی ارائه‌دهندگان خانگی را ارائه می‌دهند و احتمال مسدود شدن درخواست را کاهش می‌دهند.

روش 3: پارس کردن از طریق APIهای JSON پنهان

تقریباً تمام بازارهای آنلاین مدرن — از جمله Wildberries، Ozon و Yandex.Market — کارت‌های محصولات و لیست‌ها را از طریق APIهای JSON داخلی که فرانت‌اند فراخوانی می‌کند، رندر می‌کنند. می‌توان این نقاط پایانی را از طریق زبانه Network در DevTools پیدا کرد و درخواست‌ها را بر اساس نوع XHR/Fetch فیلتر کرد. به طور معمول، یک چنین درخواستی JSON را به حجم 5-30 کیلوبایت با داده‌های خالص ارائه می‌دهد: id محصول، قیمت، تخفیف، موجودی، امتیاز — بدون یک بایت HTML یا CSS.

تفاوت در حجم داده‌های منتقل شده بین یک صفحه HTML کامل و دسترسی مستقیم به API JSON می‌تواند به 10-15 برابر برسد. مزیت اضافی — JSON به طور برنامه‌نویسی ساده‌تر پارس می‌شود: نیازی به انتخاب‌گرهای XPath نیست، کافی است به فیلد مورد نیاز بر اساس کلید دیکشنری دسترسی پیدا کنید. نقطه ضعف — این نقاط پایانی اغلب به هدرهای خاص، توکن‌های جلسه یا پارامترهای امضای درخواست نیاز دارند که باید از صفحه اصلی یا اپلیکیشن موبایل استخراج شوند.

نکته برای عمل‌کنندگان

قبل از اینکه پارسر را حول API پنهان بسازید، نسخه موبایل وب‌سایت یا اپلیکیشن را از طریق پروکسی-پیرامون (Charles Proxy، Fiddler) بررسی کنید — APIهای موبایل اغلب JSON فشرده‌تر و پایدارتر از نسخه دسکتاپ وب‌سایت ارائه می‌دهند.

روش 4: فشرده‌سازی Gzip و Brotli

حتی اگر مجبور باشید HTML کامل را دریافت کنید، فعال کردن فشرده‌سازی صحیح می‌تواند اندازه انتقال را به میزان 60-80% کاهش دهد. بسیاری از پارسرهای نوشته شده خودشان هدر Accept-Encoding: gzip, br را ارسال نمی‌کنند، به همین دلیل سرور پاسخ بدون فشرده‌سازی را ارائه می‌دهد. کتابخانه‌های requests و httpx به طور خودکار Gzip و Brotli را از حالت فشرده خارج می‌کنند — فقط مهم است که پشتیبانی از فشرده‌سازی را به وضوح در هدرهای درخواست مشخص کنید.

Brotli به طور متوسط متن HTML را بیشتر از Gzip به میزان 15-20% فشرده می‌کند، اما همه سرورها از این الگوریتم پشتیبانی نمی‌کنند — بهتر است هر دو گزینه را درخواست کنید و به سرور اجازه دهید بهترین گزینه را انتخاب کند. برای APIهای JSON، اثر فشرده‌سازی حتی بیشتر قابل مشاهده است: کلیدهای تکراری دیکشنری‌ها («price»، «name»، «rating») تقریباً به طور ایده‌آل فشرده می‌شوند و وزن پاسخ را به شدت کاهش می‌دهند.

روش 5: درخواست‌های شرطی و کش

اگر شما قیمت‌ها را برای یکسان‌ترین محصولات چندین بار در روز رصد می‌کنید، بخش عمده‌ای از کارت‌ها بین بررسی‌ها تغییر نمی‌کند. از هدرهای If-Modified-Since و If-None-Match با مقدار ETag که در اولین درخواست دریافت شده است، استفاده کنید. اگر محتوا تغییر نکرده باشد، سرور وضعیت 304 Not Modified را تقریباً بدون بدنه پاسخ ارائه می‌دهد — صرفه‌جویی در ترافیک تا 95% در صفحات بدون تغییر.

import httpx

etag_store = {}

def fetch_with_cache(url, client):
    headers = {}
    if url in etag_store:
        headers["If-None-Match"] = etag_store[url]
    resp = client.get(url, headers=headers)
    if resp.status_code == 304:
        return None  # داده‌ها تغییر نکرده‌اند
    etag_store[url] = resp.headers.get("ETag", "")
    return resp.content

همه وب‌سایت‌ها به درستی از ETag پشتیبانی نمی‌کنند، اما برای آنهایی که پشتیبانی می‌کنند، این روش به مؤثرترین راه برای کاهش ترافیک در هنگام رصد منظم تبدیل می‌شود — شما عملاً فقط برای تغییرات واقعی داده‌ها هزینه می‌کنید، نه برای بارگذاری مجدد محتوای بدون تغییر.

روش 6: پارس انتخابی فیلدهای مورد نیاز

گاهی اوقات کاهش ترافیک ورودی از سمت سرور غیرممکن است — وب‌سایت صفحه کامل را به طور کامل بدون توجه به درخواست ارائه می‌دهد. در این صورت، بهینه‌سازی در مرحله پردازش انجام می‌شود: صفحه را دوباره بارگذاری نکنید فقط برای اینکه یک فیلد دیگر را استخراج کنید. XPath یا CSS-انتخاب‌گرها را طوری طراحی کنید که در یک بار عبور از DOM تمام ویژگی‌های مورد نیاز — قیمت، نام، کد، موجودی، امتیاز — را استخراج کنید، به جای اینکه بارها به همان URL با پارسرهای مختلف برای وظایف مختلف درخواست کنید.

همچنین مفید است که عمق خزیدن صفحات تو در تو را محدود کنید. اگر برای رصد قیمت‌ها داده‌های صفحه دسته‌بندی (لیست محصولات) کافی است، به صفحه هر محصول به طور جداگانه نروید — این ترافیک تکراری است که اغلب اطلاعات جدیدی جز توضیحات و نظرات که بر قیمت و موجودی تأثیر نمی‌گذارد، ارائه نمی‌دهد.

روش 7: بهینه‌سازی الگوی خزیدن

حذف URL — یک روش پایه‌ای اما اغلب نادیده گرفته شده است. دایرکتوری‌های بازارهای آنلاین تعداد زیادی لینک با محتوای یکسان اما با پارامترهای مرتب‌سازی، برچسب‌های UTM یا ID جلسه مختلف تولید می‌کنند. نرمال‌سازی URL قبل از قرار دادن در صف (حذف پارامترهای ردیابی، مرتب‌سازی پارامترهای query) 10-30% از درخواست‌های اضافی را در هنگام خزیدن در دایرکتوری‌های بزرگ حذف می‌کند.

اولویت‌بندی خزیدن بر اساس فراوانی تغییر داده‌ها نیز در صرفه‌جویی ترافیک مؤثر است: محصولات با تقاضای بالا و قیمت‌های نوسانی باید هر ساعت بررسی شوند، در حالی که موارد نادر — یک بار در روز. چنین برنامه‌ریزی تطبیقی به جای خزیدن یکنواخت از همه کارت‌ها با یک دوره زمانی یکسان، حجم کلی درخواست‌ها را 2-4 برابر کاهش می‌دهد بدون اینکه از به‌روزرسانی داده‌های حیاتی کاسته شود.

چگونه این با استراتژی پروکسی ترکیب می‌شود

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

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

ترکیب «حداقل ترافیک در هر درخواست» + «نوع پروکسی مناسب برای وظیفه» به طور همزمان هزینه‌های زیرساخت را کاهش می‌دهد و سرعت جمع‌آوری داده‌ها را بدون از دست دادن قابلیت اطمینان افزایش می‌دهد.

جدول مقایسه روش‌ها

روش کاهش ترافیک پیچیدگی پیاده‌سازی
مسدود کردن تصاویر/CSS/فونت‌ها 50-70% پایین
درخواست‌های HTTP به جای مرورگر 3-8 برابر متوسط
APIهای JSON پنهان 10-15 برابر بالا
فشرده‌سازی Gzip/Brotli 60-80% پایین
درخواست‌های شرطی (ETag) تا 95% در صفحات بدون تغییر متوسط
حذف URL و اولویت‌بندی 2-4 برابر متوسط

چک‌لیست پیاده‌سازی

  • بررسی کنید که آیا صفحه هدف به رندرینگ JavaScript نیاز دارد یا می‌توان HTML را به طور مستقیم از طریق httpx/requests دریافت کرد
  • تنظیم مسدود کردن image/media/font/stylesheet در مرورگر بدون سر، اگر مرورگر هنوز نیاز است
  • یافتن APIهای JSON داخلی از طریق DevTools → Network → XHR/Fetch
  • اضافه کردن هدرهای Accept-Encoding: gzip, br به همه درخواست‌ها
  • پیاده‌سازی ذخیره‌سازی ETag/Last-Modified برای درخواست‌های شرطی در URLهای تکراری
  • نرمال‌سازی و حذف URLهای تکراری قبل از خزیدن
  • تنظیم فرکانس خزیدن تطبیقی بر اساس اهمیت و نوسانات داده‌ها
  • انتخاب نوع پروکسی مناسب برای پروفایل نهایی ترافیک — داده‌مرکزی، مقیم یا موبایل

نتیجه‌گیری

کاهش ترافیک پارسر به میزان 5 برابر یک هدف واقع‌گرایانه است، اگر روش‌ها را به طور متوالی اعمال کنید: حذف منابع اضافی، انتقال به درخواست‌های HTTP مستقیم یا API JSON در جاهایی که ممکن است، فعال کردن فشرده‌سازی، استفاده از درخواست‌های شرطی برای داده‌های بدون تغییر و بهینه‌سازی خود الگوی خزیدن. هر یک از این مراحل تأثیر قابل اندازه‌گیری دارد و در مجموع، آنها اقتصاد پروژه جمع‌آوری داده‌ها از بازارهای آنلاین و سایر وب‌سایت‌ها را به طور اساسی تغییر می‌دهند.

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