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

پارسر به صورت محلی کار می‌کند اما در سرور مسدود می‌شود: ۷ دلیل و راه‌حل‌های آن

پارسر Wildberries، Ozon یا Avito به‌خوبی روی لپ‌تاپ کار می‌کند، اما به‌طور مداوم در سرور مسدود می‌شود؟ ۷ دلیل فنی را بررسی می‌کنیم و نشان می‌دهیم که چه چیزی را در کد و زیرساخت باید تغییر داد.

📅۶ مهر ۱۴۰۵

وضعیت کلاسیک: اسکریپت برای نظارت بر قیمت‌ها در Wildberries یا Ozon به‌خوبی بر روی لپ‌تاپ خانگی کار می‌کند، اما پس از انتقال به VPS شروع به دریافت 403، کپچا یا مسدودیت فوری بر اساس IP می‌کند. توسعه‌دهنده هدرها را تغییر می‌دهد، تأخیرها را اضافه می‌کند — اما نتیجه تغییر نمی‌کند. مشکل تقریباً هرگز در کد پارسر به‌عنوان یک کل نیست، بلکه در محیطی است که از آن درخواست‌ها انجام می‌شود. به بررسی 7 دلیل خاص و اینکه چه چیزی را تغییر دهیم تا پارسر به‌طور پایدار بر روی سرور کار کند، می‌پردازیم.

چرا همه چیز به‌صورت محلی کار می‌کند، اما در سرور — مسدودیت

زمانی که شما پارسر را از کامپیوتر خانگی خود اجرا می‌کنید، سایت درخواست را از یک IP معمولی و خانگی ارائه‌دهنده اینترنت شما می‌بیند، از منطقه‌ای آشنا، با محیط مرورگر واقعی، اگر شما از Selenium یا Playwright با پروفایل واقعی استفاده کنید. به محض اینکه همان اسکریپت به VPS در آلمان، هلند یا ایالات متحده منتقل می‌شود، تصویر به‌طور کامل تغییر می‌کند: IP متعلق به دیتاسنتر است، اثر انگشت TLS ممکن است به دلیل نسخه‌های مختلف کتابخانه‌ها متفاوت باشد، منطقه زمانی سرور با جغرافیای IP مطابقت ندارد و فرکانس درخواست‌ها به‌طور ناگهانی افزایش می‌یابد، زیرا سرور به‌طور 24 ساعته و 7 روز هفته بدون وقفه کار می‌کند.

سیستم‌های ضد ربات Wildberries، Ozon، Avito و اکثر بازارهای بزرگ دیگر مدت‌هاست که تنها به User-Agent نگاه نمی‌کنند. آنها مجموعه‌ای از ده‌ها سیگنال را تحلیل می‌کنند: نوع IP، سرعت و منظم بودن درخواست‌ها، رفتار در صفحه، تطابق هدرها و پارامترهای TLS، وجود کوکی‌ها و تاریخچه سشن. ماشین محلی به‌طور تصادفی از اکثر موارد بررسی عبور می‌کند، در حالی که سرور تقریباً در همه موارد رد می‌شود. در زیر، تجزیه و تحلیل دقیقی از هر دلیل ارائه می‌شود.

دلیل 1: IP دیتاسنتر به جای IP خانگی

این دلیل شماره 1 در 80% موارد است. آدرس‌های IP VPS و سرورهای ابری (AWS، DigitalOcean، Hetzner، هاستینگ‌های VDS معمولی) در پایگاه‌های داده دیتاسنترها قرار دارند — ASN این ارائه‌دهندگان به‌طور عمومی شناخته شده و توسط سیستم‌های ضد ربات برای فیلتر کردن فوری ترافیک استفاده می‌شود. بازارهای آنلاین از این لیست‌ها در درجه اول استفاده می‌کنند، زیرا 95% از پارسنگ‌های خودکار دقیقاً از IPهای سروری انجام می‌شود.

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

دلیل 2: عدم چرخش IP و محدودیت فرکانس درخواست‌ها

در ماشین محلی شما 20–50 درخواست به‌صورت دستی در حین آزمایش‌ها انجام می‌دهید و سایت این را متوجه نمی‌شود. در سرور، اسکریپت هر 5 دقیقه از طریق cron اجرا می‌شود و هزاران کارت محصول را به‌طور متوالی از یک IP پردازش می‌کند. چنین الگوی رفتاری یک سیگنال مستقیم برای سیستم ضد ربات است: یک انسان واقعی نمی‌تواند 3000 صفحه کاتالوگ را در یک ساعت بدون هیچ‌گونه وقفه‌ای باز کند.

باید چرخش IP را بر روی مجموعه پروکسی‌ها وارد کرده و تعداد درخواست‌ها به یک آدرس را در یک واحد زمانی محدود کنید. قاعده عملی: حداکثر 30–60 درخواست از یک IP در دقیقه برای کارت‌های محصول، با تغییر خودکار آدرس پس از هر دسته از درخواست‌ها. نمونه‌ای از تنظیم چرخش در Python از طریق مجموعه پروکسی:

import requests

