دور زدن اثر انگشت TLS/JA3 با curl_cffi

تاریخ انتشار: 23 ژوئیه 2026 · 7 دقیقه مطالعه

خلاصه: اگر اسکرپر شما حتی از یک آی‌پی خانگی تمیز هم مسدود می‌شود، تقریباً مطمئناً هدف دارد دست‌دهی TLS (JA3/JA4) و فریم‌های HTTP/2 شما را انگشت‌نگاری می‌کند. requests و httpx پایتون اثر انگشتی تولید می‌کنند که هیچ مرورگر واقعی ندارد، بنابراین پیش از بارگذاری هر محتوایی پرچم‌گذاری می‌شوید. curl_cffi امضای TLS یک مرورگر واقعی را جعل می‌کند. آن را همراه با یک پروکسی خانگی استفاده کنید — یکی اعتبار آی‌پی را حل می‌کند، دیگری اثر انگشت را، و اهداف سخت هر دو را بررسی می‌کنند.

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

یک آی‌پی خانگی تازه می‌چرخانید، یک User-Agent واقعی Chrome تنظیم می‌کنید، هدرها را از تب شبکه مرورگرتان کپی می‌کنید — و هدف بازهم 403 یا کپچای بی‌پایان ارائه می‌دهد. چیزی در درخواست اشتباه به نظر نمی‌رسد. مشکل چیزی است که نمی‌توانید از لایه اپلیکیشن تنظیم کنید: خود دست‌دهی TLS.

وقتی کلاینت شما یک اتصال HTTPS باز می‌کند، یک ClientHello ارسال می‌کند که مجموعه شیفرها، افزونه‌ها و منحنی‌هایی که پشتیبانی می‌کند را به ترتیب مشخصی فهرست می‌کند. این الگو به یک اثر انگشت JA3 (یا جدیدتر، JA4) هش می‌شود. یک Chrome واقعی یک امضا دارد؛ requests پایتون، که از OpenSSL سیستم استفاده می‌کند، امضایی کاملاً متفاوت دارد. ارائه‌دهندگان ضدربات فهرستی نگه می‌دارند از اینکه کدام اثر انگشت‌ها متعلق به مرورگرهای واقعی و کدام متعلق به کتابخانه‌های اسکریپتی است، و آن را طی دست‌دهی بررسی می‌کنند — پیش از آنکه حتی هدرها یا آی‌پی شما ارزیابی شود.

بنابراین ممکن است آی‌پی خانگی بی‌نقص و هدرهای بی‌نقص داشته باشید و بازهم پرچم‌گذاری شوید، چون اثر انگشت TLS شما می‌گوید «پایتون».

راه‌حل: با curl_cffi خود را جای یک مرورگر واقعی جا بزنید

curl_cffi یک باندینگ پایتون برای curl-impersonate است، ساختی از curl که برای بازتولید دقیق اثر انگشت‌های TLS و HTTP/2 مرورگرهای واقعی پچ شده. API آن عمداً requests را بازتاب می‌دهد، بنابراین پذیرفتن آن عمدتاً یک تغییر یک‌خطی است.

pip install curl_cffi

یک درخواست پایه که Chrome را جعل می‌کند:

from curl_cffi import requests

r = requests.get("https://example.com", impersonate="chrome")
print(r.status_code, r.text[:200])

آرگومان impersonate اصل موضوع است — به curl_cffi می‌گوید ترتیب شیفر/افزونه Chrome را ارسال کند تا هش JA3 با یک مرورگر واقعی مطابقت داشته باشد. می‌توانید یک نسخه خاص را ثابت کنید (chrome124، chrome131، safari17_0، firefox133) یا chrome را برای مقدار پیش‌فرض اخیر پاس دهید.

افزودن یک پروکسی خانگی

اثر انگشت اکنون درست است، اما یک هدف سخت همچنان آی‌پی خروجی را زیر نظر دارد. درخواست را از طریق یک پروکسی خانگی با همان آرگومان proxies= که از requests می‌شناسید مسیردهی کنید:

from curl_cffi import requests

proxies = {"https": "http://USER:PASS@gw.roamproxy.com:41080"}

r = requests.get(
    "https://example.com",
    impersonate="chrome124",
    proxies=proxies,
)
print(r.status_code)

اکنون دست‌دهی مثل Chrome به نظر می‌رسد و اتصال از یک آی‌پی واقعی اینترنت خانگی خارج می‌شود. این دقیقاً همان ترکیبی است که اهداف سخت واقعاً در جستجوی آن هستند. curl_cffi همچنین یک پروکسی SOCKS5 را نیز می‌پذیرد، اگر ترجیح می‌دهید — از socks5://USER:PASS@gw.roamproxy.com:41080 به‌عنوان مقدار استفاده کنید.

از کاراکترهای خاص در رمز عبور پروکسی پرهیز کنید. مقدار پروکسی به‌عنوان یک URL تجزیه می‌شود، بنابراین یک #، @، / یا : در رمز عبور، تجزیه را می‌شکند. آن‌ها را درصدی رمزگذاری کنید (# به %23 تبدیل می‌شود) یا رمز عبور را بدون آن‌ها دوباره تولید کنید.

یک نشست برای درخواست‌های زیاد

برای یک خزش واقعی، یک نشست را دوباره استفاده کنید تا اتصال و اثر انگشت فقط یک‌بار تنظیم شوند:

from curl_cffi import requests

