# curl_cffi против requests: что исправляет и что не может

Замена requests на curl_cffi превращает множество 403 в 200. Это также не помогает при заблокированном IP. Вот граница между ними и пятнадцатиминутный тест, который покажет, на какой стороне ваша проблема.

Вопрос curl_cffi против requests обычно возникает в разгар инцидента: скрейпер, который работал месяцами, начинает возвращать 403 на первом вызове, кто-то на Reddit говорит заменить клиент, и это работает. Это реальный эффект с реальным объяснением — но то, как это повторяется ("просто используйте curl_cffi"), скрывает как то, что происходит, так и где это перестает помогать. requests не медленный и не плохо написан. У него есть ровно один недостаток в контексте скрейпинга, он значительный, и он не имеет ничего общего с API, который вы вводите. Здесь клиенты действительно различаются, что меняется при переключении, и одна вещь, которую имитация никогда не исправит, независимо от того, какую библиотеку вы выберете.

## Единственное различие, которое имеет значение

Обе библиотеки отправляют одинаковые заголовки. Различие в одном уровне ниже, в TLS рукопожатии, которое открывает соединение до того, как передается первый байт HTTP. requests использует urllib3 и OpenSSL, которые рекламируют список шифров, набор расширений и порядок, принадлежащие Python и ничему другому. curl_cffi — это привязка к исправленной версии curl, которая воспроизводит ClientHello браузера байт за байтом, вместе с его HTTP/2 SETTINGS кадром — так что его JA3, JA3N и Akamai хэши совпадают с настоящим Chrome, а не с библиотекой скриптов. Поставщики антиботов ведут базы данных этих подписей; несоответствие между заголовком User-Agent Chrome и рукопожатием Python — это противоречие, которое невозможно объяснить. Мы разобрали механику в [JA3 и JA4 отпечатках](https://quantumproxies.io/blog/tls-ja3-fingerprinting-scraping), и тот же эффект объясняет, почему [curl получает 403, где ваш браузер получает 200](https://quantumproxies.io/blog/curl-403-but-browser-works) на идентичном URL.

Все остальное в сравнении следует из реализации. Поскольку curl_cffi оборачивает libcurl, он наследует HTTP/2, HTTP/3, вебсокеты и asyncio, ни одно из которых requests никогда не поддерживал. Поскольку requests написан на чистом Python, он устанавливается на что угодно и имеет десятилетнюю экосистему. Оба утверждения верны одновременно, и какое из них доминирует, зависит полностью от вашей цели.

## Воспроизводимый тест, который вы можете провести за пять минут

Не доверяйте таблице пропусков никого, включая нашу. Различие в отпечатках можно наблюдать напрямую: направьте оба клиента на TLS-echo endpoint и сравните хэши, которые они возвращают. Если две строки совпадают, ваша сборка ничего не имитирует.

```python
# pip install requests curl_cffi
import requests
import curl_cffi

URL = "https://tls.browserleaks.com/json"

a = requests.get(URL, timeout=30).json()
b = curl_cffi.get(URL, impersonate="chrome", timeout=30).json()

print("requests   ja3n:", a["ja3n_hash"], "| akamai:", a.get("akamai_hash", "-"))
print("curl_cffi  ja3n:", b["ja3n_hash"], "| akamai:", b.get("akamai_hash", "-"))

# Two different ja3n hashes = impersonation is working. The curl_cffi README
# documents aa56c057ad164ec4fdcb7a5a283be9fc as a Chrome-matched ja3n value.
# The akamai (HTTP/2) fingerprint is usually empty for requests: it is
# HTTP/1.1 only, so there is no SETTINGS frame to fingerprint in the first place.
```

С версии v0.15 есть однострочная версия той же проверки: `curl-cffi get tls.browserleaks.com/json --impersonate chrome`. Запустите это перед тем, как отлаживать что-либо еще — это отделяет "моя имитация неправильно настроена" от "моя имитация в порядке, и что-то еще меня блокирует", что совершенно разные ситуации.

![Сравнение requests и curl_cffi бок о бок по протоколам, параллелизму, отпечаткам и портативности: curl_cffi выигрывает по HTTP/2, HTTP/3, asyncio и TLS-отпечатку, совпадающему с Chrome, requests выигрывает по портативности и экосистеме, и ни один не решает вопрос качества IP, ведь это не функция клиента.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785776553/blog/generated/qp-b10-007-diag1.png)
*requests выигрывает по портативности и экосистеме; curl_cffi выигрывает по протоколам и отпечаткам. Ни один не выигрывает по качеству IP — это не функция клиента.*

## Что curl_cffi не исправляет: репутация IP

Вот часть, которую упускают из виду в совете "замените библиотеку". TLS отпечаток отвечает на вопрос "какое это программное обеспечение?". Он ничего не говорит о "откуда это?" — и на этот второй вопрос отвечает отдельный запрос к вашему выходному IP: какой ASN владеет им, является ли это хостинг-провайдером или потребительским ISP, появлялся ли он в списках злоупотреблений, сколько других сессий было с этого адреса на этот сайт за последний час. Безупречное рукопожатие Chrome, прибывающее из облачного VM в диапазоне датацентра, это браузер Chrome, который, по-видимому, установлен в стойке сервера. Это не более убедительно, чем python-requests. В некоторых случаях это даже менее убедительно, потому что противоречие более явное.

FAQ проекта ставит качество IP на первое место в списке факторов, перед частотой запросов и отпечатками JavaScript, объясняя, почему одной имитации может быть недостаточно. Этот порядок не случаен: репутация — это самый дешевый сигнал для оценки защитником и самый сложный для подделки атакующим, потому что, в отличие от заголовка или списка шифров, вы не можете сгенерировать его локально. Если ваш скрейпер на базе requests уже работал через пул датацентра и блокировался, переход на curl_cffi в том же пуле изменяет одну из двух провальных проверок. Вы увидите частичное улучшение на мягких целях и никакого улучшения на жестких — это именно тот запутанный результат, о котором сообщают люди.

Исправление для этой оси — это качество адреса, а не код: [резидентные IP](https://quantumproxies.io/residential-proxies) от реальных потребительских ISP, что дает вам более 90 миллионов адресов в более чем 200 странах. Если вы хотите проверить, как выглядит ваш текущий выходной IP, прежде чем что-то менять, наш бесплатный [проверщик качества IP](https://quantumproxies.io/ip-checker) сообщает ASN и классификацию, которую увидит цель.

## 2x2, который покажет, какая ось сломана

Вместо того чтобы гадать, протестируйте обе переменные независимо на вашей реальной цели. Четыре запроса, четыре строки вывода, и результат назовет вашу проблему:

```python
import requests
import curl_cffi

TARGET = "https://your-target.example/api/items"
DC  = "http://USER:PASS@your-datacenter-gateway:PORT"
RES = "http://USER:PASS@residentialpremium.quantumproxies.io:8080"

def probe(label, fn):
    try:
        print(f"{label:26} -> {fn().status_code}")
    except Exception as e:
        print(f"{label:26} -> {type(e).__name__}")

probe("requests  + datacenter",
      lambda: requests.get(TARGET, proxies={"https": DC}, timeout=30))
probe("curl_cffi + datacenter",
      lambda: curl_cffi.get(TARGET, proxy=DC, impersonate="chrome", timeout=30))
probe("requests  + residential",
      lambda: requests.get(TARGET, proxies={"https": RES}, timeout=30))
probe("curl_cffi + residential",
      lambda: curl_cffi.get(TARGET, proxy=RES, impersonate="chrome", timeout=30))
```

Читайте четыре результата как таблицу истинности:

- **Только строки датацентра не проходят** — это репутация IP. Клиент не имеет значения; купите лучшие выходы.
- **Только строки requests не проходят** — это отпечаток TLS. Переключите клиент и оставьте существующий пул.
- **Только последняя строка проходит** — обе проверки активны. Вам нужны имитация и чистые IP вместе; это обычный случай на серьезных целях.
- **Все четыре не проходят** — вы за пределами того, что может сделать любой HTTP клиент. Это означает JavaScript вызов, токен, который вы не генерируете, или блокировку на уровне учетной записи. Используйте реальный браузер или управляемый [Scraper API](https://quantumproxies.io/scraper-api).
- **Все четыре проходят** — у вас никогда не было проблемы с отпечатками. Не добавляйте зависимость.

Запустите это несколько десятков раз, а не один раз. Оба уровня блокировки вероятностные, и один 200 почти ничего не говорит.

[Тестируйте строку резидентных IP с реальными домашними IP](https://quantumproxies.io/residential-proxies)

![Одно и то же TLS-рукопожатие curl_cffi, совпадающее с браузерным, отправлено с двух выходов: с IP датацентра его отклоняют по репутации, с резидентного IP оно проходит. Карточка разбирает два отдельных барьера, TLS-отпечаток и репутацию IP, и объясняет, почему исправление только одного из них все равно заканчивается блокировкой.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785776554/blog/generated/qp-b10-007-diag2.png)
*Имитация и репутация IP — это отдельные ворота. Исправление одного и оставление другого — вот почему "я переключился на curl_cffi и ничего не изменилось" — это такой распространенный отчет.*

## Когда дополнительная зависимость не стоит того

Откровенность дешевле, чем переписывание. Оставайтесь на requests, когда:

- **Вы вызываете API, который вам разрешено вызывать.** Документированные endpoints с вашим собственным ключом не отпечатывают вас. Добавление имитации здесь — это карго-культ.
- **Ваша цель развертывания неудобна.** curl_cffi поставляется с компилированными wheels и требует Python 3.10 или новее с версии v0.14. requests работает практически на всем, включая старые образы и ограниченные встроенные среды.
- **Вы зависите от экосистемы requests.** Пользовательские адаптеры, requests-cache, requests-oauthlib и подобные все подключаются к транспортному уровню, который curl_cffi намеренно не раскрывает.
- **Вам нужны повторные попытки по коду состояния из коробки.** `Retry` из urllib3 с `status_forcelist` повторяет попытки на 429 и 503; параметр `retry` curl_cffi повторяет только при транспортных исключениях.
- **Ваши блокировки поведенческие.** Ограничения скорости, блокировки учетных записей и квоты на сессию не зависят от рукопожатия.

И есть средний путь, который большинство людей упускает: вам не нужно отказываться от requests, чтобы получить рукопожатие. Поддерживающие указывают на curl-adapter, который монтирует curl_cffi как транспортный адаптер для requests, и httpx-curl-cffi на PyPI, который делает то же самое для httpx. Вы сохраняете свой существующий код и экосистему, и только байты на проводе меняются.

## Подводные камни миграции, которые стоит знать заранее

API достаточно близок, чтобы большинство скриптов работали после изменения импорта, но страница совместимости перечисляет реальные различия, и стоит их прочитать перед крупным портом. Тела ответов на перенаправления не сохраняются в `Response.history`. Cookies с пустыми доменами могут теряться при перенаправлениях. Потоковые объекты ответов не могут быть сериализованы, хотя обычные ответы могут. API файлов немного отличается. И вообще нет транспортов или адаптеров, потому что библиотека намеренно приварена к libcurl-impersonate. Конфигурация прокси также отличается небольшим образом, который сбивает людей с толку:

```python
# requests: dict, and retries mounted on an adapter
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

s = requests.Session()
s.mount("https://", HTTPAdapter(max_retries=Retry(total=4, status_forcelist=[429, 503])))
r = s.get(url, proxies={"https": "http://USER:PASS@residentialpremium.quantumproxies.io:8080"}, timeout=30)

# curl_cffi: single proxy string preferred, retries are a session parameter
from curl_cffi import Session
from curl_cffi.requests import RetryStrategy

s = Session(
    impersonate="chrome",
    proxy="http://USER:PASS@residentialpremium.quantumproxies.io:8080",
    retry=RetryStrategy(count=4, delay=1.0, backoff="exponential"),
    timeout=30,
)
r = s.get(url)  # note: retry fires on transport errors, not on 429/503
```

Полная поверхность прокси — ключи словаря, `proxy_auth`, ротация по запросу, async и префикс `https://`, который вызывает бесполезную ошибку WRONG_VERSION_NUMBER — покрыта шаг за шагом в нашем [руководстве по прокси curl_cffi](https://quantumproxies.io/blog/curl-cffi-proxy-guide). Если вы остаетесь на месте, эквивалентная ссылка для другой стороны — это наше [руководство по прокси Python Requests](https://quantumproxies.io/blog/python-requests-proxy-guide).

## Часто задаваемые вопросы

### curl_cffi быстрее requests?

Да, и бенчмарки проекта ставят его наравне с aiohttp и pycurl, а не с requests. Прирост идет от того, что libcurl выполняет работу на C плюс мультиплексирование HTTP/2, а не от хитрого Python. Для нескольких последовательных вызовов разница незаметна; при высокой параллельности, особенно с async, она значительна.

### curl_cffi безопасен в использовании?

Он лицензирован по MIT, широко используется и поставляется с предварительно скомпилированными wheels, так что нет этапа сборки для аудита. Стоит обратить внимание на одно предупреждение: в версии v0.15.0 есть рекомендация по поводу SSRF на основе перенаправлений. Если вы получаете URL от других людей, установите `allow_redirects="safe"` или отключите перенаправления. Имитация браузера — это техническая мера, а не разрешение игнорировать условия сайта.

### curl_cffi обходит Cloudflare?

Он убирает отпечатки TLS и HTTP/2, что устраняет базовые уровни защиты. Он не может выполнить JavaScript вызов, решить Turnstile или исправить помеченный выходной IP. Поддерживающие говорят об этом в своем FAQ и рекомендуют лучший пул прокси плюс автоматизацию браузера для более высоких уровней.

### curl_cffi против httpx или tls_client — что мне использовать?

httpx дает вам HTTP/2 и async, но без имитации отпечатков, так что он находится между requests и curl_cffi по скрытности. tls_client также подделывает профили TLS и имеет схожие бенчмарки; curl_cffi имеет более крупное сообщество и добавляет HTTP/3 и вебсокеты. Если httpx уже в вашем стеке, транспорт httpx-curl-cffi дает вам имитацию без переписывания.

Краткая версия: переключайтесь на curl_cffi, когда ваша цель читает рукопожатия, оставайтесь на requests, когда этого не происходит, и никогда не ожидайте, что любой из выборов очистит IP датацентра. Клиенты различаются по одной оси, прокси по другой, и заблокированные скрейперы почти всегда история о том и другом. Запустите четыре проверки, прочитайте таблицу истинности и исправьте ось, на которую указывает данные, а не ту, о которой кричал интернет.

[Исправьте ось, которую не может достичь имитация](https://quantumproxies.io/residential-proxies)