proxies_pool = [
    "http://user:[email protected]:9000",
    "http://user:[email protected]:9001",
    "http://user:[email protected]:9002",
]

def get_page(url, session_id):
    proxy = proxies_pool[session_id % len(proxies_pool)]
    resp = requests.get(
        url,
        proxies={"http": proxy, "https": proxy},
        headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"},
        timeout=10
    )
    return resp.text

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

دلیل 3: هدرها و User-Agent شبیه به مرورگر نیستند

بسیاری از پارسرها در requests یا aiohttp درخواست را با حداقل مجموعه‌ای از هدرها یا با User-Agent استاندارد کتابخانه ارسال می‌کنند، که بلافاصله اسکریپت را نشان می‌دهد (به‌عنوان مثال python-requests/2.31.0). در ماشین محلی از طریق مرورگر، مجموعه هدرها کامل است: Accept، Accept-Language، Accept-Encoding، Sec-Ch-Ua، Referer و دیگران — مجموع آنها به‌طور طبیعی به نظر می‌رسد.

باید مجموعه کامل هدرهای یک مرورگر واقعی را کپی کنید، از جمله ترتیب ارسال آنها — برخی از سیستم‌های ضد ربات حتی این را بررسی می‌کنند. علاوه بر این، مهم است که User-Agent را همزمان با نسخه اثر انگشت TLS چرخش دهید (به بند بعدی مراجعه کنید)، در غیر این صورت عدم تطابق بین هدر مرورگر و کلاینت واقعی TLS به یک سیگنال جدید برای ربات تبدیل می‌شود.

دلیل 4: اثر انگشت TLS/JA3 اسکریپت را نشان می‌دهد

این یک دلیل کمتر شناخته شده، اما بسیار رایج برای مسدودیت‌ها به‌ویژه در سرور است. کتابخانه‌های requests، urllib، aiohttp از پیاده‌سازی خودشان برای TLS handshake استفاده می‌کنند که با پیاده‌سازی در Chrome یا Firefox متفاوت است. سیستم‌های ضد ربات اثر انگشت JA3/JA4 اتصال TLS را محاسبه می‌کنند — و این اثر انگشت در اسکریپت پایتون به‌طور کامل با اثر انگشت مرورگر واقعی متفاوت است، حتی اگر هدرها به‌طور کامل کپی شده باشند.

راه‌حل — استفاده از کتابخانه‌هایی است که اثر انگشت TLS مرورگر را شبیه‌سازی می‌کنند (به‌عنوان مثال curl_cffi، tls-client در Python، یا مرورگر headless کامل مبتنی بر Chromium از طریق Playwright/Puppeteer). گزینه دوم — کار کردن نه از طریق یک کلاینت HTTP خالص، بلکه از طریق یک موتور مرورگر مدیریت شده در ترکیب با ابزار ضد شناسایی، جایی که TLS و هدرها توسط هسته واقعی مرورگر ایجاد می‌شوند، نه شبیه‌سازی کتابخانه.

دلیل 5: منطقه زمانی، محلی و DNS سرورها

اگر اسکریپت از طریق Selenium یا Playwright مرورگر را شبیه‌سازی کند، سیستم ضد ربات ممکن است منطقه زمانی سیستم، زبان رابط، DNS resolver و حتی نشت WebRTC IP واقعی سرور را بررسی کند. VPS در دیتاسنتر فرانکفورت با منطقه زمانی سیستم UTC و ارائه‌دهنده DNS هاست، در حالی که از پروکسی با IP از مسکو استفاده می‌کند، عدم تطابق واضحی در داده‌های جغرافیایی ایجاد می‌کند — این یکی از مطمئن‌ترین سیگنال‌ها برای شناسایی است.

تمام پارامترهای محیط — منطقه زمانی، زبان مرورگر، DNS، جغرافیایی بر اساس WebRTC — باید با منطقه IP آدرس مورد استفاده برای درخواست مطابقت داشته باشند. به‌منظور حل این مشکل، مرورگرهای ضد شناسایی ایجاد شده‌اند: Dolphin Anty، AdsPower، Multilogin، Octo Browser و GoLogin به شما این امکان را می‌دهند که یک «پروفایل مرورگر» جداگانه برای هر پروکسی تنظیم کنید، جایی که به‌طور خودکار منطقه زمانی، محلی، وضوح صفحه و WebRTC را با جغرافیای IP تطبیق می‌دهند.

دلیل 6: الگوی درخواست‌ها بیش از حد «ربات‌گونه» است

انسان‌ها کاتالوگ را با وقفه‌های مختلف ورق می‌زنند، بر روی محصولات تصادفی کلیک می‌کنند، گاهی به عقب برمی‌گردند و صفحه را به‌طور نامنظم اسکرول می‌کنند. اسکریپت سروری معمولاً درخواست‌ها را با فواصل مساوی (به‌عنوان مثال دقیقاً هر 2 ثانیه) انجام می‌دهد و تنها به URLهای مورد نیاز بدون «سر و صدا» اطراف می‌پردازد — بدون بارگذاری تصاویر، اسکریپت‌ها، بدون مراجعه به صفحه اصلی قبل از کارت محصول.