session = requests.Session(impersonate="chrome124")
session.proxies = {"https": "http://USER:PASS@gw.roamproxy.com:41080"}

for url in urls:
    r = session.get(url)
    ...

برای پخش کردن یک کار بزرگ در میان آی‌پی‌های خروجی زیاد، از یک نشست چرخشی استفاده کنید تا هر درخواست از یک آی‌پی خانگی متفاوت خارج شود؛ برای نگه‌داشتن یک آی‌پی در طول یک روند ورود، از یک نشست ثابت استفاده کنید. اینکه کدام را می‌خواهید و رشته نشست چگونه آن را کنترل می‌کند، در پروکسی‌های چرخشی چیستند پوشش داده شده است.

تأیید کنید اثر انگشت واقعاً تغییر کرده

JA3 خود را پیش و پس از تغییر بررسی کنید. یک نقطه پایانی اکو اثر انگشت، هشی را که سرور می‌بیند برمی‌گرداند:

from curl_cffi import requests

print(requests.get("https://tls.browserleaks.com/json", impersonate="chrome").json()["ja3_hash"])

همان فراخوانی را با requests ساده اجرا کنید و هش متفاوتی خواهید گرفت — آن تفاوت دقیقاً همان چیزی است که هدف روی آن مسدود می‌کرد.

اشتباهات رایج

برای تصویر گسترده‌تری از اینکه چرا درخواست‌ها مسدود می‌شوند و چه چیز دیگری را باید بررسی کرد، به چگونه در وب‌اسکرپینگ مسدود نشویم مراجعه کنید.

سوالات متداول

چرا حتی با یک پروکسی خانگی تازه هم مسدود می‌شوم؟

چون آی‌پی فقط یکی از سیگنال‌هاست. سیستم‌های ضدربات مثل Cloudflare، DataDome و Akamai، در همان لحظه باز شدن اتصال، ClientHello شما در TLS (JA3/JA4) و ترتیب فریم‌های HTTP/2 را انگشت‌نگاری می‌کنند — پیش از آنکه اعتبار آی‌پی یا هدرهای شما را ببینند. استک پیش‌فرض پایتون اثر انگشتی تولید می‌کند که هیچ مرورگر واقعی آن را ندارد، بنابراین فارغ از تمیزی آی‌پی خروجی، شما به‌عنوان اتوماسیون امتیازدهی می‌شوید. پروکسی خانگی و اثر انگشت دقیق مرورگر، دو راه‌حل جدا برای دو بررسی جداگانه‌اند؛ اهداف سخت هر دو را بررسی می‌کنند.

دقیقاً اثر انگشت JA3 چیست؟

JA3 هش برخی فیلدهای مشخص در ClientHello TLS است — مجموعه شیفرهایی که کلاینت شما پیشنهاد می‌دهد، افزونه‌ها، منحنی‌های بیضوی، دقیقاً به همان ترتیبی که ارسال می‌کند. کلاینت‌های مختلف HTTP این‌ها را متفاوت مرتب می‌کنند، بنابراین هش عملاً نرم‌افزار ارسال‌کننده درخواست را شناسایی می‌کند. Chrome واقعی یک JA3 تولید می‌کند؛ requests پایتون (از طریق OpenSSL) کاملاً متفاوتی تولید می‌کند. JA4 جانشین جدیدتر و دقیق‌تر آن است. curl_cffi ترتیب یک مرورگر واقعی را بازتولید می‌کند تا هش با Chrome یا Safari مطابقت داشته باشد، نه با «پایتون».

آیا curl_cffi به‌تنهایی و بدون پروکسی کافی است؟

برای یک سایت با محافظت سبک، گاهی بله. برای هر چیز جدی، نه. جعل اثر انگشت شما را از بررسی TLS/HTTP2 عبور می‌دهد، اما اگر صدها درخواست از یک آی‌پی دیتاسنتر ارسال کنید، بازهم محدود به نرخ می‌شوید یا بر اساس اعتبار آی‌پی مسدود می‌شوید. راه‌حل قابل‌اعتماد، curl_cffi برای اثر انگشت به‌علاوه یک پروکسی خانگی چرخشی برای آی‌پی است — برای اینکه چرا نوع آی‌پی اهمیت دارد، به خانگی در برابر دیتاسنتر مراجعه کنید.

requests، httpx یا curl_cffi — از کدام استفاده کنم؟

requests و httpx برای APIها و سایت‌هایی که انگشت‌نگاری نمی‌کنند مناسب‌اند. همان لحظه‌ای که هدفی پشت Cloudflare/DataDome/Akamai است و با وجود هدرهای درست و آی‌پی خوب شما را مسدود می‌کند، به curl_cffi سوییچ کنید — API آن تقریباً کاملاً مثل requests است، بنابراین مهاجرت معمولاً فقط تغییر یک خط import به‌علاوه یک آرگومان impersonate= است.

curl_cffi اثر انگشت را اصلاح می‌کند؛ یک آی‌پی خروجی تمیز اعتبار را اصلاح می‌کند. Roam آی‌پی‌های خانگی چرخشی با $2 در هر گیگابایت و خانگی ثابت با $4 در هر آی‌پی در ماه از طریق HTTP و SOCKS5 به شما می‌دهد، بنابراین مستقیم در آرگومان proxies= بالا جا می‌افتد. یک حساب بسازید و 300 مگابایت ترافیک آزمایشی رایگان بگیرید تا این ترکیب را روی هدف خودتان تست کنید.