Frequently Asked Questions
Pyinstaller ModuleNotFoundError: No module named '_cffi_backend'
You need to tell pyinstaller to pack cffi and data files inside the package:
pyinstaller -F .\example.py --hidden-import=_cffi_backend --collect-all curl_cffi
See also issue #48 for additional parameters.
Using https proxy, error: OPENSSL_internal:WRONG_VERSION_NUMBER
You are messing up https-over-http proxy and https-over-https proxy, for most cases, you
should change {"https": "https://localhost:3128"} to {"https": "http://localhost:3128"}.
Note the protocol in the url for https proxy is http not https.
See this issue for a detailed explanation.
Why does the JA3 fingerprints change for Chrome 110+ impersonation?
This is intended.
Chrome introduces ClientHello permutation in version 110, which means the order of
extensions will be random, thus JA3 fingerprints will be random. So, when comparing
JA3 fingerprints of curl_cffi and a browser, they may differ. However, this does not
mean that TLS fingerprints will not be a problem, ClientHello extension order is just
one factor of how servers can tell automated requests from browsers.
Roughly, this can be mitigated like:
ja3 = md5(list(extensions), ...other arguments)
ja3n = md5(set(extensions), ...other arguments)
See more from this article and curl-impersonate notes.
I'm getting certs errors
The simplest way is to turn off cert verification by verify=False:
r = requests.get("https://example.com", verify=False)
curl_cffi.CurlError: Failed to perform, ErrCode: 92, Reason: 'HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)'
Try remove the Content-Length header from you request. see #19.
Or, you can just force curl to use http 1.1 only.
from curl_cffi import requests, CurlHttpVersion
r = requests.get("https://postman-echo.com", http_version=CurlHttpVersion.v1_1)
Not working on Windows, NotImplementedError
Accroding to the Python docs:
Changed in version 3.8: On Windows, ProactorEventLoop is now the default event loop. The loop.add_reader() and loop.add_writer() methods are not supported.
You can use the SelectorEventLoop instead.
import sys, asyncio
if sys.version_info >= (3, 8) and sys.platform.lower().startswith("win"):
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())