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

API JSON پنهان سایت: چگونه نقاط پایانی داخلی را پیدا کنیم و ترافیک پارسر را کاهش دهیم

سایت به طور خودکار داده‌ها را در فرمت JSON ارائه می‌دهد و این پاسخ به مراتب سبک‌تر از صفحه HTML است. مراحل را بررسی می‌کنیم که چگونه نقطه پایانی داخلی را در DevTools پیدا کنیم، چرا cURL کپی شده کار می‌کند اما کد شما کار نمی‌کند، چه کارهایی باید با توکن‌ها و صفحه‌بندی انجام دهیم و چه زمانی بهتر است از ایده صرف‌نظر کنیم.

📅۳۱ شهریور ۱۴۰۵
API JSON پنهان سایت: چگونه نقاط پایانی داخلی را پیدا کنیم و ترافیک پارسر را کاهش دهیم

پارسر ۴۰۰ کیلوبایت HTML را برای هشت فیلد می‌کشد که سایت به خود در پاسخ JSON به ۸ کیلوبایت می‌دهد. تفاوت پنجاه برابر — این درباره «کد زیبا» نیست، بلکه درباره هزینه پروکسی‌های مقیم است که شما برای هر گیگابایت پرداخت می‌کنید. بررسی می‌کنیم که چگونه API داخلی سایت را پیدا کنیم، چه چیزی در سال ۲۰۲۶ مانع از تکرار آن می‌شود و چه زمانی باید از این ایده صرف‌نظر کنیم.

چرا باید API پنهان را جستجو کنیم، اگر HTML قبلاً تجزیه می‌شود

تقریباً هر رابط کاربری مدرن — React، Vue، Angular، Next.js — ابتدا ساختار صفحه را بارگذاری می‌کند و داده‌ها را از طریق درخواست‌های جداگانه به نقاط پایانی خود می‌کشد. این نقاط پایانی مستند نشده‌اند، اما وجود دارند، پاسخ‌های JSON خالص می‌دهند و بدون مرورگر headless در دسترس هستند.

چه چیزی را با رفتن به آن‌ها به دست می‌آورید:

  • ترافیک به شدت کاهش می‌یابد. در تجزیه یک خروجی کالایی معمولی، صفحه HTML حدود ۴۰۰ کیلوبایت وزن دارد که شامل نشانه‌گذاری، استایل‌ها و ردیاب‌ها است، در حالی که نقطه پایانی JSON مربوطه تقریباً ۸ کیلوبایت است و فیلدهای بیشتری دارد: شناسه‌های داخلی، موجودی‌ها، گزینه‌های محصول.
  • نیازی به مرورگر نیست. رندر کردن JavaScript حذف می‌شود و به همراه آن — حافظه، پردازنده و ده‌ها درخواست اضافی برای فونت‌ها و تجزیه و تحلیل.
  • داده‌ها قبلاً ساختار یافته‌اند. هیچ انتخابگری که از تغییر کلاس CSS خراب شود وجود ندارد.
  • درخواست‌های کمتر — دلایل کمتر برای ممنوعیت. رندر کردن یک صفحه کاتالوگ در مرورگر ده‌ها درخواست به سایت است؛ همان حجم داده‌ها از طریق API — یک درخواست.

برای پروژه‌ای که از پروکسی‌های مقیم استفاده می‌کند، این یک صرفه‌جویی مستقیم است: تعرفه بر اساس گیگابایت محاسبه می‌شود و انتقال از رندر به JSON معمولاً هزینه را بیشتر از هر ترفند دیگری برای مسدود کردن تصاویر کاهش می‌دهد. موضوع مرتبط — چگونه ترافیک پارسر را ۵ برابر کاهش دهیم با روش‌های دیگر.

