Skip to main content

基于原primp 重新优化调整的请求库 - The fastest python HTTP client that can impersonate web browsers

Project description

🪞 NEVER_PRIMP

Since the original primp project author did not maintain updates for a long time, he refactored and maintained based on the primp project

The Ultimate Python HTTP Client for Web Scraping & Browser Impersonation

Python >= 3.8 PyPI version License Rust

Lightning-fast HTTP client built with Rust, designed for web scraping, anti-bot bypass, and perfect browser impersonation

English | 简体中文

InstallationKey FeaturesQuick StartDocumentationExamples


🎯 What is NEVER_PRIMP?

NEVER_PRIMP (Python Requests IMPersonate) is a cutting-edge HTTP client library that combines:

  • Blazing Speed: Built on Rust's wreq with zero-copy parsing
  • 🎭 Perfect Browser Impersonation: Mimic Chrome, Firefox, Safari, Edge down to TLS/JA3/JA4 fingerprints
  • 🛡️ Anti-Bot Bypass: Advanced features for bypassing WAF, Cloudflare, and bot detection
  • 🔧 Production-Ready: Connection pooling, retries, cookies, streaming, and more

Why Choose NEVER_PRIMP?

Feature NEVER_PRIMP requests httpx curl-cffi
Speed ⚡⚡⚡ ⚡⚡ ⚡⚡
Browser Impersonation ✅ Full ✅ Limited
Header Order Control
Cookie Splitting (HTTP/2)
Connection Pooling
Async Support
Native TLS

📦 Installation

pip install -U never-primp

Platform Support

Precompiled wheels available for:

  • 🐧 Linux: x86_64, aarch64, armv7 (manylinux_2_34+)
  • 🐧 Linux (musl): x86_64, aarch64
  • 🪟 Windows: x86_64
  • 🍏 macOS: x86_64, ARM64 (Apple Silicon)

✨ Key Features

🚀 Performance Optimized

Click to expand
  • Connection Pooling: Reuse connections with configurable idle timeout
  • TCP Optimization: TCP_NODELAY + TCP keepalive for lower latency
  • Zero-Copy Parsing: Rust's efficient memory handling
  • HTTP/2 Multiplexing: Multiple requests over single connection
client = primp.Client(
    pool_idle_timeout=90.0,        # Keep connections alive 90s
    pool_max_idle_per_host=10,     # Max 10 idle connections per host
    tcp_nodelay=True,               # Disable Nagle's algorithm
    tcp_keepalive=60.0,            # TCP keepalive every 60s
)

Benchmark: ~59% faster than requests for sequential requests with connection reuse.

🎭 Advanced Browser Impersonation

Click to expand

Perfect fingerprint mimicry for:

  • Chrome (100-141): Latest versions with full TLS/HTTP2 fingerprints
  • Safari (15.3-26): iOS, iPadOS, macOS variants
  • Firefox (109-143): Desktop versions
  • Edge (101-134): Chromium-based
  • OkHttp (3.9-5.0): Android application library
client = primp.Client(
    impersonate="chrome_141",      # Browser version
    impersonate_os="windows"       # OS: windows, macos, linux, android, ios
)

Impersonates:

  • ✅ TLS fingerprint (JA3/JA4)
  • ✅ HTTP/2 fingerprint (AKAMAI)
  • ✅ Header order and casing
  • ✅ Cipher suites
  • ✅ Extension order

🛡️ Anti-Bot Bypass Features

Click to expand

1. Ordered Headers 🆕

Maintain exact header order to bypass detection systems that check header sequence:

client = primp.Client(
    ordered_headers={
        "user-agent": "Mozilla/5.0...",
        "accept": "text/html,application/xhtml+xml",
        "accept-language": "en-US,en;q=0.9",
        "accept-encoding": "gzip, deflate, br",
        "sec-fetch-dest": "document",
        "sec-fetch-mode": "navigate",
    }
)

Use Case: Websites checking header order (Cloudflare, Akamai, etc.)

📖 Full Documentation

2. Split Cookies (HTTP/2) 🆕

Send cookies as separate headers like real browsers:

client = primp.Client(
    split_cookies=True,  # Send cookies in HTTP/2 style
    http2_only=True
)

# Sends:
# cookie: session_id=abc123
# cookie: user_token=xyz789
# cookie: preference=dark_mode

# Instead of:
# Cookie: session_id=abc123; user_token=xyz789; preference=dark_mode

Use Case: Precise HTTP/2 browser simulation for anti-bot bypass

📖 Full Documentation

3. Dynamic Configuration

Change client behavior without recreation:

client = primp.Client(impersonate="chrome_140")

# Switch impersonation dynamically
client.impersonate = "safari_18"
client.impersonate_os = "macos"

# Update headers
client.ordered_headers = {...}
client.headers_update({"Referer": "https://example.com"})

# Change proxy
client.proxy = "socks5://127.0.0.1:1080"

🍪 Smart Cookie Management

Click to expand

Automatic Cookie Persistence

client = primp.Client(cookie_store=True)  # Default

# Cookies automatically stored and sent
resp1 = client.get("https://example.com/login")
resp2 = client.get("https://example.com/dashboard")  # Cookies included

Manual Cookie Control

# Set cookies
client.set_cookies(
    url="https://example.com",
    cookies={"session": "abc123", "user_id": "456"}
)

# Get cookies
cookies = client.get_cookies(url="https://example.com")

# Per-request cookies
resp = client.get(url, cookies={"temp": "value"})

🔒 Certificate Management

Click to expand
  • System Certificate Store: Auto-updated with OS (no more expiration issues!)
  • Custom CA Bundle: Support for corporate proxies
# Use system certificates (default)
client = primp.Client(verify=True)

# Custom CA bundle
client = primp.Client(ca_cert_file="/path/to/cacert.pem")

# Environment variable
export PRIMP_CA_BUNDLE="/path/to/cert.pem"

🔄 Retry Mechanism

Click to expand

Automatic retries with exponential backoff:

client = primp.Client(
    retry_count=3,        # Retry up to 3 times
    retry_backoff=1.0,    # 1 second backoff between retries
)

Handles transient failures gracefully.

🌊 Streaming Responses

Click to expand

Stream large responses efficiently:

resp = client.get("https://example.com/large-file.zip")

for chunk in resp.stream():
    process_chunk(chunk)

⚡ Async Support

Click to expand

Full async/await support with AsyncClient:

import asyncio
import never_primp as primp

async def fetch(url):
    async with primp.AsyncClient(impersonate="chrome_141") as client:
        return await client.get(url)

async def main():
    urls = ["https://site1.com", "https://site2.com", "https://site3.com"]
    tasks = [fetch(url) for url in urls]
    results = await asyncio.gather(*tasks)

asyncio.run(main())

🚀 Quick Start

Basic Usage

import never_primp as primp

# Simple GET request
client = primp.Client()
response = client.get("https://httpbin.org/get")
print(response.text)

# With browser impersonation
client = primp.Client(impersonate="chrome_141", impersonate_os="windows")
response = client.get("https://tls.peet.ws/api/all")
print(response.json())

Perfect Browser Simulation

# Complete browser simulation for anti-bot bypass
client = primp.Client(
    # Browser impersonation
    impersonate="chrome_141",
    impersonate_os="windows",

    # Advanced anti-detection
    ordered_headers={
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "sec-ch-ua": '"Chromium";v="141", "Not?A_Brand";v="8"',
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": '"Windows"',
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "sec-fetch-site": "none",
        "sec-fetch-mode": "navigate",
        "sec-fetch-user": "?1",
        "sec-fetch-dest": "document",
        "accept-encoding": "gzip, deflate, br",
        "accept-language": "en-US,en;q=0.9",
    },
    split_cookies=True,  # HTTP/2 style cookies

    # Performance optimization
    pool_idle_timeout=90.0,
    pool_max_idle_per_host=10,
    tcp_nodelay=True,

    # Reliability
    retry_count=3,
    retry_backoff=1.0,
    timeout=30,
)

# Use like any HTTP client
response = client.get("https://difficult-site.com")

📚 Documentation

Core Documentation

Quick References

