Skip to main content

Browser TLS fingerprint impersonation library powered by Rust (BoringSSL + hyper).

Project description

rqsession

中文 | English

A Python HTTP library that impersonates real browser TLS fingerprints, powered by a Rust native extension (BoringSSL + hyper + tokio).

PyPI version Python versions License


What it does

Most anti-bot systems (Cloudflare, Akamai, DataDome, etc.) inspect the TLS ClientHello and HTTP/2 SETTINGS frame to distinguish scrapers from real browsers. Standard requests or httpx produce a recognizable Python fingerprint regardless of what User-Agent you set.

rqsession controls the full fingerprint stack at the Rust level:

Layer What is controlled
TLS ClientHello Cipher suite order, supported groups (curves), ALPN, signature algorithms, version range
HTTP/2 SETTINGS frame values (window size, max frame size), connection WINDOW_UPDATE
HTTP headers Exact header order, browser-specific headers (sec-ch-ua, sec-fetch-*, etc.)

No external proxy process required — it's a compiled .pyd / .so extension, imported directly.


Installation

pip install rqsession

Pre-built wheels are available for Windows x86_64 and Linux x86_64 (Python 3.9+).
Other platforms require a local Rust toolchain to build from the source distribution.


Quick Start

Synchronous

from rqsession.rust_session import BrowserSession, Chrome120

with BrowserSession(Chrome120) as s:
    resp = s.get("https://httpbin.org/get")
    print(resp.status_code)   # 200
    print(resp.json())

Async

import asyncio
from rqsession.rust_session import AsyncBrowserSession, Chrome120

async def main():
    async with AsyncBrowserSession(Chrome120) as s:
        resp = await s.get("https://httpbin.org/get")
        print(resp.status_code)
        print(resp.json())

asyncio.run(main())

Concurrent async requests

import asyncio
from rqsession.rust_session import AsyncBrowserSession, Chrome120

async def main():
    async with AsyncBrowserSession(Chrome120) as s:
        results = await asyncio.gather(
            s.get("https://httpbin.org/get"),
            s.get("https://httpbin.org/ip"),
            s.get("https://httpbin.org/user-agent"),
        )
    for r in results:
        print(r.status_code)

asyncio.run(main())

Built-in Browser Profiles

Import name Browser OS
Chrome138 Chrome 138 Windows
Chrome120 Chrome 120 Windows
Chrome119 Chrome 119 Windows
Edge147 Edge 147 Windows
Edge142 Edge 142 Windows
Edge141 Edge 141 Windows
Firefox146 Firefox 146 Windows
Firefox133 Firefox 133 Windows
Tor128 Tor Browser 128 Windows
Safari17 Safari 17 macOS
MacosChrome140 Chrome 140 macOS
AndroidChrome114 Chrome 114 Android
Py37Aiohttp381 Python aiohttp 3.8.1 Windows
from rqsession.rust_session import (
    BrowserSession, AsyncBrowserSession,
    Chrome138, Chrome120, Chrome119,
    Edge147, Edge142, Edge141,
    Firefox146, Firefox133,
    Tor128, Safari17, MacosChrome140,
    AndroidChrome114, Py37Aiohttp381,
)

Each profile carries its own cipher suite order, curves, signature algorithms, HTTP/2 settings, and header order — matching the real browser's wire behavior.


Proxy Support

Both sync and async sessions accept a proxy URL at construction time:

# HTTP proxy
s = BrowserSession(Chrome120, proxy="http://127.0.0.1:7890")

# Authenticated proxy
s = BrowserSession(Chrome120, proxy="http://user:pass@host:port")

# Async
async with AsyncBrowserSession(Firefox133, proxy="http://127.0.0.1:7890") as s:
    resp = await s.get("https://example.com")

The proxy tunnel is implemented as an HTTP CONNECT connection at the TCP level, so TLS fingerprinting applies end-to-end through the tunnel.


Session API

Constructor parameters

BrowserSession(
    profile,              # built-in constant or BrowserProfile object
    *,
    proxy=None,           # "http://[user:pass@]host:port"
    verify=True,          # set False to skip SSL verification
    ca_bundle=None,       # path to CA bundle; auto-detects certifi when None
)
# AsyncBrowserSession takes the same parameters

Request methods

# GET
resp = s.get(url, headers={...}, params={...})

# POST — form data or JSON
resp = s.post(url, data=b"...", headers={...})
resp = s.post(url, json={"key": "value"})

# Generic
resp = s.request("PUT", url, headers={...}, json={...})

# Async versions — same signature, add `await`
resp = await s.get(url)
resp = await s.post(url, json={...})

# Disable redirect following (default: allow_redirects=True)
resp = s.get(url, allow_redirects=False)   # returns the 3xx directly
resp = await s.get(url, allow_redirects=False)

Response object

