Skip to content
Advanced / 4 min read

چگونه پروکسی‌های Dataimpulse را برای وب‌اسکرپینگ از طریق mitmproxy روی macOS مسیریابی کنیم

یک شنونده محلی mitmproxy همه اسکرپرها، مرورگرها و شبیه‌سازها روی macOS را از طریق HTTP یا SOCKS5 به پروکسی‌های مسکونی یا موبایل Dataimpulse هدایت می‌کند، با چرخش، محدودسازی نرخ و بازرسی اختیاری TLS که تحت کنترل شماست.

macOS SOCKS5 وب اسکرپینگ حریم خصوصی/ناشناسی

مرور کلی

mitmproxy یک پروکسی رهگیر متن‌باز و قابل اسکریپت‌نویسی است که به‌عنوان یک فرایند معمولی macOS اجرا می‌شود. در حالت upstream اتصال‌ها را از کلاینت‌های محلی روی یک پورت (127.0.0.1:8080) می‌پذیرد و آن ترافیک را به یک پروکسی دوم — در این مورد، نقطه پایانی مسکونی یا موبایل Dataimpulse — هدایت می‌کند.

مزیت آن متمرکزسازی است: پروکسی را یک‌بار پیکربندی می‌کنید و سپس هر مرورگر، ابزار CLI، اسکریپت Python یا شبیه‌ساز موبایل روی دستگاه می‌تواند بدون ویرایش تنظیمات پروکسی خودِ آن ابزار، از طریق Dataimpulse مسیریابی شود. همه‌چیز از یک نقطه گلوگاه واحد عبور می‌کند که در آن می‌توانید هم‌زمانی را محدود کنید، خرابی‌ها را بپایید و تأیید کنید که واقعاً از کدام IP خروجی استفاده می‌کنید.

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

چه زمانی این رویکرد منطقی است

رویکرد چه چیزی را پیکربندی می‌کنید بهترین کاربرد
حالت upstream در mitmproxy (همین راهنما) یک پورت محلی برای همه کلاینت‌ها چند ابزار هم‌زمان، محدودسازی و گزارش‌گیری متمرکز
گزینه‌های پروکسی هر ابزار (curl -x، requests proxies=) هر ابزار به‌صورت جداگانه یک اسکریپت واحد با کمترین اجزای متحرک
مدیرهای پروکسی دسکتاپ (مثلاً Proxifier) قواعد به‌ازای هر برنامه برنامه‌های GUI که تنظیمات پروکسی سیستم را نادیده می‌گیرند

چه چیزی می‌سازید

  • یک شنونده محلی mitmproxy روی 127.0.0.1:8080
  • یک اتصال upstream به Dataimpulse از طریق HTTP یا SOCKS5
  • رهگیری اختیاری TLS برای میزبان‌های مشخصی که می‌خواهید بررسی کنید
  • یک افزونه دروازه هم‌زمانی که فشار درخواست‌ها را قابل‌پیش‌بینی نگه می‌دارد
  • نمونه‌های کاربردی برای curl، requests، Playwright و یک شبیه‌ساز Android

پیش‌نیازها

  • macOS 13 یا جدیدتر با Homebrew نصب‌شده
  • یک حساب Dataimpulse، به‌همراه نام کاربری، رمز عبور، میزبان دروازه و پورت‌های HTTP/SOCKS5 که در داشبورد شما نمایش داده می‌شود
  • Python 3.9 یا جدیدتر برای نمونه‌های کلاینت (python3 --version)
  • تسلط نسبی بر Terminal و درک پایه‌ای از پروکسی‌های HTTP و TLS

نحوه کار راه‌اندازی

  1. mitmproxy روی 127.0.0.1:8080 گوش می‌دهد.
  2. کلاینت شما درخواستش را به‌جای ارسال مستقیم به سایت هدف، به mitmproxy می‌فرستد.
  3. mitmproxy اتصالی به دروازه Dataimpulse باز می‌کند.
  4. Dataimpulse یک IP خروجی از استخر خود تخصیص می‌دهد.
  5. پاسخ از طریق mitmproxy به کلاینت شما بازمی‌گردد.

دو حالت مهم هستند و انتخاب زودهنگام بین آن‌ها در زمان صرفه‌جویی می‌کند:

  • عبوردهی (تونل‌سازی): mitmproxy بایت‌های TLS را بدون رمزگشایی آن‌ها هدایت می‌کند. هیچ تغییر گواهی‌نامه‌ای در هیچ‌جا لازم نیست. با --ignore-hosts '.*' فعال می‌شود.
  • رهگیری: mitmproxy TLS را پایان می‌دهد تا بتواند درخواست‌ها و پاسخ‌ها را بخواند یا بازنویسی کند. نیازمند اعتماد به گواهی‌نامه CA مربوط به mitmproxy روی macOS و در هر محیط اجرای کلاینت است.

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