Client Parameters
Client(
    # Authentication
    auth: tuple[str, str | None] | None = None,
    auth_bearer: str | None = None,

    # Headers & Cookies
    headers: dict[str, str] | None = None,
    ordered_headers: dict[str, str] | None = None,  # 🆕 Ordered headers
    cookie_store: bool = True,
    split_cookies: bool = False,  # 🆕 HTTP/2 cookie splitting

    # Browser Impersonation
    impersonate: str | None = None,  # chrome_141, safari_18, etc.
    impersonate_os: str | None = None,  # windows, macos, linux, etc.

    # Network Settings
    proxy: str | None = None,
    timeout: float = 30,
    verify: bool = True,
    ca_cert_file: str | None = None,

    # HTTP Configuration
    http2_only: bool = False,
    https_only: bool = False,
    follow_redirects: bool = True,
    max_redirects: int = 20,
    referer: bool = True,

    # Performance Optimization
    pool_idle_timeout: float | None = None,
    pool_max_idle_per_host: int | None = None,
    tcp_nodelay: bool | None = None,
    tcp_keepalive: float | None = None,

    # Retry Mechanism
    retry_count: int | None = None,
    retry_backoff: float | None = None,

    # Query Parameters
    params: dict[str, str] | None = None,
)
Request Methods
# HTTP Methods
client.get(url, **kwargs)
client.post(url, **kwargs)
client.put(url, **kwargs)
client.patch(url, **kwargs)
client.delete(url, **kwargs)
client.head(url, **kwargs)
client.options(url, **kwargs)

# Common Parameters
params: dict[str, str] | None = None,
headers: dict[str, str] | None = None,
ordered_headers: dict[str, str] | None = None,  # 🆕
cookies: dict[str, str] | None = None,
auth: tuple[str, str | None] | None = None,
auth_bearer: str | None = None,
timeout: float | None = None,

# POST/PUT/PATCH Specific
content: bytes | None = None,
data: dict[str, Any] | None = None,
json: Any | None = None,
files: dict[str, str] | None = None,
Response Object
response.status_code        # HTTP status code
response.headers            # Response headers
response.cookies            # Response cookies
response.url                # Final URL (after redirects)
response.encoding           # Content encoding

# Body Access
response.text               # Text content
response.content            # Binary content
response.json()             # Parse JSON
response.stream()           # Stream response body

# HTML Conversion
response.text_markdown      # HTML → Markdown
response.text_plain         # HTML → Plain text
response.text_rich          # HTML → Rich text
Supported Browsers

Chrome (100-141)

chrome_100, chrome_101, chrome_104, chrome_105, chrome_106, chrome_107, chrome_108, chrome_109, chrome_114, chrome_116, chrome_117, chrome_118, chrome_119, chrome_120, chrome_123, chrome_124, chrome_126, chrome_127, chrome_128, chrome_129, chrome_130, chrome_131, chrome_133, chrome_134, chrome_135, chrome_136, chrome_137, chrome_138, chrome_139, chrome_140, chrome_141

Safari (15.3-26)

safari_15.3, safari_15.5, safari_15.6.1, safari_16, safari_16.5, safari_17.0, safari_17.2.1, safari_17.4.1, safari_17.5, safari_18, safari_18.2, safari_26, safari_ios_16.5, safari_ios_17.2, safari_ios_17.4.1, safari_ios_18.1.1, safari_ios_26, safari_ipad_18, safari_ipad_26

Firefox (109-143)

firefox_109, firefox_117, firefox_128, firefox_133, firefox_135, firefox_136, firefox_139, firefox_142, firefox_143

Edge (101-134)

edge_101, edge_122, edge_127, edge_131, edge_134

OkHttp (3.9-5.0)

okhttp_3.9, okhttp_3.11, okhttp_3.13, okhttp_3.14, okhttp_4.9, okhttp_4.10, okhttp_5

OS Support

windows, macos, linux, android, ios


💡 Examples

Example 1: Web Scraping with Anti-Bot Bypass

import never_primp as primp

