primp

repository·main·Indexed 20 days ago

https://github.com/deedy5/primp

An HTTP client with browser impersonation capabilities designed to bypass fingerprinting-based restrictions by mimicking specific browser and OS profiles. It provides both Rust and Python APIs, supporting synchronous and asynchronous operations. The ecosystem includes primp-h2, a fork of the h2 HTTP/2 client and server library, and supports profiles for Chrome, Safari, Edge, Firefox, and Opera.

Tokens
42.5K
Snippets
130
Records
183
Agent score
69%

What's inside primp

  1. What is impersonated by primp

    main

    When using impersonation, primp modifies the following layers of the network request:

    • TLS fingerprint: cipher suites, signature algorithms, named groups, extension order.
    • HTTP/2 fingerprint: SETTINGS order, pseudo-header order, header priority, header order, initial window sizes.
    • Headers: User-Agent, sec-ch-ua, Accept, Accept-Language, Accept-Encoding, sec-fetch-*, etc.
    • Compression: Support for gzip, brotli, and zstd per browser profile.
  2. Use a fallback chain for DNS resolution

    main

    If you provide a list to dns_resolver, primp will attempt to use the resolvers in the order they are listed. The first resolver that succeeds will be used. This is useful for attempting secure protocols like DoH or DoT first, then falling back to the system resolver or plain DNS if they fail.

    # Try DoH first, fall back to system
    client = primp.Client(dns_resolver=["doh://cloudflare-dns.com/dns-query", "system"])
    
    # Try DoH first, fall back to plain DNS
    client = primp.Client(dns_resolver=["doh://cloudflare-dns.com/dns-query", "1.1.1.1"])
  3. Understand the primp Python exception hierarchy

    main

    All exceptions in primp derive from PrimpError. Understanding the hierarchy allows you to catch specific errors (like ConnectError) or broad categories (like RequestError) depending on your error handling strategy.

    Hierarchy:

    • PrimpError (base exception)
      • BuilderError: Errors during client or request construction (e.g., invalid URLs).
      • RequestError: Generic request/network errors.
        • ConnectError: Connection-level issues (DNS, proxy, SSL, network).
        • TimeoutError: Request or connection timeouts.
      • StatusError: HTTP 4xx or 5xx responses (includes status_code).
      • RedirectError: Exceeding the maximum number of redirects.
      • BodyError: Errors during body or stream I/O.
      • DecodeError: Errors decoding content (e.g., gzip, deflate, zstd).
      • UpgradeError: Protocol upgrade failures.
    PrimpError (base exception)
    ├── BuilderError          # Client/request builder errors
    ├── RequestError          # Generic request errors
    │   ├── ConnectError     # Connection errors (DNS, proxy, SSL)
    │   └── TimeoutError     # Request timeout
    ├── StatusError           # HTTP 4xx/5xx (has status_code attribute)
    ├── RedirectError         # Too many redirects
    ├── BodyError             # Body/stream errors
    ├── DecodeError           # Content decoding errors
    └── UpgradeError          # Protocol upgrade errors
  4. Impersonate browsers and operating systems

    main

    To avoid detection, you can configure the client to mimic specific browser and OS fingerprints using the impersonate and impersonate_os arguments in the Client constructor.

    Supported Browser Profiles (impersonate):

    • Chrome: chrome_144, chrome_145, chrome_146, chrome
    • Safari: safari_18.5, safari_26, safari_26.3, safari
    • Edge: edge_144, edge_145, edge_146, edge
    • Firefox: firefox_140, firefox_146, firefox_147, firefox_148, firefox
    • Opera: opera_126, opera_127, opera_128, opera_129, opera
    • Random: random

    Supported OS Profiles (impersonate_os):

    • android, ios, linux, macos, windows, random
  5. Quick Start with primp Client

    main

    You can create an HTTP client that impersonates a specific web browser using Client::builder() and the .impersonate() method. This allows your requests to mimic the TLS and HTTP/2 fingerprints of real browsers.

    use primp::{Client, Impersonate};
    
    #[tokio::main]
    async fn main() -> Result<(), primp::Error> {
        let client = Client::builder()
            .impersonate(Impersonate::ChromeV146)
            .build()?;
        let resp = client.get("https://tls.peet.ws/api/all").send().await?;
        println!("Body: {}", resp.text().await?);
        Ok(())
    }
  6. Ensure resource cleanup when streaming

    main

    When using streaming responses, always use a context manager to prevent resource leaks. If you do not use a context manager, you must manually call .close() (sync) or .aclose() (async) on the response object.

    Recommended Pattern:

    with primp.get(url, stream=True) as resp:
        for chunk in resp.iter_bytes(65536):
            process(chunk)

    Manual Pattern (Avoid if possible):

    resp = primp.get(url, stream=True)
    try:
        for chunk in resp.iter_bytes():
            process(chunk)
    finally:
        resp.close()
    # Good
    with primp.get(url, stream=True) as resp:
        for chunk in resp.iter_bytes(65536):  # 64KB chunks
            process(chunk)
    
    # Avoid — remember to call resp.close()
    resp = primp.get(url, stream=True)
    for chunk in resp.iter_bytes():
        process(chunk)
    resp.close()
  7. Build primp from source

    main

    If you need to build primp from the source repository, follow these steps using maturin:

    1. Clone the repository and navigate to the Python crate directory.
    2. Create and activate a virtual environment.
    3. Install maturin and run maturin develop -r to build and install the package in development mode.
    git clone https://github.com/deedy5/primp.git && cd primp/crates/primp-python
    python -m venv .venv && source .venv/bin/activate
    pip install maturin && maturin develop -r
  8. Use AsyncClient for asynchronous HTTP requests

    main

    The AsyncClient is an asynchronous HTTP client designed to impersonate web browsers. It is best used within an async with context manager to ensure proper resource management. All request methods (GET, POST, etc.) return awaitable futures that must be awaited.

    import asyncio
    import primp
    
    async def main():
        async with primp.AsyncClient(impersonate="chrome_146") as client:
            resp = await client.get("https://httpbin.org/get")
            print(resp.text)
    
    asyncio.run(main())