مراحل

  1. mitmproxy را نصب کنید.

    brew install mitmproxy
    mitmdump --version
    
  2. اعتبارنامه‌های Dataimpulse خود را به‌عنوان متغیرهای محیطی صادر کنید تا هرگز در تاریخچه shell یا فایل‌های کامیت‌شده ظاهر نشوند.

    export DI_USER='your-dataimpulse-username'
    export DI_PASS='your-dataimpulse-password'
    export DI_HOST='gateway-host-from-your-dashboard'
    export DI_HTTP_PORT='http-port-from-your-dashboard'
    export DI_SOCKS_PORT='socks5-port-from-your-dashboard'
    export DI_SESSION='scrape-macos-01'
    

    همین خطوط را به ~/.zshrc اضافه کنید اگر می‌خواهید در هر shell جدید در دسترس باشند، و میزبان و پورت را بدون چاپ رمز عبور تأیید کنید:

    echo "${DI_HOST}:${DI_HTTP_PORT}"
    
  3. اعتبارنامه‌هایی را که شامل نویسه‌های رزروشده هستند، درصدی‌کدگذاری کنید. نویسه‌هایی مانند @، :، / یا # در داخل رمز عبور، URL بالادستی را خراب می‌کنند. فقط مقداری را که در URL قرار می‌دهید کدگذاری کنید.

    python3 -c "import os, urllib.parse; print(urllib.parse.quote(os.environ['DI_PASS'], safe=''))"
    
  4. mitmproxy را در حالت upstream عبوردهی از طریق HTTP راه‌اندازی کنید. در حالت عبوردهی، mitmproxy ترافیک را بدون رمزگشایی تونل می‌کند، بنابراین هیچ تغییر گواهی‌نامه کلاینتی لازم نیست.

    mitmdump \
      --mode "upstream:http://${DI_USER}:${DI_PASS}@${DI_HOST}:${DI_HTTP_PORT}" \
      --listen-port 8080 \
      --ignore-hosts '.*' \
      --set flow_detail=1
    
  5. IP خروجی را تأیید کنید. mitmproxy را در پنجره ترمینال خودش در حال اجرا رها کنید و از پنجره دوم آزمایش کنید.

    curl -s -x http://127.0.0.1:8080 https://api.ipify.org
    echo
    curl -s https://api.ipify.org
    echo
    

    این دو آدرس باید متفاوت باشند. اگر یکسان باشند، درخواست به Dataimpulse نمی‌رسد — بخش عیب‌یابی را ببینید.

  6. در صورت نیاز، upstream را به SOCKS5 تغییر دهید زمانی که می‌خواهید پروکسی DNS را از راه دور resolve کند، که اغلب برای اهداف حساس به موقعیت جغرافیایی ترجیح داده می‌شود.

    mitmdump \
      --mode "upstream:socks5://${DI_USER}:${DI_PASS}@${DI_HOST}:${DI_SOCKS_PORT}" \
      --listen-port 8080 \
      --ignore-hosts '.*'
    
  7. رهگیری را فقط برای میزبان‌هایی که نیاز دارید فعال کنید. --allow-hosts رمزگشایی را به میزبان‌های منطبق محدود می‌کند؛ بقیه چیزها تونل‌شده و دست‌نخورده باقی می‌مانند.

    mitmdump \
      --mode "upstream:http://${DI_USER}:${DI_PASS}@${DI_HOST}:${DI_HTTP_PORT}" \
      --listen-port 8080 \
      --allow-hosts 'example\.com' \
      -s ./gate.py
    
  8. قبل از اسکرپینگ میزبان‌های HTTPS از طریق رهگیری، به گواهی‌نامه CA مربوط به mitmproxy اعتماد کنید. فایل‌های گواهی‌نامه اولین‌بار که mitmproxy راه‌اندازی می‌شود ایجاد می‌شوند.

    # First run generates ~/.mitmproxy/mitmproxy-ca-cert.pem
    mitmdump --listen-port 8081 &
    sleep 2
    kill %1
    
    sudo security add-trusted-cert -d -r trustRoot \
      -k /Library/Keychains/System.keychain \
      ~/.mitmproxy/mitmproxy-ca-cert.pem
    

    محیط‌های اجرای خط فرمان اغلب Keychain مک را نادیده می‌گیرند، بنابراین آن‌ها را به یک بسته صریح اشاره دهید:

    cat "$(python3 -c 'import certifi; print(certifi.where())')" \
      ~/.mitmproxy/mitmproxy-ca-cert.pem > ~/.mitmproxy/ca-bundle.pem
    
    export REQUESTS_CA_BUNDLE=~/.mitmproxy/ca-bundle.pem
    export NODE_EXTRA_CA_CERTS=~/.mitmproxy/mitmproxy-ca-cert.pem
    
  9. یک افزونه دروازه هم‌زمانی اضافه کنید تا انفجار درخواست‌ها از یک اسکرپر سریع، دروازه را سیل‌آسا نکند. این را با نام gate.py در همان دایرکتوری‌ای که mitmproxy را از آن اجرا می‌کنید ذخیره کنید.

    # gate.py — cap in-flight requests passing through mitmproxy
    import asyncio
    
    from mitmproxy import http
    
    
    class Gate:
        def __init__(self, limit: int = 8) -> None:
            self._limit = limit
            self._sem: asyncio.Semaphore | None = None
    
        def running(self) -> None:
            self._sem = asyncio.Semaphore(self._limit)
    
        async def request(self, flow: http.HTTPFlow) -> None:
            await self._sem.acquire()
            flow.metadata["gate_held"] = True
    
        def _release(self, flow: http.HTTPFlow) -> None:
            if flow.metadata.pop("gate_held", False):
                self._sem.release()
    
        def response(self, flow: http.HTTPFlow) -> None:
            self._release(flow)
    
        def error(self, flow: http.HTTPFlow) -> None:
            self._release(flow)
    
    
    addons = [Gate(limit=8)]
    

    آن را با -s ./gate.py بارگذاری کنید. توجه کنید که افزونه‌ها فقط جریان‌های رهگیری‌شده را می‌بینند: اگر با --ignore-hosts '.*' اجرا کنید، اتصال‌ها تونل می‌شوند و این hookها هرگز فعال نمی‌شوند. در آن صورت، به‌جای آن هم‌زمانی را داخل اسکرپر خود محدود کنید.

  10. ابزارهای خود را به شنونده محلی اشاره دهید. برای ابزارهای shell، متغیرهای استاندارد را در ترمینالی که از آن اسکرپ می‌کنید صادر کنید — اما نه در ترمینالی که mitmproxy را اجرا می‌کند، تا از حلقه پروکسی جلوگیری شود.

    export HTTP_PROXY=http://127.0.0.1:8080
    export HTTPS_PROXY=http://127.0.0.1:8080
    export NO_PROXY=localhost,127.0.0.1
    curl -s https://httpbin.org/ip
    

    برای یک اسکریپت Python، تا وقتی در حالت عبوردهی می‌مانید، هیچ پیکربندی CA لازم نیست:

    import requests
    
    LOCAL_PROXY = "http://127.0.0.1:8080"
    proxies = {"http": LOCAL_PROXY, "https": LOCAL_PROXY}
    
    response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30)
    response.raise_for_status()
    print(response.json())
    

    برای یک مرورگر headless، همان پروکسی محلی را به context مرورگر بدهید:

    from playwright.sync_api import sync_playwright
    
    LOCAL_PROXY = "http://127.0.0.1:8080"
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True, proxy={"server": LOCAL_PROXY})
        page = browser.new_page()
        page.goto("https://httpbin.org/ip", wait_until="domcontentloaded")
        print(page.inner_text("body"))
        browser.close()
    

    اگر همچنین نیاز دارید سرویسی را که روی دستگاه خودتان اجرا می‌شود اسکرپ کنید، Chromium به‌طور پیش‌فرض آدرس‌های loopback را دور می‌زند. افزودن args=["--proxy-bypass-list=<-loopback>"] به فراخوان راه‌اندازی، آن معافیت را حذف می‌کند.

  11. ترافیک شبیه‌ساز را ضبط کنید (اختیاری). نقاط پایانی موبایل Dataimpulse IPهای خروجی در سطح اپراتور ارائه می‌دهند؛ آن‌ها خودشان ترافیک دستگاه را ضبط نمی‌کنند. برای مسیریابی یک شبیه‌ساز از طریق آن استخر، شبیه‌ساز را به شنونده میزبان اشاره دهید.

    # Android emulator: 10.0.2.2 is the host machine
    adb shell settings put global http_proxy 10.0.2.2:8080
    adb shell settings get global http_proxy
    
    # Reset when finished
    adb shell settings put global http_proxy :0
    

    برای iOS Simulator، Settings را باز کنید، Wi-Fi را انتخاب کنید، سپس Configure Proxy، Manual، و سرور را روی 127.0.0.1 و پورت 8080 تنظیم کنید. ترافیک شبیه‌ساز از پشته شبکه مک استفاده می‌کند، بنابراین رهگیری نیازمند نصب CA در شبیه‌ساز نیز هست.

  12. پس از پایان، پاک‌سازی کنید. گواهی‌نامه رهگیری را حذف کنید و تنظیمات کلاینت را بازنشانی کنید تا ترافیک نامرتبط از mitmproxy عبور نکند.

    sudo security delete-certificate -c mitmproxy /Library/Keychains/System.keychain
    unset HTTP_PROXY HTTPS_PROXY
    

