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.1.tar.gz (66.3 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.1-cp38-abi3-win_amd64.whl (3.2 MB view details)

Uploaded CPython 3.8+Windows x86-64

never_primp-1.0.1-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.1-cp38-abi3-macosx_11_0_arm64.whl (3.1 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

never_primp-1.0.1-cp38-abi3-macosx_10_12_x86_64.whl (3.2 MB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

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

File metadata

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

File hashes

Hashes for never_primp-1.0.1.tar.gz
Algorithm Hash digest
SHA256 7147675e3bdd4890923d880b723c5971ade378d3c9613ab673c5c3ea3ef27307
MD5 10680cbef30d0af1e5d8e69630e77e3c
BLAKE2b-256 243f117a3bf50e1620b098aeb9c761c73499782d766d7d9d1b3152aa845348cb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for never_primp-1.0.1-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 c4404735204743c8a612e3fdf572cbc945588789bd5f814cd41f8dc6db14a1f8
MD5 e5db9c7bb09c1132c3a425956c6a39c3
BLAKE2b-256 5c2230d1c08fb6d94f7aa7a88de39cc97f19b8940ed6525fe819fdcd4d5aa7aa

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for never_primp-1.0.1-cp38-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 7d27d32fb2113bf72cf2fd981b3fa7ef799475c793f9219f37a949765ae073bf
MD5 7ee81c79f2721a9c0ee021411ab5fada
BLAKE2b-256 e2cdea405aa63bdaf016597384585d6859757c63ad27fa1baab5462f94fdb4f5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for never_primp-1.0.1-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f1c60b3f44d48bc0368778c78f7649cde984df14d22f33f34a867dc84a3359c6
MD5 e22a1982965ae558d35ddb607f563d1f
BLAKE2b-256 dc5dd184a28a0c71cdc3a7c61ea950218c65bcd7b0feb3d94e9d70c9fba14ec9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for never_primp-1.0.1-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 b54cdd406de1eac20d4c5cbc42de47d7a888e8829477352cb10a8545f8428428
MD5 f59d5281f626be12f0dfaafa9a39e35c
BLAKE2b-256 4a76117e64f580b347131062567f71fb5259df8892986e4d7008bc3c435d0d7d

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