گام به گام: چگونه نقطه پایانی را پیدا کنیم

  1. ابتدا بررسی کنید که آیا API رسمی وجود ندارد. به /developers، /api، /docs سایت هدف نگاهی بیندازید. API عمومی مستند شده نسخه‌بندی می‌شود و درباره انقضا هشدار می‌دهد — API خصوصی به آرامی تغییر می‌کند.
  2. DevTools را باز کنید (F12) و به تب Network بروید و مطمئن شوید که ضبط فعال است.
  3. فیلتر Fetch/XHR را فعال کنید. این فیلتر تصاویر، فونت‌ها و تجزیه و تحلیل را حذف می‌کند و فقط درخواست‌های داده را باقی می‌گذارد.
  4. لیست را پاک کنید تا نویز بارگذاری اولیه را حذف کنید.
  5. داده‌های مورد نیاز را تحریک کنید: خروجی را مرور کنید، روی «صفحه بعدی» کلیک کنید، فیلتر را اعمال کنید، کارت محصول را باز کنید. درخواست مورد نظر شما در لحظه عمل ظاهر می‌شود.
  6. پاسخ با داده‌های شما را پیدا کنید. سریع‌ترین راه — Ctrl+F در پنل Network: به دنبال مقدار منحصر به فردی باشید که روی صفحه می‌بینید (کد محصول، قیمت دقیق، بخشی از نام) و ببینید چه درخواستی آن را ایجاد کرده است.
  7. درخواست را به طور کامل کپی کنید: کلیک راست روی خط → Copy → Copy as cURL. سپس آن را با استفاده از curlconverter به کد تبدیل کنید — اینگونه هیچ هدر را از دست نخواهید داد.

مسیرهای مشخصی که باید در اولویت بررسی شوند: /api/، /v1/، /v2/، /search، /products، /listings، /graphql.

مورد خاص: سایت‌های Next.js

در اینجا داده‌ها اغلب اصلاً نیازی به درخواست جداگانه ندارند — آن‌ها مستقیماً در HTML قرار دارند. در روتر صفحات قدیمی، این بلوک __NEXT_DATA__ است. در روتر اپ (Next.js 13 و جدیدتر) داده‌ها برای هیدراتاسیون در چندین گره script در فراخوانی‌های self.__next_f.push() قرار دارند — این payload سریالی شده از اجزای سرور React است. تجزیه آن به صورت دستی ناخوشایند است: چانک‌ها از طریق پیشوندهای $ به یکدیگر ارجاع می‌دهند و ممکن است در وسط یک رشته قطع شوند. برای Python یک کتابخانه nextflight وجود دارد که هم payload Flight را از HTML و هم پاسخ خام RSC (درخواست با هدر RSC: 1) تجزیه می‌کند و پیشنهاد می‌کند که در آن به دنبال نام‌های کلیدها باشید، نه به دنبال ایندکس‌های آرایه — اینگونه پارسر از دوباره‌استقرار سایت جان سالم به در می‌برد.

معکوس کردن پارامترها: صفحه‌بندی و فیلترها

نقطه پایانی پیدا شده تقریباً همیشه پارامترشده است. سه الگو وجود دارد:

  • بر اساس صفحات: ?page=3&per_page=20
  • جابه‌جایی و محدودیت: ?offset=40&limit=20
  • کورسور: ?after=<token>&limit=20 — توکن صفحه بعدی در بدنه پاسخ قبلی می‌آید

سه قاعده که ساعت‌ها عیب‌یابی را صرفه‌جویی می‌کند:

  • بر روی بسته خالی متوقف شوید، نه بر روی عدد صفحات محاسبه شده از قبل: شمارنده total در API‌های خصوصی بیشتر از آنچه که باید دروغ می‌گوید.
  • اندازه واقعی بسته را بررسی کنید. ۱۰۰ درخواست کردید، ۲۰ آمد — یعنی نقطه پایانی سقف خود را دارد و حساب شما برای صفحات دیگر نادرست است.
  • به صفحه ۵۰۰ نروید. صفحه‌بندی عمیق تقریباً در همه جا توسط سرور قطع می‌شود؛ به جای آن، انتخاب را با فیلترها برش دهید — بر اساس دسته، بر اساس دامنه قیمت، بر اساس تاریخ.