عیب‌یابی

407 Proxy Authentication Required (نیاز به احراز هویت پروکسی)

URL بالادستی فاقد اعتبارنامه است، یا یک نویسه رزروشده در رمز عبور URL را خراب کرده است. دستور درصدی‌کدگذاری در مرحله 3 را دوباره اجرا کنید و رشته --mode را با مقدار کدگذاری‌شده بازسازی کنید.

SSLCertVerificationError، CERT_AUTHORITY_INVALID، یا unable to get local issuer certificate

شما رهگیری را فعال کرده‌اید اما کلاینت به CA مربوط به mitmproxy اعتماد نمی‌کند. گواهی‌نامه را همان‌گونه که در مرحله 8 نشان داده شده نصب کنید، سپس متغیرهای بسته مخصوص محیط اجرا (REQUESTS_CA_BUNDLE، NODE_EXTRA_CA_CERTS) را تنظیم کنید. در غیر این صورت، اگر نیازی به خواندن ترافیک ندارید، با --ignore-hosts '.*' به حالت عبوردهی برگردید.

آدرس از قبل در حال استفاده است

فرایند دیگری از قبل مالک پورت است. آن را پیدا کنید، سپس به‌جای کشتن سرویس‌های نامرتبط، --listen-port را تغییر دهید.