Compatible with requests.Response style:

resp.status_code    # int
resp.text           # str (auto-decoded)
resp.content        # bytes
resp.headers        # dict[str, str]
resp.json()         # parsed JSON → dict / list
resp.ok             # True when status < 400
resp.raise_for_status()   # raises on 4xx/5xx
resp.url            # final URL after redirects

Response bodies are automatically decompressed (gzip, deflate, br, zstd).

Cookies

# Persist cookies manually
s.update_cookies({"token": "abc123"})

# Cookies from Set-Cookie response headers are automatically
# stored in the session and sent on subsequent requests.

Adding Custom Browser Profiles

Capture a fingerprint from a real browser using tls.peet.ws/api/all, then convert it:

# Save output from tls.peet.ws as chrome136.json, then:
python tools/tls_peet_to_profile.py chrome136.json -n chrome136_windows --install

The --install flag writes the profile directly to rqsession/rust_session/profiles/builtin/.
You can also load profiles at runtime without rebuilding:

from rqsession.rust_session import BrowserSession, load_custom, load_profile_json
from rqsession._rust_core import load_profile

# From profiles/custom/<name>.json
s = BrowserSession(load_custom("my_browser"))

# From a JSON string
s = BrowserSession(load_profile_json('{"name": "...", "tls": {...}, ...}'))

# From an arbitrary file path
s = BrowserSession(load_profile("/path/to/profile.json"))

# List available profiles
from rqsession.rust_session import list_builtin, list_custom
print(list_builtin())   # ['chrome120_windows', 'firefox133_windows', ...]
print(list_custom())    # ['my_browser', ...]

Windows asyncio note

Python 3.8+ on Windows uses ProactorEventLoop by default. If you see event-loop errors, switch to SelectorEventLoop before asyncio.run():

import asyncio, sys

if sys.platform == "win32":
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

asyncio.run(main())

Legacy layers

Earlier versions of this library included RequestSession and EnhancedRequestSession. These layers are still available for backward compatibility:

from rqsession import RequestSession          # basic requests.Session wrapper
from rqsession import EnhancedRequestSession  # requests.Session wrapper with browser headers

For new projects, use BrowserSession / AsyncBrowserSession instead — they are faster, require no external process, and provide more accurate fingerprinting.


License

Apache 2.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rqsession-0.4.7.tar.gz (281.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rqsession-0.4.7-cp38-abi3-win_amd64.whl (2.1 MB view details)

Uploaded CPython 3.8+Windows x86-64

rqsession-0.4.7-cp38-abi3-manylinux_2_28_x86_64.whl (2.2 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.28+ x86-64

rqsession-0.4.7-cp38-abi3-manylinux_2_28_aarch64.whl (2.1 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.28+ ARM64

File details

Details for the file rqsession-0.4.7.tar.gz.

File metadata

  • Download URL: rqsession-0.4.7.tar.gz
  • Upload date:
  • Size: 281.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.0

File hashes

Hashes for rqsession-0.4.7.tar.gz
Algorithm Hash digest
SHA256 2535e0eee181bc1267fecd86127df1ae54e6adc32f6d44134b54408d1b37334a
MD5 25a974c0fece6b2d7235f215c3101a8d
BLAKE2b-256 0b7b3cda48cea24c97e23036f30bc4e509cdd6d96bfbdb1bc80356fc936b68a7

See more details on using hashes here.

File details

Details for the file rqsession-0.4.7-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: rqsession-0.4.7-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 2.1 MB
  • Tags: CPython 3.8+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.0

File hashes

Hashes for rqsession-0.4.7-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 94cfa4dad7f1ee79326f6d69382a913634d427e7043ed5ffc8d8ba7a2d2f4d44
MD5 fbdee13399f3fd4c2cbcc507cc0b1a7a
BLAKE2b-256 3c957d0c4ec47b8d23c533fa04f38687a965a4f2809baf1859a33efcf33c4ea8

See more details on using hashes here.

File details

Details for the file rqsession-0.4.7-cp38-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rqsession-0.4.7-cp38-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6f1879b2e385e92cebf661edaf044d0cca3f27e8a836422aed540cc3ac7abf76
MD5 fe2df3cafebaaa66779f81d241709a15
BLAKE2b-256 c5766c1f2c14ec7537adb6dd086d4ca591fd1e9e7ad4b35eb430d73a7473b0fc

See more details on using hashes here.

File details

Details for the file rqsession-0.4.7-cp38-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for rqsession-0.4.7-cp38-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 12cdf23f7e583d8dbedbb714369e1265cca21a80f7d76f49da394cbd8475760d
MD5 83b45edc0322afadd1bc2a387056b2ab
BLAKE2b-256 d7a890b9cba1e42a146770d1cb48d6e908beded0e52f4f9a4354477745e7ef2c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page