# Perfect browser simulation
client = primp.Client(
    impersonate="chrome_141",
    impersonate_os="windows",
    ordered_headers={
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "accept-language": "en-US,en;q=0.9",
        "accept-encoding": "gzip, deflate, br",
    },
    split_cookies=True,
    retry_count=3,
)

response = client.get("https://difficult-site.com")
print(response.status_code)

Example 2: API Integration with Authentication

client = primp.Client(
    headers={
        "Content-Type": "application/json",
        "X-API-Version": "v1",
    },
    auth_bearer="your-api-token",
    timeout=30,
)

# GET request
data = client.get("https://api.example.com/users").json()

# POST request
response = client.post(
    "https://api.example.com/users",
    json={"name": "John", "email": "john@example.com"}
)

Example 3: File Upload

client = primp.Client()

files = {
    'document': '/path/to/document.pdf',
    'image': '/path/to/image.png'
}

response = client.post(
    "https://example.com/upload",
    files=files,
    data={"description": "My files"}
)

Example 4: Session Management

# Automatic cookie persistence
client = primp.Client(cookie_store=True)

# Login
client.post(
    "https://example.com/login",
    data={"username": "user", "password": "pass"}
)

# Subsequent requests include session cookies
profile = client.get("https://example.com/profile")

Example 5: Proxy Usage

# SOCKS5 proxy
client = primp.Client(proxy="socks5://127.0.0.1:1080")

# HTTP proxy with authentication
client = primp.Client(proxy="http://user:pass@proxy.example.com:8080")

# Environment variable
import os
os.environ['PRIMP_PROXY'] = 'http://127.0.0.1:8080'

Example 6: Async Concurrent Requests

import asyncio
import never_primp as primp

async def fetch_all(urls):
    async with primp.AsyncClient(impersonate="chrome_141") as client:
        tasks = [client.get(url) for url in urls]
        responses = await asyncio.gather(*tasks)
        return [r.text for r in responses]

urls = ["https://site1.com", "https://site2.com", "https://site3.com"]
results = asyncio.run(fetch_all(urls))

Example 7: Streaming Large Files

client = primp.Client()

response = client.get("https://example.com/large-file.zip")

with open("output.zip", "wb") as f:
    for chunk in response.stream():
        f.write(chunk)

🎯 Use Cases

✅ Perfect For

  • Web Scraping: Bypass anti-bot systems (Cloudflare, Akamai, PerimeterX)
  • API Testing: High-performance API client with retries
  • Data Collection: Concurrent requests with connection pooling
  • Security Research: TLS fingerprint analysis and testing
  • Browser Automation Alternative: Lighter than Selenium/Playwright

⚠️ Not Suitable For

  • JavaScript Rendering: Use Playwright/Selenium for dynamic content
  • Browser Automation: No DOM manipulation or JavaScript execution
  • Visual Testing: No screenshot or rendering capabilities

🔬 Benchmarks

Sequential Requests (Connection Reuse)

Library Time (10 requests) Relative Speed
never_primp 1.24s 1.00x (baseline)
httpx 1.89s 0.66x slower
requests 3.05s 0.41x slower

Concurrent Requests (AsyncClient)

Library Time (100 requests) Relative Speed
never_primp 2.15s 1.00x (baseline)
httpx 2.83s 0.76x slower
aiohttp 2.45s 0.88x slower

Benchmarks run on: Python 3.11, Ubuntu 22.04, AMD Ryzen 9 5900X


🛠️ Development

Building from Source

# Clone repository
git clone https://github.com/yourusername/never-primp.git
cd never-primp

# Create virtual environment
python -m venv venv
source venv/bin/activate  # Linux/macOS
# or
venv\Scripts\activate  # Windows

# Install maturin (Rust-Python build tool)
pip install maturin

# Build and install in development mode
maturin develop --release

# Run examples
python examples/example_ordered_headers.py

Project Structure

