tlsreq
English | 简体中文
A single Session / AsyncSession API over four TLS-capable HTTP stacks:
curl_cffi · wreq · niquests + xutls · httpx + xutls
Change backend and impersonate. Request code stays the same.
Install
pip install tlsreq # httpx + h2 + brotli + zstd + xutls
pip install "tlsreq[niquests]" # or wreq / curl_cffi / all
pip install tlsreq pulls the default httpx stack: HTTP/2 (h2), br/zstd body decoding, and Chrome 152 TLS via xutls.
| Extra | Pulls in | Notes |
|---|---|---|
| (default) | httpx, h2, brotli, zstandard, xutls | Chrome 152 TLS + HTTP/2; decodes br/zstd |
httpx |
(already in the default install) | Kept so tlsreq[httpx] still works |
niquests |
niquests | Chrome 152 TLS + HTTP/2 patches |
wreq |
wreq | Python ≥ 3.11 only; skipped on 3.9/3.10 |
curl_cffi |
curl_cffi | |
all |
niquests, curl_cffi; wreq if Python ≥ 3.11 |
xutls import name is still utls. Do not also install the upstream utls package — both provide the utls module. To upgrade later: pip install -U xutls.
Quick start
import asyncio
from tlsreq import AsyncSession, Session
async def main():
async with AsyncSession(
backend="niquests",
impersonate="chrome152",
proxy="http://user:pass@host:port",
timeout=30,
extra={"pool_maxsize": 1},
) as s:
r = await s.get("https://tls.peet.ws/api/all")
print(r.status_code, r.http_version, r.cookies)
print(r.json()["tls"]["ja4"])
r = await s.post(
"https://example.com/login",
data=b"user=a&pass=b",
headers={"content-type": "application/x-www-form-urlencoded"},
header_order=["user-agent", "accept", "content-type"],
)
print(r.status_code, r.text)
asyncio.run(main())
with Session("wreq", "chrome149", proxy="http://127.0.0.1:7890") as s:
r = s.get("https://example.com")
print(r.status_code, r.headers)
The native client is on session.raw when you need a backend-specific knob.
Backends
backend |
Default impersonate | Latest Chrome alias | Sync | Async |
|---|---|---|---|---|
niquests |
chrome:152 |
chrome152 |
yes | yes |
httpx |
chrome:152 |
chrome152 |
yes | yes |
curl_cffi |
chrome150 |
chrome150 |
yes | yes |
wreq |
Chrome149 |
chrome149 |
yes | yes |
Unknown backend or impersonate values raise. There is no silent fallback to another profile.
chrome / chromestable map to that backend’s current default. wreq also accepts its native names (Firefox151, Safari18_5, Edge148, Opera131, OkHttp5, …). curl_cffi accepts firefox, safari, edge, chrome_android, tor, and the library’s versioned profiles.
httpx / niquests offer both HTTP/2 and HTTP/1.1. The protocol is chosen from the negotiated TLS ALPN (h2 vs http/1.1); an HTTP/1.1-only origin falls back instead of failing.
Chrome 152 (niquests / httpx)
These two backends apply Chrome 152 HTTP/2 framing on top of xutls ClientHello impersonation:
| Signal | Value |
|---|---|
| SETTINGS | 1:65536;2:0;4:6291456;6:262144 |
| WINDOW_UPDATE | 15663105 |
| HEADERS priority | exclusive, weight 256 |
| Pseudo-header order | m,a,s,p |
| JA4 | t13d1517h2_8daaf6152771_cb7bf5808d99 |
| Akamai fingerprint | 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p |
Checked against tls.peet.ws.
curl_cffi and wreq use their own stacks; they do not take this HTTP/2 patch.
API
Session / AsyncSession
Session(
backend: str,
impersonate: str | None = None,
*,
proxy: str | None = None,
timeout: float = 30,
verify: bool = True,
headers: dict | None = None,
cookies: dict | None = None,
allow_redirects: bool = True,
extra: dict | None = None,
)
Context-manager safe. AsyncSession methods are coroutines.
Requests
get / post / put / patch / delete / head / options all call request.
| Argument | Meaning |
|---|---|
headers |
Per-request headers |
params |
Query string |
data |
Form dict or raw body (str / bytes) |
json |
JSON body |
cookies |
Per-request cookies |
timeout |
Override session timeout |
allow_redirects |
Override session redirect flag |
header_order |
Wire order of header names, when the backend supports it |
extra |
Backend-specific kwargs for this call |
extra on the session is merged into the underlying constructor; extra on a request is merged into that call. Later keys win.
Response
Body is fully read when the response is wrapped. .text and .json() are synchronous on both Session types.
| Attribute | Type |
|---|---|
status_code |
int |
content |
bytes |
text |
str |
headers |
dict[str, str] |
cookies |
dict[str, str] |
url |
str |
http_version |
str | None |
raw |
native response |
session.cookies is the cookie jar as a dict. session.set_cookies(dict, url=None) writes into it.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tlsreq-0.1.6.tar.gz.
File metadata
- Download URL: tlsreq-0.1.6.tar.gz
- Upload date:
- Size: 27.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2b0e924bd752c2819808e1dbb0896a462066b76236905ae6568825193aeef30
|
|
| MD5 |
86ed5382dd138af0304ca61978d5a711
|
|
| BLAKE2b-256 |
18494eeeef90073ce699b806f2862214560ca37664c0f72c3d76f02cf1dd56db
|
File details
Details for the file tlsreq-0.1.6-py3-none-any.whl.
File metadata
- Download URL: tlsreq-0.1.6-py3-none-any.whl
- Upload date:
- Size: 26.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
579a40f038bdcf0fd33826faaee0519619126e6c5da67905c054cd010263c5ed
|
|
| MD5 |
9e794a45868883b220a96ec052b76113
|
|
| BLAKE2b-256 |
655396292d1916fecb3ba9c4500bb6996e8e80f60e5301c5910eda03925fba0d
|