lsof -nP -iTCP:8080 -sTCP:LISTEN

همه درخواست‌ها معلق می‌مانند یا تایم‌اوت می‌شوند

به احتمال زیاد در یک حلقه پروکسی هستید: HTTP_PROXY در همان shellی صادر شده که mitmproxy را اجرا کرده، بنابراین اتصال upstream خود mitmproxy به خودش بازفرستاده می‌شود. mitmproxy را در یک ترمینال تمیز اجرا کنید، یا قبل از راه‌اندازی آن unset HTTP_PROXY HTTPS_PROXY را اجرا کنید.

درخواست‌ها موفق‌اند اما IP خروجی هرگز تغییر نمی‌کند

حالت عبوردهی خودش چیزی را نمی‌چرخاند. رفتار چرخش با نوع sessionی که در داشبورد پیکربندی کرده‌اید و نحوه باز کردن اتصال‌ها توسط کلاینت شما تعیین می‌شود. تأیید کنید که یک session چسبنده واحد را در کل اجرا پین نکرده‌اید، و IP خروجی را با دستور مرحله 5 بررسی کنید.

شبیه‌ساز پروکسی را نادیده می‌گیرد

در شبیه‌سازهای Android، 127.0.0.1 به خود شبیه‌ساز اشاره دارد، نه به مک. از 10.0.2.2 استفاده کنید و مقدار را با adb shell settings get global http_proxy تأیید کنید.

اهداف کد 403 یا 429 برمی‌گردانند

این محدودسازی نرخ در مقصد است، نه شکست پروکسی. محدودیت دروازه در gate.py را کاهش دهید، بین درخواست‌ها تأخیر بیندازید و مطمئن شوید که اسکرپینگ شما با شرایط سایت و robots.txt سازگار است.

خلاصه

اکنون یک شنونده محلی mitmproxy روی macOS دارید که هر کلاینت را از طریق HTTP یا SOCKS5 به پروکسی‌های مسکونی یا موبایل Dataimpulse هدایت می‌کند، با حالت عبوردهی برای چرخش ساده IP و رهگیری انتخابی برای بررسی عمیق‌تر. اعتبارنامه‌ها در متغیرهای محیطی قرار دارند، هم‌زمانی با یک افزونه محدود می‌شود، و اعتماد به گواهی‌نامه را می‌توان زمانی که دیگر نیازی به خواندن ترافیک رمزنگاری‌شده ندارید، به‌صورت تمیز اضافه یا حذف کرد.