never-primp/
├── src/
│   ├── lib.rs              # Main Rust implementation
│   ├── traits.rs           # Header conversion traits
│   ├── response.rs         # Response handling
│   ├── impersonate.rs      # Browser impersonation
│   └── utils.rs            # Certificate utilities
├── never_primp/
│   ├── __init__.py         # Python API wrapper
│   └── never_primp.pyi     # Type hints
├── examples/
│   ├── example_ordered_headers.py
│   └── example_split_cookies.py
├── Cargo.toml              # Rust dependencies
└── pyproject.toml          # Python package config

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Guidelines

  1. Follow Rust best practices for src/ files
  2. Maintain Python 3.8+ compatibility
  3. Add tests for new features
  4. Update documentation

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


⚠️ Disclaimer

This tool is intended for educational purposes and legitimate use cases only, such as:

  • Testing your own applications
  • Academic research
  • Security auditing (with permission)
  • Data collection from public APIs

Important:

  • Respect websites' robots.txt and Terms of Service
  • Do not use for malicious purposes or unauthorized access
  • Be mindful of rate limiting and server resources
  • The authors are not responsible for misuse of this tool

Use responsibly and ethically. 🙏


🙏 Acknowledgments

Built with:

  • wreq - Rust HTTP client with browser impersonation
  • PyO3 - Rust bindings for Python
  • tokio - Async runtime for Rust

Inspired by:


📞 Support


Made with ❤️ and ⚙️ Rust

If you find this project helpful, please consider giving it a ⭐!

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

never_primp-1.0.2.tar.gz (69.5 kB view details)

Uploaded Source

Built Distributions

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

never_primp-1.0.2-cp38-abi3-win_amd64.whl (3.2 MB view details)

Uploaded CPython 3.8+Windows x86-64

never_primp-1.0.2-cp38-abi3-manylinux_2_28_x86_64.whl (3.5 MB view details)

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

never_primp-1.0.2-cp38-abi3-macosx_11_0_arm64.whl (3.1 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

never_primp-1.0.2-cp38-abi3-macosx_10_12_x86_64.whl (3.3 MB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

Details for the file never_primp-1.0.2.tar.gz.

File metadata

  • Download URL: never_primp-1.0.2.tar.gz
  • Upload date:
  • Size: 69.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.9.6

File hashes

Hashes for never_primp-1.0.2.tar.gz
Algorithm Hash digest
SHA256 3d83d5a8547db0122ca4010c356318f1baf118260dd604af9bc3bf3ca0ce0bbe
MD5 2675b35686d76ab5f46919c51cb919d4
BLAKE2b-256 4406a5ae7d2202f780cc464d64cb2090ddbd3cd33fb822dbecd2469567446dee

See more details on using hashes here.

File details

Details for the file never_primp-1.0.2-cp38-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for never_primp-1.0.2-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 88cc9cbb100e5e699a6d88e4bafb54b33e6b9cda5821ea088a34236ef62e07f2
MD5 a2d3ed0f59196bdeb75e3b7c823fb222
BLAKE2b-256 63cfa7d55a884363c016ee16a5cbed7d8d81bf1a16dc1b3995c33d77aab6acf5

See more details on using hashes here.

File details

Details for the file never_primp-1.0.2-cp38-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for never_primp-1.0.2-cp38-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 731cb744168638333e5147576d7d97a93a52ad91f8af30c1a5a066890869693c
MD5 059a67c90b65ca7b742e6da19906dc6d
BLAKE2b-256 521cf4ea363b7a8e2bb793d35f96c06180757b8c88ace977cbfa6d399fbe843f

See more details on using hashes here.

File details

Details for the file never_primp-1.0.2-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for never_primp-1.0.2-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 219f128c3e6da12605985b83bc7a0167bb376ca2d14cdd6b2a7893429d174d23
MD5 417209848cbe331511f3fe487bd50aa5
BLAKE2b-256 fa9e4eec9f0b4a5b60d77111a0041b2c1410cde60b76c6581432de0992a1845b

See more details on using hashes here.

File details

Details for the file never_primp-1.0.2-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for never_primp-1.0.2-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 5308bb45ac1b32a3e151e2b5321d1ee4150cb4a70470bb6733c93034a6b3e68d
MD5 f847b9d3048dfc3af852ac65461931f3
BLAKE2b-256 0156df7f90b3dc1fbae6773ca7513c8a694945cb63ec0453c47a3460f407163c

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