چرا cURL از مرورگر کار می‌کند، اما کد شما — نه

این معمولاً نقطه شکست است و تقریباً همیشه یک دلیل دارد: هدر گم شده. cURL کپی شده تمام زمینه درخواست را به همراه دارد، اما کلاینت نوشته شده توسط خودتان — ندارد.

چه چیزهایی معمولاً اجباری می‌شود:

  • هدرهای سفارشی با پیشوند X- — X-CSRF-Token، X-Requested-With: XMLHttpRequest و انواع X-*-Token که فرانت‌اند خودش قرار می‌دهد. بدون آن‌ها شما پاسخ‌هایی در محدوده ۴۰۰–۵۰۰ دریافت خواهید کرد.
  • Referer — هدر زمینه‌ای که توسط عمل کاربر تولید می‌شود. بسیاری از نقاط پایانی بررسی می‌کنند که درخواست «از صفحه خود آمده است».
  • Authorization: Bearer <JWT> — توکن کوتاه‌مدت، معمولاً برای ۱۵–۶۰ دقیقه. هاردکد کردن آن بی‌معنی است: باید بتوانید توکن جدیدی دریافت کنید.
  • کوکی‌های سشن — آن‌ها را در شیء سشن نگه دارید، نه اینکه به صورت دستی کپی کنید.
  • نوع محتوا Content-Type صحیح برای POST: application/json و application/x-www-form-urlencoded بدنه را به شیوه‌های مختلف کدگذاری می‌کنند و عدم تطابق با نوع اعلام شده درخواست را به آرامی خراب می‌کند.

کجا باید به دنبال خود توکن‌ها باشید، اگر در کوکی‌ها نیستند: در منبع HTML درون <script> (جستجو بر اساس مقدار شناخته شده از طریق Ctrl+F)، در بسته‌های JavaScript، در localStorage یا IndexedDB — تب Application در DevTools.

دام‌های زیرآبی که دیر متوجه می‌شوند

API خصوصی بدون هشدار تغییر می‌کند. این API نسخه‌بندی ندارد، وعده‌های سازگاری و پشتیبانی ندارد: تیم فرانت‌اند یک فیلد را در عصر پنجشنبه تغییر نام می‌دهد و پارسر شما خالی جمع‌آوری می‌کند. حفاظت — نه «انتخابگر مطمئن»، بلکه کنترل ساختار: بررسی کنید که فیلدهای الزامی در جای خود و از نوع مناسب هستند؛ نسبت مقادیر خالی و تعداد رکوردها در اجرای خود را زیر نظر داشته باشید؛ رکوردهای خراب را رد کنید، اما اگر نقص بیش از ۱۰٪ شد، زنگ خطر را به صدا درآورید؛ پاسخ‌های خام را ذخیره کنید تا بعداً با آن‌ها مقایسه کنید.

API گاهی اوقات سخت‌تر از صفحه محافظت می‌شود. این موضوع به طور منظم اتفاق می‌افتد: HTML به آرامی ارائه می‌شود، اما در /api/ یک ضد ربات وجود دارد که هم فینگرپرینت TLS و هم ترکیب هدرها را بررسی می‌کند. در این صورت، صرفه‌جویی در ترافیک به افزایش نسبت درخواست‌های ناموفق تبدیل می‌شود و سود از بین می‌رود.

درخواست‌های امضا شده. اگر در پارامترها چیزی شبیه به sign، hash یا _s وجود داشته باشد، فرانت‌اند امضای آن را در JavaScript محاسبه می‌کند. بازتولید آن — یک پروژه جداگانه است و اغلب ارزان‌تر است که در HTML بمانید.