چه چیزی را تغییر دهیم: تأخیرهای تصادفی اضافه کنید (نه 2 ثانیه ثابت، بلکه تصادفی از 1.5 تا 6 ثانیه)، به‌طور دوره‌ای به صفحات میانجی بروید (دسته → کارت، نه درخواست مستقیم به API)، اسکرول و حرکات ماوس را هنگام کار از طریق مرورگر headless شبیه‌سازی کنید. این زمان جمع‌آوری داده‌ها را افزایش می‌دهد، اما به‌طور چشمگیری تعداد مسدودیت‌ها را کاهش می‌دهد.

دلیل 7: سشن‌ها و کوکی‌ها بین درخواست‌ها ذخیره نمی‌شوند

اغلب پارسر در سرور برای هر درخواست یک سشن جدید requests ایجاد می‌کند — بدون کوکی‌ها، بدون توکن تأیید هویت ذخیره شده، بدون تاریخچه بازدیدها. بازارهایی مانند Wildberries و Ozon کوکی‌ها و توکن‌های موقتی را در اولین بازدید ارائه می‌دهند، و درخواست‌های بعدی بدون آنها مشکوک به نظر می‌رسند، گویی هر درخواست توسط یک بازدیدکننده ناشناس جدید انجام می‌شود.

طرح صحیح: یک سشن (requests.Session() یا زمینه مرورگر) — برای یک IP از مجموعه پروکسی، با حفظ کوکی‌ها در طول تمام سری درخواست‌ها به این IP. هنگام تغییر پروکسی، باید یک سشن جدید با کوکی‌های تمیز آغاز کنید، به‌گونه‌ای که کاربر جدید را شبیه‌سازی کنید، نه اینکه از کوکی‌های قدیمی با IP جدید استفاده کنید — این نیز عدم تطابق ایجاد می‌کند و مسدودیت را تحریک می‌کند.

چک‌لیست: چه چیزی را به ترتیب تغییر دهیم

اگر پارسر به‌طور پایدار در سرور مسدود می‌شود، اما به‌صورت محلی کار می‌کند، تغییرات را به این ترتیب بررسی کنید — تا سریع‌تر دلیل را پیدا کنید:

مرحله چه چیزی را بررسی کنیم چه چیزی را تغییر دهیم
1 نوع IP سرور به پروکسی‌های خانگی به‌جای IP مستقیم هاستینگ بروید
2 فرکانس درخواست‌ها چرخش IP و محدودیت درخواست‌ها به آدرس را وارد کنید
3 هدرهای درخواست مجموعه کامل هدرهای یک مرورگر واقعی را کپی کنید
4 اثر انگشت TLS از curl_cffi / مرورگر headless به‌جای requests خالص استفاده کنید
5 منطقه زمانی و محلی پروفایل را در Dolphin Anty / AdsPower برای منطقه IP تنظیم کنید
6 الگوی رفتار تأخیرها را تصادفی کنید، صفحات میانجی را اضافه کنید
7 سشن‌ها و کوکی‌ها یک سشن را به یک IP در تمام چرخه درخواست‌ها متصل کنید

برای پارسنگ با فرکانس بالا در کاتالوگ‌های Wildberries و Ozon، جایی که سرعت عبور از هزاران صفحه مهم است، معمولاً دو نوع پروکسی ترکیب می‌شود: پروکسی‌های دیتاسنتر برای درخواست‌های فنی اولیه (بررسی دسترسی، کدهای وضعیت) و پروکسی‌های خانگی — برای جمع‌آوری نهایی داده‌ها از کارت‌ها، جایی که پنهان‌سازی به‌عنوان یک کاربر واقعی مهم است. برای برنامه‌های موبایل بازارها و Avito گاهی اوقات پروکسی‌های موبایل مؤثرتر هستند، زیرا کمتر در لیست‌های مسدودیت خودکار بر اساس ASN قرار می‌گیرند.

نتیجه‌گیری

مسدودیت پارسر در سرور در حالی که نسخه محلی کار می‌کند تقریباً همیشه به محیط مربوط می‌شود: نوع IP، اثر انگشت TLS، هدرها، منطقه زمانی، الگوی درخواست‌ها و مدیریت سشن‌ها. با بررسی هر یک از 7 دلیل به ترتیب — از رایج‌ترین (IP دیتاسنتر) تا کم‌مشهودترین (عدم تطابق منطقه زمانی و منطقه IP) — می‌توان عملکرد پایدار پارسر را بدون تغییر در منطق اصلی کسب‌وکار جمع‌آوری داده‌ها بازیابی کرد.

اگر شما در حال جمع‌آوری قیمت‌ها و موجودی‌ها در Wildberries، Ozon یا Avito به‌صورت صنعتی هستید، با تغییر IP شروع کنید: سعی کنید از پروکسی‌های خانگی به‌جای آدرس استاندارد VPS استفاده کنید — در اکثر موارد این کار تا 70% از مسدودیت‌ها را قبل از اینکه شما شروع به تنظیم هدرها و اثر انگشت TLS کنید، برطرف می‌کند.