محدودیت‌های فرکانس. نقاط پایانی خصوصی برای جریان طراحی نشده‌اند: ۱–۲ درخواست در ثانیه نگه دارید، زمان‌های جداگانه‌ای برای اتصال و خواندن (به عنوان مثال، ۵ و ۳۰ ثانیه) تنظیم کنید، فقط خطاهای گذرا را تکرار کنید — ۴۲۹، ۵۰۰، ۵۰۲، ۵۰۳، ۵۰۴ — و به ۴۰۱ و ۴۰۴ دست نزنید. تأخیر نمایی با جیتری الزامی است، در غیر این صورت همه کارگران به طور همزمان به دور دوم می‌روند. جزئیات بیشتر — در تجزیه و تحلیل زمان‌های انتظار و منطق تکرار برای پروکسی.

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

چه زمانی بر روی HTML بمانید

API پنهان — همیشه سودآور نیست. اگر:

  • سایت سروری است و هیچ API داخلی وجود ندارد؛
  • نقطه پایانی به امضا یا چرخش توکن‌ها نیاز دارد — نگهداری آن گران‌تر از صفحه است؛
  • در API محافظت سخت‌تری نسبت به صفحات عمومی وجود دارد؛
  • نتیجه نهایی خاصی نیاز دارید که فرانت‌اند از چندین منبع جمع‌آوری می‌کند؛
  • شما ده‌ها سایت را مدیریت می‌کنید: یک خط تولید HTML بهتر از یک باغ وحش API‌های خصوصی با ویژگی‌های فردی مقیاس‌پذیر است.

چه نوع پروکسی برای پارسینگ API بگیریم

انتقال به JSON محاسبات را تغییر می‌دهد، زیرا گلوگاه جابه‌جا می‌شود: ترافیک کم می‌شود، اما نیاز به کیفیت IP و ثبات جلسه بیشتر می‌شود.

  • نقطه پایانی باز بدون احراز هویت و بدون ضد ربات. در اینجا کافی است پروکسی‌های دیتاسنتر: حجم داده‌ها کوچک است و نیازی به پرداخت برای پروکسی‌های مقیم نیست.
  • نقطه پایانی پشت ضد ربات یا با وابستگی به جلسه. به پروکسی‌های مقیم با جلسه چسبنده نیاز دارید: توکن، کوکی و IP باید در تمام طول زنجیره مطابقت داشته باشند، در غیر این صورت سرور جلسه را در درخواست دوم قطع می‌کند. در عین حال، هزینه همچنان کم خواهد ماند — گیگابایت‌ها در حالت JSON به آرامی مصرف می‌شوند.
  • داده‌ها از برنامه موبایل. اگر نسخه وب بسته است و برنامه همان داده‌ها را به سادگی ارائه می‌دهد، نقاط پایانی را از طریق رهگیری ترافیک جستجو کنید — این یک روند جداگانه است که در مقاله‌ای درباره جستجوی API پنهان برنامه موبایل از طریق mitmproxy بررسی شده است.

خلاصه

بیست دقیقه در DevTools اغلب جایگزین روزها مبارزه با مرورگر headless می‌شود: فیلتر Fetch/XHR، جستجو بر اساس مقدار قابل مشاهده، Copy as cURL — و شما یک درخواست کارآمد در دست دارید. سپس جزئیات را حل می‌کنند: تمام هدرها را منتقل کنید، طرح صفحه‌بندی را تجزیه کنید، اعتبارسنجی پاسخ را قرار دهید و به طور منطقی ارزیابی کنید که آیا نقطه پایانی بدتر از خود صفحه محافظت شده است یا خیر. جایی که API خصوصی کار می‌کند، هم حجم ترافیک و هم تعداد درخواست‌ها را کاهش می‌دهد — یعنی به طور همزمان هزینه پروکسی و احتمال ممنوعیت را کاهش می‌دهد.