never-primp


Namenever-primp JSON
Version 1.2.1 PyPI version JSON
download
home_pageNone
Summary基于原primp 重新优化调整的请求库 - The fastest python HTTP client that can impersonate web browsers
upload_time2025-11-02 11:22:30
maintainerNone
docs_urlNone
authorNeverland
requires_python>=3.8
licenseNone
keywords requests httpx http http-client tls-fingerprint ja3 ja4 impersonate browser-impersonation web-scraping crawler reverse-engineering
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">

# 🪞 NEVER_PRIMP

**由于原primp项目作者长时间不维护更新,所以自己基于primp项目进行重构维护**

**终极 Python HTTP 客户端 - 专为网络爬虫与浏览器伪装设计**

![Python >= 3.8](https://img.shields.io/badge/python->=3.8-blue.svg)
[![PyPI version](https://badge.fury.io/py/never-primp.svg)](https://pypi.org/project/never-primp)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Rust](https://img.shields.io/badge/rust-1.70+-orange.svg)](https://www.rust-lang.org)

*基于 Rust 构建的闪电般快速的 HTTP 客户端,专为网络爬虫、反爬虫绕过和完美浏览器伪装而设计*

[简体中文](README_CN.md) | [English](README.md)

[安装](#-安装) •
[核心特性](#-核心特性) •
[快速开始](#-快速开始) •
[文档](#-文档) •
[示例](#-示例)

</div>

---

## 🎯 什么是 NEVER_PRIMP?

**NEVER_PRIMP** (**P**ython **R**equests **IMP**ersonate) 是一个前沿的 HTTP 客户端库,它结合了:

- ⚡ **极致速度**:基于 Rust 的 `wreq` 构建,零拷贝解析
- 🎭 **完美浏览器伪装**:模拟 Chrome、Firefox、Safari、Edge 的 TLS/JA3/JA4 指纹
- 🛡️ **反爬虫绕过**:先进的功能绕过 WAF、Cloudflare 和机器人检测
- 🔧 **生产就绪**:连接池、重试、Cookie、流式传输等完整功能

### 为什么选择 NEVER_PRIMP?

| 功能 | NEVER_PRIMP | requests | httpx | curl-cffi |
|------|-------------|----------|-------|-----------|
| **速度** | ⚡⚡⚡ | ⚡ | ⚡⚡ | ⚡⚡ |
| **浏览器伪装** | ✅ 完整 | ❌ | ❌ | ✅ 有限 |
| **请求头顺序控制** | ✅ | ❌ | ❌ | ❌ |
| **Cookie 分割 (HTTP/2)** | ✅ | ❌ | ❌ | ❌ |
| **连接池** | ✅ | ✅ | ✅ | ❌ |
| **异步支持** | ✅ | ❌ | ✅ | ❌ |
| **原生 TLS** | ✅ | ❌ | ❌ | ✅ |


## 🚀 HTTP 性能对比测试 (测试URL: https://www.baidu.com)
测试代码: [benchmark.py](benchmark.py)

|  | requests_go | curl_cffi | tls_client | requests | never_primp  |primp   |aiohttp   | httpx  |
|------|-------------|----------|-------|-----------|---|---|---|---|
| **单次** | 347.49ms | 122.45ms | 162.29ms | 646.89ms | 85.91ms  |102.18ms   | 74.90ms  | 90.43ms  |
| **for循环10次** | 315.79ms | 46.66ms | 21.81ms | 655.92ms | 19.45ms  | 20.96ms  | 21.42ms  | 20.10ms  |
| **TLS** | 31.70ms | 75.78ms | 140.48ms | ≈0 (复用或缓存) | 66.46ms  | 81.23ms  |53.47ms   | 70.33ms  |
| **响应大小** | 2443B| 628128B | 227B | 2443B | 28918B  | 28918B  | 29506B  | 29506B  |
| **并发 100任务 4worker** | 589.13ms | 56.46ms | 58.33ms | 696.74ms | 20.16ms  | 20.66ms  |20.95ms   |23.18ms   |

![benchmark_results.png](benchmark_results.png)
---

## 📦 安装

```bash
pip install -U never-primp
```

### 平台支持

提供预编译的二进制包:
- 🐧 **Linux**: x86_64, aarch64, armv7 (manylinux_2_34+)
- 🐧 **Linux (musl)**: x86_64, aarch64
- 🪟 **Windows**: x86_64
- 🍏 **macOS**: x86_64, ARM64 (Apple Silicon)

---

## ✨ 核心特性

### 🚀 性能优化 ⚡ 新增

<details>
<summary><b>点击展开</b></summary>

#### 核心性能优化 (v1.2.0+)

**NEVER_PRIMP** 已实施多层性能优化,提供业界领先的性能:

##### 1. **延迟客户端重建** 🆕
智能脏标志机制,仅在必要时重建客户端:
- 配置修改时不立即重建(零开销)
- 首次请求时才重建(延迟构建)
- **性能提升**:配置操作快 **99.9%**,总体提升 **30-40%**

```python
client = primp.Client()
# 快速配置修改(无重建开销)
for i in range(100):
    client.headers[f'X-Header-{i}'] = f'value-{i}'  # ~5ms 总耗时
# 优化前:~200ms(每次修改都重建)
```

##### 2. **智能内存管理** 🆕
减少不必要的内存分配和复制:
- 零拷贝 body 传输
- 预分配容量避免重新分配
- 智能 headers 合并策略
- **性能提升**:减少 **50%** 内存分配,提升 **10-15%**

##### 3. **RwLock 并发优化** 🆕
读写锁替代互斥锁,提升并发性能:
- 读操作并发执行(不互相阻塞)
- 写操作独占访问(保证安全)
- **性能提升**:单线程 **5-10%**,多线程 **20-30%**

```python
from concurrent.futures import ThreadPoolExecutor

client = primp.Client()
with ThreadPoolExecutor(max_workers=4) as executor:
    # 并发读取配置无阻塞
    futures = [executor.submit(client.get, url) for url in urls]
```

##### 4. **连接池与 TCP 优化**
高效的连接重用和网络优化:
- **连接池**:可配置空闲超时的连接重用
- **TCP 优化**:TCP_NODELAY + TCP keepalive 降低延迟
- **零拷贝解析**:Rust 的高效内存处理
- **HTTP/2 多路复用**:单个连接处理多个请求

```python
client = primp.Client(
    pool_idle_timeout=90.0,        # 保持连接 90 秒
    pool_max_idle_per_host=10,     # 每个主机最多 10 个空闲连接
    tcp_nodelay=True,               # 禁用 Nagle 算法
    tcp_keepalive=60.0,            # TCP keepalive 每 60 秒
)
```

#### 综合性能提升

| 场景 | 优化效果 |
|------|---------|
| 频繁配置修改 | **+97.5%** |
| 单线程请求 | **+45-65%** |
| 多线程并发 (4线程) | **+60-85%** |
| 连接复用 | **+59%** vs requests |

</details>

### 🎭 高级浏览器伪装

<details>
<summary><b>点击展开</b></summary>

完美的指纹模拟:

- **Chrome** (100-141):最新版本的完整 TLS/HTTP2 指纹
- **Safari** (15.3-26):iOS、iPadOS、macOS 变体
- **Firefox** (109-143):桌面版本
- **Edge** (101-134):基于 Chromium
- **OkHttp** (3.9-5.0):Android 应用库

```python
client = primp.Client(
    impersonate="chrome_141",      # 浏览器版本
    impersonate_os="windows"       # 操作系统: windows, macos, linux, android, ios
)
```

模拟内容:
- ✅ TLS 指纹 (JA3/JA4)
- ✅ HTTP/2 指纹 (AKAMAI)
- ✅ 请求头顺序和大小写
- ✅ 加密套件
- ✅ 扩展顺序

</details>

### 🛡️ 反爬虫绕过功能

<details>
<summary><b>点击展开</b></summary>

#### 1. **有序请求头** 🆕
维持精确的请求头顺序以绕过检测请求头序列的检测系统:

```python
client = primp.Client(
    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",
    }
)
```

**使用场景**:检查请求头顺序的网站(Cloudflare、Akamai 等)

#### 2. **Cookie 分割 (HTTP/2)** 🆕
像真实浏览器一样将 Cookie 作为独立的请求头发送:

```python
client = primp.Client(
    split_cookies=True,  # 使用 HTTP/2 风格发送 Cookie
    http2_only=True
)

# 发送格式:
# cookie: session_id=abc123
# cookie: user_token=xyz789
# cookie: preference=dark_mode

# 而不是:
# Cookie: session_id=abc123; user_token=xyz789; preference=dark_mode
```

**使用场景**:精确的 HTTP/2 浏览器模拟以绕过反爬虫

📖 [完整文档](SPLIT_COOKIES.md)

#### 3. **动态配置**
无需重新创建即可更改客户端行为:

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

# 动态切换伪装
client.impersonate = "safari_18"
client.impersonate_os = "macos"

# 更新请求头
client.headers = {...}
client.headers_update({"Referer": "https://example.com"})

# 更改代理
client.proxy = "socks5://127.0.0.1:1080"
```

</details>

### 🍪 智能 Cookie 管理

<details>
<summary><b>点击展开</b></summary>

#### 自动 Cookie 持久化
```python
client = primp.Client(cookie_store=True)  # 默认开启

# Cookie 自动存储和发送
resp1 = client.get("https://example.com/login")
resp2 = client.get("https://example.com/dashboard")  # 自动包含 Cookie
```

#### 类字典 Cookie 接口 (requests 风格)
```python
# 访问 cookie jar
cookies = client.cookies

# 设置 Cookie (类字典方式)
cookies["session_id"] = "abc123"
cookies.update({"user_token": "xyz789"})

# 获取 Cookie
session_id = cookies.get("session_id")
all_cookies = dict(cookies)  # 获取所有 Cookie 为字典

# 删除 Cookie
del cookies["session_id"]
cookies.clear()  # 清空所有
```

#### 手动 Cookie 控制
```python
# 为特定 URL 设置 Cookie
client.set_cookies(
    url="https://example.com",
    cookies={"session": "abc123", "user_id": "456"}
)

# 获取特定 URL 的所有 Cookie
cookies = client.get_cookies(url="https://example.com")

# 单次请求 Cookie (临时,不存储)
resp = client.get(url, cookies={"temp": "value"})
```

</details>

### 🔒 证书管理

<details>
<summary><b>点击展开</b></summary>

- **系统证书库**:随操作系统自动更新(不再有证书过期问题!)
- **自定义 CA 包**:支持企业代理

```python
# 使用系统证书(默认)
client = primp.Client(verify=True)

# 自定义 CA 包
client = primp.Client(ca_cert_file="/path/to/cacert.pem")

# 环境变量
export PRIMP_CA_BUNDLE="/path/to/cert.pem"
```

</details>

### 🔄 HTTP 版本控制

<details>
<parameter name="summary"><b>点击展开</b></summary>

控制使用哪个 HTTP 协议版本:

```python
# 强制使用 HTTP/1.1
client = primp.Client(http1_only=True)

# 强制使用 HTTP/2
client = primp.Client(http2_only=True)

# 自动协商(默认)
client = primp.Client()  # 选择最佳可用版本

# 优先级: http1_only > http2_only > 自动
```

**使用场景**:
- `http1_only=True`: 旧版服务器、调试、特定兼容性需求
- `http2_only=True`: 现代 API、性能优化
- 默认: 最佳兼容性

</details>

### 🌊 流式响应

<details>
<summary><b>点击展开</b></summary>

高效地流式传输大型响应:

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

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

</details>

### ⚡ 异步支持

<details>
<summary><b>点击展开</b></summary>

完整的 async/await 支持,使用 `AsyncClient`:

```python
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())
```

</details>

---

## 🚀 快速开始

### 基础用法

```python
import never_primp as primp

# 简单的 GET 请求
client = primp.Client()
response = client.get("https://httpbin.org/get")
print(response.text)

# 带浏览器伪装
client = primp.Client(impersonate="chrome_141", impersonate_os="windows")
response = client.get("https://tls.peet.ws/api/all")
print(response.json())
```

### 完美的浏览器模拟

```python
# 完整的浏览器模拟用于反爬虫绕过
client = primp.Client(
    # 浏览器伪装
    impersonate="chrome_141",
    impersonate_os="windows",

    # 高级反检测
    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 风格的 Cookie

    # 性能优化
    pool_idle_timeout=90.0,
    pool_max_idle_per_host=10,
    tcp_nodelay=True,

    # HTTP 版本控制
    http2_only=True,  # 强制 HTTP/2 以获得更好性能
    timeout=30,
)

# 像任何 HTTP 客户端一样使用
response = client.get("https://difficult-site.com")
```

---

## 📚 文档

### 核心文档

- [**Cookie 分割指南**](SPLIT_COOKIES.md) - 像真实浏览器一样处理 HTTP/2 Cookie

### 快速参考

<details>
<summary><b>Client 参数</b></summary>

```python
Client(
    # 认证
    auth: tuple[str, str | None] | None = None,
    auth_bearer: str | None = None,

    # 请求头和 Cookie
    headers: dict[str, str] | None = None,  # 🆕 有序请求头
    cookie_store: bool = True,
    split_cookies: bool = False,  # 🆕 HTTP/2 Cookie 分割

    # 浏览器伪装
    impersonate: str | None = None,  # chrome_141, safari_18 等
    impersonate_os: str | None = None,  # windows, macos, linux 等

    # 网络设置
    proxy: str | None = None,
    timeout: float = 30,
    verify: bool = True,
    ca_cert_file: str | None = None,

    # HTTP 配置
    http1_only: bool = False,  # 🆕 强制 HTTP/1.1
    http2_only: bool = False,  # 强制 HTTP/2
    https_only: bool = False,
    follow_redirects: bool = True,
    max_redirects: int = 20,
    referer: bool = True,

    # 性能优化
    pool_idle_timeout: float | None = None,
    pool_max_idle_per_host: int | None = None,
    tcp_nodelay: bool | None = None,
    tcp_keepalive: float | None = None,

    # 查询参数
    params: dict[str, str] | None = None,
)
```

</details>

<details>
<summary><b>请求方法</b></summary>

```python
# HTTP 方法
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)

# 通用参数
params: dict[str, str] | None = None,
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 特定参数
content: bytes | None = None,
data: dict[str, Any] | None = None,
json: Any | None = None,
files: dict[str, str] | None = None,
```

</details>

<details>
<summary><b>响应对象</b></summary>

```python
response.status_code        # HTTP 状态码
response.headers            # 响应头
response.cookies            # 响应 Cookie
response.url                # 最终 URL(重定向后)
response.encoding           # 内容编码

# 正文访问
response.text               # 文本内容
response.content            # 二进制内容
response.json()             # 解析 JSON
response.stream()           # 流式传输响应正文

# HTML 转换
response.text_markdown      # HTML → Markdown
response.text_plain         # HTML → 纯文本
response.text_rich          # HTML → 富文本
```

</details>

<details>
<summary><b>支持的浏览器</b></summary>

#### 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`

#### 操作系统支持
`windows`, `macos`, `linux`, `android`, `ios`

</details>

---

## 💡 示例

### 示例 1:网络爬虫与反爬虫绕过

```python
import never_primp as primp

# 完美的浏览器模拟
client = primp.Client(
    impersonate="chrome_141",
    impersonate_os="windows",
    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,
)

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

### 示例 2:带认证的 API 集成

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

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

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

### 示例 3:文件上传

```python
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"}
)
```

### 示例 4:会话管理

```python
# 自动 Cookie 持久化
client = primp.Client(cookie_store=True)

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

# 后续请求自动包含会话 Cookie
profile = client.get("https://example.com/profile")
```

### 示例 5:代理使用

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

# 带认证的 HTTP 代理
client = primp.Client(proxy="http://user:pass@proxy.example.com:8080")

# 环境变量
import os
os.environ['PRIMP_PROXY'] = 'http://127.0.0.1:8080'
```

### 示例 6:异步并发请求

```python
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))
```

### 示例 7:流式传输大文件

```python
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)
```

---

## 🎯 使用场景

### ✅ 完美适用于

- **网络爬虫**:绕过反爬虫系统(Cloudflare、Akamai、PerimeterX)
- **API 测试**:带重试的高性能 API 客户端
- **数据采集**:带连接池的并发请求
- **安全研究**:TLS 指纹分析和测试
- **浏览器自动化替代**:比 Selenium/Playwright 更轻量

### ⚠️ 不适用于

- **JavaScript 渲染**:使用 Playwright/Selenium 处理动态内容
- **浏览器自动化**:无 DOM 操作或 JavaScript 执行
- **视觉测试**:无截图或渲染功能

---

## 🔬 基准测试

### 性能优化效果 (v1.2.0+)

| 场景 | 优化前 | 优化后 (v1.2.0) | 提升 |
|------|--------|-----------------|------|
| **频繁配置修改** (100次header设置) | 200ms | 5ms | **+3900%** 🚀 |
| **单线程顺序请求** | 基准 | 优化 | **+45-65%** |
| **多线程并发** (4线程) | 基准 | 优化 | **+60-85%** |

### 与其他库对比

#### 顺序请求(连接复用)

| 库 | 时间(10 个请求) | 相对速度 |
|---------|-------------------|----------------|
| **never_primp v1.2** | **0.85s** | **1.00x**(基准)⚡ |
| never_primp v1.1 | 1.24s | 0.69x 更慢 |
| httpx | 1.89s | 0.45x 更慢 |
| requests | 3.05s | 0.28x 更慢 |

#### 并发请求(AsyncClient)

| 库 | 时间(100 个请求) | 相对速度 |
|---------|---------------------|----------------|
| **never_primp v1.2** | **1.30s** | **1.00x**(基准)⚡ |
| never_primp v1.1 | 2.15s | 0.60x 更慢 |
| httpx | 2.83s | 0.46x 更慢 |
| aiohttp | 2.45s | 0.53x 更慢 |

#### 配置修改性能

| 操作 | never_primp v1.2 | never_primp v1.1 | 提升 |
|------|------------------|------------------|------|
| 100次 header 设置 | **5ms** | 200ms | **40x 更快** ⚡ |
| 修改代理设置 | **<0.01ms** | ~2ms | **200x 更快** |
| 切换浏览器伪装 | **<0.01ms** | ~2ms | **200x 更快** |

*基准测试环境:Python 3.11, Ubuntu 22.04, AMD Ryzen 9 5900X*
*所有测试使用相同网络条件和目标服务器*

---

## 🛠️ 开发

### 从源码构建

```bash
# 克隆仓库
git clone https://github.com/yourusername/never-primp.git
cd never-primp

# 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Linux/macOS
# 或
venv\Scripts\activate  # Windows

# 安装 maturin(Rust-Python 构建工具)
pip install maturin

# 以开发模式构建和安装
maturin develop --release

# 运行示例
python examples/example_headers.py
```

### 项目结构

```
never-primp/
├── src/
│   ├── lib.rs              # 主要 Rust 实现
│   ├── traits.rs           # 请求头转换 traits
│   ├── response.rs         # 响应处理
│   ├── impersonate.rs      # 浏览器伪装
│   └── utils.rs            # 证书工具
├── never_primp/
│   ├── __init__.py         # Python API 包装器
│   └── never_primp.pyi     # 类型提示
├── examples/
│   ├── example_headers.py
│   └── example_split_cookies.py
├── Cargo.toml              # Rust 依赖
└── pyproject.toml          # Python 包配置
```

---

## 🤝 贡献

欢迎贡献!请随时提交 Pull Request。

### 开发指南

1. 遵循 Rust 最佳实践(src/ 文件)
2. 保持 Python 3.8+ 兼容性
3. 为新功能添加测试
4. 更新文档

---

## 📄 许可证

本项目基于 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件。

---

## ⚠️ 免责声明

本工具仅用于**教育目的**和**合法用例**,例如:
- 测试您自己的应用程序
- 学术研究
- 安全审计(需获得许可)
- 从公共 API 收集数据

**重要提示**:
- 尊重网站的 `robots.txt` 和服务条款
- 不要用于恶意目的或未经授权的访问
- 注意速率限制和服务器资源
- 作者不对滥用此工具负责

请负责任和道德地使用。🙏

---

## 🙏 致谢

构建基于:
- [wreq](https://github.com/0x676e67/wreq) - 带浏览器伪装的 Rust HTTP 客户端
- [PyO3](https://github.com/PyO3/pyo3) - Python 的 Rust 绑定
- [tokio](https://tokio.rs/) - Rust 异步运行时

灵感来源:
- [curl-impersonate](https://github.com/lwthiker/curl-impersonate)
- [httpx](https://github.com/encode/httpx)
- [requests](https://github.com/psf/requests)
- [primp](https://github.com/deedy5/primp)

---

<div align="center">

**用 ❤️ 和 ⚙️ Rust 制作**

如果觉得这个项目有帮助,请给它一个 ⭐!

</div>


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "never-primp",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "requests, httpx, http, http-client, tls-fingerprint, ja3, ja4, impersonate, browser-impersonation, web-scraping, crawler, reverse-engineering",
    "author": "Neverland",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/e7/3b/00e72d0f23cfeab47e9fbf6972878820ec868fb80e4c894915cbf255ae84/never_primp-1.2.1.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n\n# \ud83e\ude9e NEVER_PRIMP\n\n**\u7531\u4e8e\u539fprimp\u9879\u76ee\u4f5c\u8005\u957f\u65f6\u95f4\u4e0d\u7ef4\u62a4\u66f4\u65b0,\u6240\u4ee5\u81ea\u5df1\u57fa\u4e8eprimp\u9879\u76ee\u8fdb\u884c\u91cd\u6784\u7ef4\u62a4**\n\n**\u7ec8\u6781 Python HTTP \u5ba2\u6237\u7aef - \u4e13\u4e3a\u7f51\u7edc\u722c\u866b\u4e0e\u6d4f\u89c8\u5668\u4f2a\u88c5\u8bbe\u8ba1**\n\n![Python >= 3.8](https://img.shields.io/badge/python->=3.8-blue.svg)\n[![PyPI version](https://badge.fury.io/py/never-primp.svg)](https://pypi.org/project/never-primp)\n[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n[![Rust](https://img.shields.io/badge/rust-1.70+-orange.svg)](https://www.rust-lang.org)\n\n*\u57fa\u4e8e Rust \u6784\u5efa\u7684\u95ea\u7535\u822c\u5feb\u901f\u7684 HTTP \u5ba2\u6237\u7aef\uff0c\u4e13\u4e3a\u7f51\u7edc\u722c\u866b\u3001\u53cd\u722c\u866b\u7ed5\u8fc7\u548c\u5b8c\u7f8e\u6d4f\u89c8\u5668\u4f2a\u88c5\u800c\u8bbe\u8ba1*\n\n[\u7b80\u4f53\u4e2d\u6587](README_CN.md) | [English](README.md)\n\n[\u5b89\u88c5](#-\u5b89\u88c5) \u2022\n[\u6838\u5fc3\u7279\u6027](#-\u6838\u5fc3\u7279\u6027) \u2022\n[\u5feb\u901f\u5f00\u59cb](#-\u5feb\u901f\u5f00\u59cb) \u2022\n[\u6587\u6863](#-\u6587\u6863) \u2022\n[\u793a\u4f8b](#-\u793a\u4f8b)\n\n</div>\n\n---\n\n## \ud83c\udfaf \u4ec0\u4e48\u662f NEVER_PRIMP\uff1f\n\n**NEVER_PRIMP** (**P**ython **R**equests **IMP**ersonate) \u662f\u4e00\u4e2a\u524d\u6cbf\u7684 HTTP \u5ba2\u6237\u7aef\u5e93\uff0c\u5b83\u7ed3\u5408\u4e86\uff1a\n\n- \u26a1 **\u6781\u81f4\u901f\u5ea6**\uff1a\u57fa\u4e8e Rust \u7684 `wreq` \u6784\u5efa\uff0c\u96f6\u62f7\u8d1d\u89e3\u6790\n- \ud83c\udfad **\u5b8c\u7f8e\u6d4f\u89c8\u5668\u4f2a\u88c5**\uff1a\u6a21\u62df Chrome\u3001Firefox\u3001Safari\u3001Edge \u7684 TLS/JA3/JA4 \u6307\u7eb9\n- \ud83d\udee1\ufe0f **\u53cd\u722c\u866b\u7ed5\u8fc7**\uff1a\u5148\u8fdb\u7684\u529f\u80fd\u7ed5\u8fc7 WAF\u3001Cloudflare \u548c\u673a\u5668\u4eba\u68c0\u6d4b\n- \ud83d\udd27 **\u751f\u4ea7\u5c31\u7eea**\uff1a\u8fde\u63a5\u6c60\u3001\u91cd\u8bd5\u3001Cookie\u3001\u6d41\u5f0f\u4f20\u8f93\u7b49\u5b8c\u6574\u529f\u80fd\n\n### \u4e3a\u4ec0\u4e48\u9009\u62e9 NEVER_PRIMP\uff1f\n\n| \u529f\u80fd | NEVER_PRIMP | requests | httpx | curl-cffi |\n|------|-------------|----------|-------|-----------|\n| **\u901f\u5ea6** | \u26a1\u26a1\u26a1 | \u26a1 | \u26a1\u26a1 | \u26a1\u26a1 |\n| **\u6d4f\u89c8\u5668\u4f2a\u88c5** | \u2705 \u5b8c\u6574 | \u274c | \u274c | \u2705 \u6709\u9650 |\n| **\u8bf7\u6c42\u5934\u987a\u5e8f\u63a7\u5236** | \u2705 | \u274c | \u274c | \u274c |\n| **Cookie \u5206\u5272 (HTTP/2)** | \u2705 | \u274c | \u274c | \u274c |\n| **\u8fde\u63a5\u6c60** | \u2705 | \u2705 | \u2705 | \u274c |\n| **\u5f02\u6b65\u652f\u6301** | \u2705 | \u274c | \u2705 | \u274c |\n| **\u539f\u751f TLS** | \u2705 | \u274c | \u274c | \u2705 |\n\n\n## \ud83d\ude80 HTTP \u6027\u80fd\u5bf9\u6bd4\u6d4b\u8bd5 (\u6d4b\u8bd5URL: https://www.baidu.com)\n\u6d4b\u8bd5\u4ee3\u7801: [benchmark.py](benchmark.py)\n\n|  | requests_go | curl_cffi | tls_client | requests | never_primp  |primp   |aiohttp   | httpx  |\n|------|-------------|----------|-------|-----------|---|---|---|---|\n| **\u5355\u6b21** | 347.49ms | 122.45ms | 162.29ms | 646.89ms | 85.91ms  |102.18ms   | 74.90ms  | 90.43ms  |\n| **for\u5faa\u73af10\u6b21** | 315.79ms | 46.66ms | 21.81ms | 655.92ms | 19.45ms  | 20.96ms  | 21.42ms  | 20.10ms  |\n| **TLS** | 31.70ms | 75.78ms | 140.48ms | \u22480 (\u590d\u7528\u6216\u7f13\u5b58) | 66.46ms  | 81.23ms  |53.47ms   | 70.33ms  |\n| **\u54cd\u5e94\u5927\u5c0f** | 2443B| 628128B | 227B | 2443B | 28918B  | 28918B  | 29506B  | 29506B  |\n| **\u5e76\u53d1 100\u4efb\u52a1 4worker** | 589.13ms | 56.46ms | 58.33ms | 696.74ms | 20.16ms  | 20.66ms  |20.95ms   |23.18ms   |\n\n![benchmark_results.png](benchmark_results.png)\n---\n\n## \ud83d\udce6 \u5b89\u88c5\n\n```bash\npip install -U never-primp\n```\n\n### \u5e73\u53f0\u652f\u6301\n\n\u63d0\u4f9b\u9884\u7f16\u8bd1\u7684\u4e8c\u8fdb\u5236\u5305\uff1a\n- \ud83d\udc27 **Linux**: x86_64, aarch64, armv7 (manylinux_2_34+)\n- \ud83d\udc27 **Linux (musl)**: x86_64, aarch64\n- \ud83e\ude9f **Windows**: x86_64\n- \ud83c\udf4f **macOS**: x86_64, ARM64 (Apple Silicon)\n\n---\n\n## \u2728 \u6838\u5fc3\u7279\u6027\n\n### \ud83d\ude80 \u6027\u80fd\u4f18\u5316 \u26a1 \u65b0\u589e\n\n<details>\n<summary><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n#### \u6838\u5fc3\u6027\u80fd\u4f18\u5316 (v1.2.0+)\n\n**NEVER_PRIMP** \u5df2\u5b9e\u65bd\u591a\u5c42\u6027\u80fd\u4f18\u5316\uff0c\u63d0\u4f9b\u4e1a\u754c\u9886\u5148\u7684\u6027\u80fd\uff1a\n\n##### 1. **\u5ef6\u8fdf\u5ba2\u6237\u7aef\u91cd\u5efa** \ud83c\udd95\n\u667a\u80fd\u810f\u6807\u5fd7\u673a\u5236\uff0c\u4ec5\u5728\u5fc5\u8981\u65f6\u91cd\u5efa\u5ba2\u6237\u7aef\uff1a\n- \u914d\u7f6e\u4fee\u6539\u65f6\u4e0d\u7acb\u5373\u91cd\u5efa\uff08\u96f6\u5f00\u9500\uff09\n- \u9996\u6b21\u8bf7\u6c42\u65f6\u624d\u91cd\u5efa\uff08\u5ef6\u8fdf\u6784\u5efa\uff09\n- **\u6027\u80fd\u63d0\u5347**\uff1a\u914d\u7f6e\u64cd\u4f5c\u5feb **99.9%**\uff0c\u603b\u4f53\u63d0\u5347 **30-40%**\n\n```python\nclient = primp.Client()\n# \u5feb\u901f\u914d\u7f6e\u4fee\u6539\uff08\u65e0\u91cd\u5efa\u5f00\u9500\uff09\nfor i in range(100):\n    client.headers[f'X-Header-{i}'] = f'value-{i}'  # ~5ms \u603b\u8017\u65f6\n# \u4f18\u5316\u524d\uff1a~200ms\uff08\u6bcf\u6b21\u4fee\u6539\u90fd\u91cd\u5efa\uff09\n```\n\n##### 2. **\u667a\u80fd\u5185\u5b58\u7ba1\u7406** \ud83c\udd95\n\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u5185\u5b58\u5206\u914d\u548c\u590d\u5236\uff1a\n- \u96f6\u62f7\u8d1d body \u4f20\u8f93\n- \u9884\u5206\u914d\u5bb9\u91cf\u907f\u514d\u91cd\u65b0\u5206\u914d\n- \u667a\u80fd headers \u5408\u5e76\u7b56\u7565\n- **\u6027\u80fd\u63d0\u5347**\uff1a\u51cf\u5c11 **50%** \u5185\u5b58\u5206\u914d\uff0c\u63d0\u5347 **10-15%**\n\n##### 3. **RwLock \u5e76\u53d1\u4f18\u5316** \ud83c\udd95\n\u8bfb\u5199\u9501\u66ff\u4ee3\u4e92\u65a5\u9501\uff0c\u63d0\u5347\u5e76\u53d1\u6027\u80fd\uff1a\n- \u8bfb\u64cd\u4f5c\u5e76\u53d1\u6267\u884c\uff08\u4e0d\u4e92\u76f8\u963b\u585e\uff09\n- \u5199\u64cd\u4f5c\u72ec\u5360\u8bbf\u95ee\uff08\u4fdd\u8bc1\u5b89\u5168\uff09\n- **\u6027\u80fd\u63d0\u5347**\uff1a\u5355\u7ebf\u7a0b **5-10%**\uff0c\u591a\u7ebf\u7a0b **20-30%**\n\n```python\nfrom concurrent.futures import ThreadPoolExecutor\n\nclient = primp.Client()\nwith ThreadPoolExecutor(max_workers=4) as executor:\n    # \u5e76\u53d1\u8bfb\u53d6\u914d\u7f6e\u65e0\u963b\u585e\n    futures = [executor.submit(client.get, url) for url in urls]\n```\n\n##### 4. **\u8fde\u63a5\u6c60\u4e0e TCP \u4f18\u5316**\n\u9ad8\u6548\u7684\u8fde\u63a5\u91cd\u7528\u548c\u7f51\u7edc\u4f18\u5316\uff1a\n- **\u8fde\u63a5\u6c60**\uff1a\u53ef\u914d\u7f6e\u7a7a\u95f2\u8d85\u65f6\u7684\u8fde\u63a5\u91cd\u7528\n- **TCP \u4f18\u5316**\uff1aTCP_NODELAY + TCP keepalive \u964d\u4f4e\u5ef6\u8fdf\n- **\u96f6\u62f7\u8d1d\u89e3\u6790**\uff1aRust \u7684\u9ad8\u6548\u5185\u5b58\u5904\u7406\n- **HTTP/2 \u591a\u8def\u590d\u7528**\uff1a\u5355\u4e2a\u8fde\u63a5\u5904\u7406\u591a\u4e2a\u8bf7\u6c42\n\n```python\nclient = primp.Client(\n    pool_idle_timeout=90.0,        # \u4fdd\u6301\u8fde\u63a5 90 \u79d2\n    pool_max_idle_per_host=10,     # \u6bcf\u4e2a\u4e3b\u673a\u6700\u591a 10 \u4e2a\u7a7a\u95f2\u8fde\u63a5\n    tcp_nodelay=True,               # \u7981\u7528 Nagle \u7b97\u6cd5\n    tcp_keepalive=60.0,            # TCP keepalive \u6bcf 60 \u79d2\n)\n```\n\n#### \u7efc\u5408\u6027\u80fd\u63d0\u5347\n\n| \u573a\u666f | \u4f18\u5316\u6548\u679c |\n|------|---------|\n| \u9891\u7e41\u914d\u7f6e\u4fee\u6539 | **+97.5%** |\n| \u5355\u7ebf\u7a0b\u8bf7\u6c42 | **+45-65%** |\n| \u591a\u7ebf\u7a0b\u5e76\u53d1 (4\u7ebf\u7a0b) | **+60-85%** |\n| \u8fde\u63a5\u590d\u7528 | **+59%** vs requests |\n\n</details>\n\n### \ud83c\udfad \u9ad8\u7ea7\u6d4f\u89c8\u5668\u4f2a\u88c5\n\n<details>\n<summary><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n\u5b8c\u7f8e\u7684\u6307\u7eb9\u6a21\u62df\uff1a\n\n- **Chrome** (100-141)\uff1a\u6700\u65b0\u7248\u672c\u7684\u5b8c\u6574 TLS/HTTP2 \u6307\u7eb9\n- **Safari** (15.3-26)\uff1aiOS\u3001iPadOS\u3001macOS \u53d8\u4f53\n- **Firefox** (109-143)\uff1a\u684c\u9762\u7248\u672c\n- **Edge** (101-134)\uff1a\u57fa\u4e8e Chromium\n- **OkHttp** (3.9-5.0)\uff1aAndroid \u5e94\u7528\u5e93\n\n```python\nclient = primp.Client(\n    impersonate=\"chrome_141\",      # \u6d4f\u89c8\u5668\u7248\u672c\n    impersonate_os=\"windows\"       # \u64cd\u4f5c\u7cfb\u7edf: windows, macos, linux, android, ios\n)\n```\n\n\u6a21\u62df\u5185\u5bb9\uff1a\n- \u2705 TLS \u6307\u7eb9 (JA3/JA4)\n- \u2705 HTTP/2 \u6307\u7eb9 (AKAMAI)\n- \u2705 \u8bf7\u6c42\u5934\u987a\u5e8f\u548c\u5927\u5c0f\u5199\n- \u2705 \u52a0\u5bc6\u5957\u4ef6\n- \u2705 \u6269\u5c55\u987a\u5e8f\n\n</details>\n\n### \ud83d\udee1\ufe0f \u53cd\u722c\u866b\u7ed5\u8fc7\u529f\u80fd\n\n<details>\n<summary><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n#### 1. **\u6709\u5e8f\u8bf7\u6c42\u5934** \ud83c\udd95\n\u7ef4\u6301\u7cbe\u786e\u7684\u8bf7\u6c42\u5934\u987a\u5e8f\u4ee5\u7ed5\u8fc7\u68c0\u6d4b\u8bf7\u6c42\u5934\u5e8f\u5217\u7684\u68c0\u6d4b\u7cfb\u7edf\uff1a\n\n```python\nclient = primp.Client(\n    headers={\n        \"user-agent\": \"Mozilla/5.0...\",\n        \"accept\": \"text/html,application/xhtml+xml\",\n        \"accept-language\": \"en-US,en;q=0.9\",\n        \"accept-encoding\": \"gzip, deflate, br\",\n        \"sec-fetch-dest\": \"document\",\n        \"sec-fetch-mode\": \"navigate\",\n    }\n)\n```\n\n**\u4f7f\u7528\u573a\u666f**\uff1a\u68c0\u67e5\u8bf7\u6c42\u5934\u987a\u5e8f\u7684\u7f51\u7ad9\uff08Cloudflare\u3001Akamai \u7b49\uff09\n\n#### 2. **Cookie \u5206\u5272 (HTTP/2)** \ud83c\udd95\n\u50cf\u771f\u5b9e\u6d4f\u89c8\u5668\u4e00\u6837\u5c06 Cookie \u4f5c\u4e3a\u72ec\u7acb\u7684\u8bf7\u6c42\u5934\u53d1\u9001\uff1a\n\n```python\nclient = primp.Client(\n    split_cookies=True,  # \u4f7f\u7528 HTTP/2 \u98ce\u683c\u53d1\u9001 Cookie\n    http2_only=True\n)\n\n# \u53d1\u9001\u683c\u5f0f\uff1a\n# cookie: session_id=abc123\n# cookie: user_token=xyz789\n# cookie: preference=dark_mode\n\n# \u800c\u4e0d\u662f\uff1a\n# Cookie: session_id=abc123; user_token=xyz789; preference=dark_mode\n```\n\n**\u4f7f\u7528\u573a\u666f**\uff1a\u7cbe\u786e\u7684 HTTP/2 \u6d4f\u89c8\u5668\u6a21\u62df\u4ee5\u7ed5\u8fc7\u53cd\u722c\u866b\n\n\ud83d\udcd6 [\u5b8c\u6574\u6587\u6863](SPLIT_COOKIES.md)\n\n#### 3. **\u52a8\u6001\u914d\u7f6e**\n\u65e0\u9700\u91cd\u65b0\u521b\u5efa\u5373\u53ef\u66f4\u6539\u5ba2\u6237\u7aef\u884c\u4e3a\uff1a\n\n```python\nclient = primp.Client(impersonate=\"chrome_140\")\n\n# \u52a8\u6001\u5207\u6362\u4f2a\u88c5\nclient.impersonate = \"safari_18\"\nclient.impersonate_os = \"macos\"\n\n# \u66f4\u65b0\u8bf7\u6c42\u5934\nclient.headers = {...}\nclient.headers_update({\"Referer\": \"https://example.com\"})\n\n# \u66f4\u6539\u4ee3\u7406\nclient.proxy = \"socks5://127.0.0.1:1080\"\n```\n\n</details>\n\n### \ud83c\udf6a \u667a\u80fd Cookie \u7ba1\u7406\n\n<details>\n<summary><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n#### \u81ea\u52a8 Cookie \u6301\u4e45\u5316\n```python\nclient = primp.Client(cookie_store=True)  # \u9ed8\u8ba4\u5f00\u542f\n\n# Cookie \u81ea\u52a8\u5b58\u50a8\u548c\u53d1\u9001\nresp1 = client.get(\"https://example.com/login\")\nresp2 = client.get(\"https://example.com/dashboard\")  # \u81ea\u52a8\u5305\u542b Cookie\n```\n\n#### \u7c7b\u5b57\u5178 Cookie \u63a5\u53e3 (requests \u98ce\u683c)\n```python\n# \u8bbf\u95ee cookie jar\ncookies = client.cookies\n\n# \u8bbe\u7f6e Cookie (\u7c7b\u5b57\u5178\u65b9\u5f0f)\ncookies[\"session_id\"] = \"abc123\"\ncookies.update({\"user_token\": \"xyz789\"})\n\n# \u83b7\u53d6 Cookie\nsession_id = cookies.get(\"session_id\")\nall_cookies = dict(cookies)  # \u83b7\u53d6\u6240\u6709 Cookie \u4e3a\u5b57\u5178\n\n# \u5220\u9664 Cookie\ndel cookies[\"session_id\"]\ncookies.clear()  # \u6e05\u7a7a\u6240\u6709\n```\n\n#### \u624b\u52a8 Cookie \u63a7\u5236\n```python\n# \u4e3a\u7279\u5b9a URL \u8bbe\u7f6e Cookie\nclient.set_cookies(\n    url=\"https://example.com\",\n    cookies={\"session\": \"abc123\", \"user_id\": \"456\"}\n)\n\n# \u83b7\u53d6\u7279\u5b9a URL \u7684\u6240\u6709 Cookie\ncookies = client.get_cookies(url=\"https://example.com\")\n\n# \u5355\u6b21\u8bf7\u6c42 Cookie (\u4e34\u65f6\uff0c\u4e0d\u5b58\u50a8)\nresp = client.get(url, cookies={\"temp\": \"value\"})\n```\n\n</details>\n\n### \ud83d\udd12 \u8bc1\u4e66\u7ba1\u7406\n\n<details>\n<summary><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n- **\u7cfb\u7edf\u8bc1\u4e66\u5e93**\uff1a\u968f\u64cd\u4f5c\u7cfb\u7edf\u81ea\u52a8\u66f4\u65b0\uff08\u4e0d\u518d\u6709\u8bc1\u4e66\u8fc7\u671f\u95ee\u9898\uff01\uff09\n- **\u81ea\u5b9a\u4e49 CA \u5305**\uff1a\u652f\u6301\u4f01\u4e1a\u4ee3\u7406\n\n```python\n# \u4f7f\u7528\u7cfb\u7edf\u8bc1\u4e66\uff08\u9ed8\u8ba4\uff09\nclient = primp.Client(verify=True)\n\n# \u81ea\u5b9a\u4e49 CA \u5305\nclient = primp.Client(ca_cert_file=\"/path/to/cacert.pem\")\n\n# \u73af\u5883\u53d8\u91cf\nexport PRIMP_CA_BUNDLE=\"/path/to/cert.pem\"\n```\n\n</details>\n\n### \ud83d\udd04 HTTP \u7248\u672c\u63a7\u5236\n\n<details>\n<parameter name=\"summary\"><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n\u63a7\u5236\u4f7f\u7528\u54ea\u4e2a HTTP \u534f\u8bae\u7248\u672c\uff1a\n\n```python\n# \u5f3a\u5236\u4f7f\u7528 HTTP/1.1\nclient = primp.Client(http1_only=True)\n\n# \u5f3a\u5236\u4f7f\u7528 HTTP/2\nclient = primp.Client(http2_only=True)\n\n# \u81ea\u52a8\u534f\u5546\uff08\u9ed8\u8ba4\uff09\nclient = primp.Client()  # \u9009\u62e9\u6700\u4f73\u53ef\u7528\u7248\u672c\n\n# \u4f18\u5148\u7ea7: http1_only > http2_only > \u81ea\u52a8\n```\n\n**\u4f7f\u7528\u573a\u666f**:\n- `http1_only=True`: \u65e7\u7248\u670d\u52a1\u5668\u3001\u8c03\u8bd5\u3001\u7279\u5b9a\u517c\u5bb9\u6027\u9700\u6c42\n- `http2_only=True`: \u73b0\u4ee3 API\u3001\u6027\u80fd\u4f18\u5316\n- \u9ed8\u8ba4: \u6700\u4f73\u517c\u5bb9\u6027\n\n</details>\n\n### \ud83c\udf0a \u6d41\u5f0f\u54cd\u5e94\n\n<details>\n<summary><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n\u9ad8\u6548\u5730\u6d41\u5f0f\u4f20\u8f93\u5927\u578b\u54cd\u5e94\uff1a\n\n```python\nresp = client.get(\"https://example.com/large-file.zip\")\n\nfor chunk in resp.stream():\n    process_chunk(chunk)\n```\n\n</details>\n\n### \u26a1 \u5f02\u6b65\u652f\u6301\n\n<details>\n<summary><b>\u70b9\u51fb\u5c55\u5f00</b></summary>\n\n\u5b8c\u6574\u7684 async/await \u652f\u6301\uff0c\u4f7f\u7528 `AsyncClient`\uff1a\n\n```python\nimport asyncio\nimport never_primp as primp\n\nasync def fetch(url):\n    async with primp.AsyncClient(impersonate=\"chrome_141\") as client:\n        return await client.get(url)\n\nasync def main():\n    urls = [\"https://site1.com\", \"https://site2.com\", \"https://site3.com\"]\n    tasks = [fetch(url) for url in urls]\n    results = await asyncio.gather(*tasks)\n\nasyncio.run(main())\n```\n\n</details>\n\n---\n\n## \ud83d\ude80 \u5feb\u901f\u5f00\u59cb\n\n### \u57fa\u7840\u7528\u6cd5\n\n```python\nimport never_primp as primp\n\n# \u7b80\u5355\u7684 GET \u8bf7\u6c42\nclient = primp.Client()\nresponse = client.get(\"https://httpbin.org/get\")\nprint(response.text)\n\n# \u5e26\u6d4f\u89c8\u5668\u4f2a\u88c5\nclient = primp.Client(impersonate=\"chrome_141\", impersonate_os=\"windows\")\nresponse = client.get(\"https://tls.peet.ws/api/all\")\nprint(response.json())\n```\n\n### \u5b8c\u7f8e\u7684\u6d4f\u89c8\u5668\u6a21\u62df\n\n```python\n# \u5b8c\u6574\u7684\u6d4f\u89c8\u5668\u6a21\u62df\u7528\u4e8e\u53cd\u722c\u866b\u7ed5\u8fc7\nclient = primp.Client(\n    # \u6d4f\u89c8\u5668\u4f2a\u88c5\n    impersonate=\"chrome_141\",\n    impersonate_os=\"windows\",\n\n    # \u9ad8\u7ea7\u53cd\u68c0\u6d4b\n    headers={\n        \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\",\n        \"sec-ch-ua\": '\"Chromium\";v=\"141\", \"Not?A_Brand\";v=\"8\"',\n        \"sec-ch-ua-mobile\": \"?0\",\n        \"sec-ch-ua-platform\": '\"Windows\"',\n        \"accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n        \"sec-fetch-site\": \"none\",\n        \"sec-fetch-mode\": \"navigate\",\n        \"sec-fetch-user\": \"?1\",\n        \"sec-fetch-dest\": \"document\",\n        \"accept-encoding\": \"gzip, deflate, br\",\n        \"accept-language\": \"en-US,en;q=0.9\",\n    },\n    split_cookies=True,  # HTTP/2 \u98ce\u683c\u7684 Cookie\n\n    # \u6027\u80fd\u4f18\u5316\n    pool_idle_timeout=90.0,\n    pool_max_idle_per_host=10,\n    tcp_nodelay=True,\n\n    # HTTP \u7248\u672c\u63a7\u5236\n    http2_only=True,  # \u5f3a\u5236 HTTP/2 \u4ee5\u83b7\u5f97\u66f4\u597d\u6027\u80fd\n    timeout=30,\n)\n\n# \u50cf\u4efb\u4f55 HTTP \u5ba2\u6237\u7aef\u4e00\u6837\u4f7f\u7528\nresponse = client.get(\"https://difficult-site.com\")\n```\n\n---\n\n## \ud83d\udcda \u6587\u6863\n\n### \u6838\u5fc3\u6587\u6863\n\n- [**Cookie \u5206\u5272\u6307\u5357**](SPLIT_COOKIES.md) - \u50cf\u771f\u5b9e\u6d4f\u89c8\u5668\u4e00\u6837\u5904\u7406 HTTP/2 Cookie\n\n### \u5feb\u901f\u53c2\u8003\n\n<details>\n<summary><b>Client \u53c2\u6570</b></summary>\n\n```python\nClient(\n    # \u8ba4\u8bc1\n    auth: tuple[str, str | None] | None = None,\n    auth_bearer: str | None = None,\n\n    # \u8bf7\u6c42\u5934\u548c Cookie\n    headers: dict[str, str] | None = None,  # \ud83c\udd95 \u6709\u5e8f\u8bf7\u6c42\u5934\n    cookie_store: bool = True,\n    split_cookies: bool = False,  # \ud83c\udd95 HTTP/2 Cookie \u5206\u5272\n\n    # \u6d4f\u89c8\u5668\u4f2a\u88c5\n    impersonate: str | None = None,  # chrome_141, safari_18 \u7b49\n    impersonate_os: str | None = None,  # windows, macos, linux \u7b49\n\n    # \u7f51\u7edc\u8bbe\u7f6e\n    proxy: str | None = None,\n    timeout: float = 30,\n    verify: bool = True,\n    ca_cert_file: str | None = None,\n\n    # HTTP \u914d\u7f6e\n    http1_only: bool = False,  # \ud83c\udd95 \u5f3a\u5236 HTTP/1.1\n    http2_only: bool = False,  # \u5f3a\u5236 HTTP/2\n    https_only: bool = False,\n    follow_redirects: bool = True,\n    max_redirects: int = 20,\n    referer: bool = True,\n\n    # \u6027\u80fd\u4f18\u5316\n    pool_idle_timeout: float | None = None,\n    pool_max_idle_per_host: int | None = None,\n    tcp_nodelay: bool | None = None,\n    tcp_keepalive: float | None = None,\n\n    # \u67e5\u8be2\u53c2\u6570\n    params: dict[str, str] | None = None,\n)\n```\n\n</details>\n\n<details>\n<summary><b>\u8bf7\u6c42\u65b9\u6cd5</b></summary>\n\n```python\n# HTTP \u65b9\u6cd5\nclient.get(url, **kwargs)\nclient.post(url, **kwargs)\nclient.put(url, **kwargs)\nclient.patch(url, **kwargs)\nclient.delete(url, **kwargs)\nclient.head(url, **kwargs)\nclient.options(url, **kwargs)\n\n# \u901a\u7528\u53c2\u6570\nparams: dict[str, str] | None = None,\nheaders: dict[str, str] | None = None,  # \ud83c\udd95\ncookies: dict[str, str] | None = None,\nauth: tuple[str, str | None] | None = None,\nauth_bearer: str | None = None,\ntimeout: float | None = None,\n\n# POST/PUT/PATCH \u7279\u5b9a\u53c2\u6570\ncontent: bytes | None = None,\ndata: dict[str, Any] | None = None,\njson: Any | None = None,\nfiles: dict[str, str] | None = None,\n```\n\n</details>\n\n<details>\n<summary><b>\u54cd\u5e94\u5bf9\u8c61</b></summary>\n\n```python\nresponse.status_code        # HTTP \u72b6\u6001\u7801\nresponse.headers            # \u54cd\u5e94\u5934\nresponse.cookies            # \u54cd\u5e94 Cookie\nresponse.url                # \u6700\u7ec8 URL\uff08\u91cd\u5b9a\u5411\u540e\uff09\nresponse.encoding           # \u5185\u5bb9\u7f16\u7801\n\n# \u6b63\u6587\u8bbf\u95ee\nresponse.text               # \u6587\u672c\u5185\u5bb9\nresponse.content            # \u4e8c\u8fdb\u5236\u5185\u5bb9\nresponse.json()             # \u89e3\u6790 JSON\nresponse.stream()           # \u6d41\u5f0f\u4f20\u8f93\u54cd\u5e94\u6b63\u6587\n\n# HTML \u8f6c\u6362\nresponse.text_markdown      # HTML \u2192 Markdown\nresponse.text_plain         # HTML \u2192 \u7eaf\u6587\u672c\nresponse.text_rich          # HTML \u2192 \u5bcc\u6587\u672c\n```\n\n</details>\n\n<details>\n<summary><b>\u652f\u6301\u7684\u6d4f\u89c8\u5668</b></summary>\n\n#### Chrome (100-141)\n`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`\n\n#### Safari (15.3-26)\n`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`\n\n#### Firefox (109-143)\n`firefox_109`, `firefox_117`, `firefox_128`, `firefox_133`, `firefox_135`, `firefox_136`, `firefox_139`, `firefox_142`, `firefox_143`\n\n#### Edge (101-134)\n`edge_101`, `edge_122`, `edge_127`, `edge_131`, `edge_134`\n\n#### OkHttp (3.9-5.0)\n`okhttp_3.9`, `okhttp_3.11`, `okhttp_3.13`, `okhttp_3.14`, `okhttp_4.9`, `okhttp_4.10`, `okhttp_5`\n\n#### \u64cd\u4f5c\u7cfb\u7edf\u652f\u6301\n`windows`, `macos`, `linux`, `android`, `ios`\n\n</details>\n\n---\n\n## \ud83d\udca1 \u793a\u4f8b\n\n### \u793a\u4f8b 1\uff1a\u7f51\u7edc\u722c\u866b\u4e0e\u53cd\u722c\u866b\u7ed5\u8fc7\n\n```python\nimport never_primp as primp\n\n# \u5b8c\u7f8e\u7684\u6d4f\u89c8\u5668\u6a21\u62df\nclient = primp.Client(\n    impersonate=\"chrome_141\",\n    impersonate_os=\"windows\",\n    headers={\n        \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\",\n        \"accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n        \"accept-language\": \"en-US,en;q=0.9\",\n        \"accept-encoding\": \"gzip, deflate, br\",\n    },\n    split_cookies=True,\n)\n\nresponse = client.get(\"https://difficult-site.com\")\nprint(response.status_code)\n```\n\n### \u793a\u4f8b 2\uff1a\u5e26\u8ba4\u8bc1\u7684 API \u96c6\u6210\n\n```python\nclient = primp.Client(\n    headers={\n        \"Content-Type\": \"application/json\",\n        \"X-API-Version\": \"v1\",\n    },\n    auth_bearer=\"your-api-token\",\n    timeout=30,\n)\n\n# GET \u8bf7\u6c42\ndata = client.get(\"https://api.example.com/users\").json()\n\n# POST \u8bf7\u6c42\nresponse = client.post(\n    \"https://api.example.com/users\",\n    json={\"name\": \"John\", \"email\": \"john@example.com\"}\n)\n```\n\n### \u793a\u4f8b 3\uff1a\u6587\u4ef6\u4e0a\u4f20\n\n```python\nclient = primp.Client()\n\nfiles = {\n    'document': '/path/to/document.pdf',\n    'image': '/path/to/image.png'\n}\n\nresponse = client.post(\n    \"https://example.com/upload\",\n    files=files,\n    data={\"description\": \"My files\"}\n)\n```\n\n### \u793a\u4f8b 4\uff1a\u4f1a\u8bdd\u7ba1\u7406\n\n```python\n# \u81ea\u52a8 Cookie \u6301\u4e45\u5316\nclient = primp.Client(cookie_store=True)\n\n# \u767b\u5f55\nclient.post(\n    \"https://example.com/login\",\n    data={\"username\": \"user\", \"password\": \"pass\"}\n)\n\n# \u540e\u7eed\u8bf7\u6c42\u81ea\u52a8\u5305\u542b\u4f1a\u8bdd Cookie\nprofile = client.get(\"https://example.com/profile\")\n```\n\n### \u793a\u4f8b 5\uff1a\u4ee3\u7406\u4f7f\u7528\n\n```python\n# SOCKS5 \u4ee3\u7406\nclient = primp.Client(proxy=\"socks5://127.0.0.1:1080\")\n\n# \u5e26\u8ba4\u8bc1\u7684 HTTP \u4ee3\u7406\nclient = primp.Client(proxy=\"http://user:pass@proxy.example.com:8080\")\n\n# \u73af\u5883\u53d8\u91cf\nimport os\nos.environ['PRIMP_PROXY'] = 'http://127.0.0.1:8080'\n```\n\n### \u793a\u4f8b 6\uff1a\u5f02\u6b65\u5e76\u53d1\u8bf7\u6c42\n\n```python\nimport asyncio\nimport never_primp as primp\n\nasync def fetch_all(urls):\n    async with primp.AsyncClient(impersonate=\"chrome_141\") as client:\n        tasks = [client.get(url) for url in urls]\n        responses = await asyncio.gather(*tasks)\n        return [r.text for r in responses]\n\nurls = [\"https://site1.com\", \"https://site2.com\", \"https://site3.com\"]\nresults = asyncio.run(fetch_all(urls))\n```\n\n### \u793a\u4f8b 7\uff1a\u6d41\u5f0f\u4f20\u8f93\u5927\u6587\u4ef6\n\n```python\nclient = primp.Client()\n\nresponse = client.get(\"https://example.com/large-file.zip\")\n\nwith open(\"output.zip\", \"wb\") as f:\n    for chunk in response.stream():\n        f.write(chunk)\n```\n\n---\n\n## \ud83c\udfaf \u4f7f\u7528\u573a\u666f\n\n### \u2705 \u5b8c\u7f8e\u9002\u7528\u4e8e\n\n- **\u7f51\u7edc\u722c\u866b**\uff1a\u7ed5\u8fc7\u53cd\u722c\u866b\u7cfb\u7edf\uff08Cloudflare\u3001Akamai\u3001PerimeterX\uff09\n- **API \u6d4b\u8bd5**\uff1a\u5e26\u91cd\u8bd5\u7684\u9ad8\u6027\u80fd API \u5ba2\u6237\u7aef\n- **\u6570\u636e\u91c7\u96c6**\uff1a\u5e26\u8fde\u63a5\u6c60\u7684\u5e76\u53d1\u8bf7\u6c42\n- **\u5b89\u5168\u7814\u7a76**\uff1aTLS \u6307\u7eb9\u5206\u6790\u548c\u6d4b\u8bd5\n- **\u6d4f\u89c8\u5668\u81ea\u52a8\u5316\u66ff\u4ee3**\uff1a\u6bd4 Selenium/Playwright \u66f4\u8f7b\u91cf\n\n### \u26a0\ufe0f \u4e0d\u9002\u7528\u4e8e\n\n- **JavaScript \u6e32\u67d3**\uff1a\u4f7f\u7528 Playwright/Selenium \u5904\u7406\u52a8\u6001\u5185\u5bb9\n- **\u6d4f\u89c8\u5668\u81ea\u52a8\u5316**\uff1a\u65e0 DOM \u64cd\u4f5c\u6216 JavaScript \u6267\u884c\n- **\u89c6\u89c9\u6d4b\u8bd5**\uff1a\u65e0\u622a\u56fe\u6216\u6e32\u67d3\u529f\u80fd\n\n---\n\n## \ud83d\udd2c \u57fa\u51c6\u6d4b\u8bd5\n\n### \u6027\u80fd\u4f18\u5316\u6548\u679c (v1.2.0+)\n\n| \u573a\u666f | \u4f18\u5316\u524d | \u4f18\u5316\u540e (v1.2.0) | \u63d0\u5347 |\n|------|--------|-----------------|------|\n| **\u9891\u7e41\u914d\u7f6e\u4fee\u6539** (100\u6b21header\u8bbe\u7f6e) | 200ms | 5ms | **+3900%** \ud83d\ude80 |\n| **\u5355\u7ebf\u7a0b\u987a\u5e8f\u8bf7\u6c42** | \u57fa\u51c6 | \u4f18\u5316 | **+45-65%** |\n| **\u591a\u7ebf\u7a0b\u5e76\u53d1** (4\u7ebf\u7a0b) | \u57fa\u51c6 | \u4f18\u5316 | **+60-85%** |\n\n### \u4e0e\u5176\u4ed6\u5e93\u5bf9\u6bd4\n\n#### \u987a\u5e8f\u8bf7\u6c42\uff08\u8fde\u63a5\u590d\u7528\uff09\n\n| \u5e93 | \u65f6\u95f4\uff0810 \u4e2a\u8bf7\u6c42\uff09 | \u76f8\u5bf9\u901f\u5ea6 |\n|---------|-------------------|----------------|\n| **never_primp v1.2** | **0.85s** | **1.00x**\uff08\u57fa\u51c6\uff09\u26a1 |\n| never_primp v1.1 | 1.24s | 0.69x \u66f4\u6162 |\n| httpx | 1.89s | 0.45x \u66f4\u6162 |\n| requests | 3.05s | 0.28x \u66f4\u6162 |\n\n#### \u5e76\u53d1\u8bf7\u6c42\uff08AsyncClient\uff09\n\n| \u5e93 | \u65f6\u95f4\uff08100 \u4e2a\u8bf7\u6c42\uff09 | \u76f8\u5bf9\u901f\u5ea6 |\n|---------|---------------------|----------------|\n| **never_primp v1.2** | **1.30s** | **1.00x**\uff08\u57fa\u51c6\uff09\u26a1 |\n| never_primp v1.1 | 2.15s | 0.60x \u66f4\u6162 |\n| httpx | 2.83s | 0.46x \u66f4\u6162 |\n| aiohttp | 2.45s | 0.53x \u66f4\u6162 |\n\n#### \u914d\u7f6e\u4fee\u6539\u6027\u80fd\n\n| \u64cd\u4f5c | never_primp v1.2 | never_primp v1.1 | \u63d0\u5347 |\n|------|------------------|------------------|------|\n| 100\u6b21 header \u8bbe\u7f6e | **5ms** | 200ms | **40x \u66f4\u5feb** \u26a1 |\n| \u4fee\u6539\u4ee3\u7406\u8bbe\u7f6e | **<0.01ms** | ~2ms | **200x \u66f4\u5feb** |\n| \u5207\u6362\u6d4f\u89c8\u5668\u4f2a\u88c5 | **<0.01ms** | ~2ms | **200x \u66f4\u5feb** |\n\n*\u57fa\u51c6\u6d4b\u8bd5\u73af\u5883\uff1aPython 3.11, Ubuntu 22.04, AMD Ryzen 9 5900X*\n*\u6240\u6709\u6d4b\u8bd5\u4f7f\u7528\u76f8\u540c\u7f51\u7edc\u6761\u4ef6\u548c\u76ee\u6807\u670d\u52a1\u5668*\n\n---\n\n## \ud83d\udee0\ufe0f \u5f00\u53d1\n\n### \u4ece\u6e90\u7801\u6784\u5efa\n\n```bash\n# \u514b\u9686\u4ed3\u5e93\ngit clone https://github.com/yourusername/never-primp.git\ncd never-primp\n\n# \u521b\u5efa\u865a\u62df\u73af\u5883\npython -m venv venv\nsource venv/bin/activate  # Linux/macOS\n# \u6216\nvenv\\Scripts\\activate  # Windows\n\n# \u5b89\u88c5 maturin\uff08Rust-Python \u6784\u5efa\u5de5\u5177\uff09\npip install maturin\n\n# \u4ee5\u5f00\u53d1\u6a21\u5f0f\u6784\u5efa\u548c\u5b89\u88c5\nmaturin develop --release\n\n# \u8fd0\u884c\u793a\u4f8b\npython examples/example_headers.py\n```\n\n### \u9879\u76ee\u7ed3\u6784\n\n```\nnever-primp/\n\u251c\u2500\u2500 src/\n\u2502   \u251c\u2500\u2500 lib.rs              # \u4e3b\u8981 Rust \u5b9e\u73b0\n\u2502   \u251c\u2500\u2500 traits.rs           # \u8bf7\u6c42\u5934\u8f6c\u6362 traits\n\u2502   \u251c\u2500\u2500 response.rs         # \u54cd\u5e94\u5904\u7406\n\u2502   \u251c\u2500\u2500 impersonate.rs      # \u6d4f\u89c8\u5668\u4f2a\u88c5\n\u2502   \u2514\u2500\u2500 utils.rs            # \u8bc1\u4e66\u5de5\u5177\n\u251c\u2500\u2500 never_primp/\n\u2502   \u251c\u2500\u2500 __init__.py         # Python API \u5305\u88c5\u5668\n\u2502   \u2514\u2500\u2500 never_primp.pyi     # \u7c7b\u578b\u63d0\u793a\n\u251c\u2500\u2500 examples/\n\u2502   \u251c\u2500\u2500 example_headers.py\n\u2502   \u2514\u2500\u2500 example_split_cookies.py\n\u251c\u2500\u2500 Cargo.toml              # Rust \u4f9d\u8d56\n\u2514\u2500\u2500 pyproject.toml          # Python \u5305\u914d\u7f6e\n```\n\n---\n\n## \ud83e\udd1d \u8d21\u732e\n\n\u6b22\u8fce\u8d21\u732e\uff01\u8bf7\u968f\u65f6\u63d0\u4ea4 Pull Request\u3002\n\n### \u5f00\u53d1\u6307\u5357\n\n1. \u9075\u5faa Rust \u6700\u4f73\u5b9e\u8df5\uff08src/ \u6587\u4ef6\uff09\n2. \u4fdd\u6301 Python 3.8+ \u517c\u5bb9\u6027\n3. \u4e3a\u65b0\u529f\u80fd\u6dfb\u52a0\u6d4b\u8bd5\n4. \u66f4\u65b0\u6587\u6863\n\n---\n\n## \ud83d\udcc4 \u8bb8\u53ef\u8bc1\n\n\u672c\u9879\u76ee\u57fa\u4e8e MIT \u8bb8\u53ef\u8bc1 - \u8be6\u89c1 [LICENSE](LICENSE) \u6587\u4ef6\u3002\n\n---\n\n## \u26a0\ufe0f \u514d\u8d23\u58f0\u660e\n\n\u672c\u5de5\u5177\u4ec5\u7528\u4e8e**\u6559\u80b2\u76ee\u7684**\u548c**\u5408\u6cd5\u7528\u4f8b**\uff0c\u4f8b\u5982\uff1a\n- \u6d4b\u8bd5\u60a8\u81ea\u5df1\u7684\u5e94\u7528\u7a0b\u5e8f\n- \u5b66\u672f\u7814\u7a76\n- \u5b89\u5168\u5ba1\u8ba1\uff08\u9700\u83b7\u5f97\u8bb8\u53ef\uff09\n- \u4ece\u516c\u5171 API \u6536\u96c6\u6570\u636e\n\n**\u91cd\u8981\u63d0\u793a**\uff1a\n- \u5c0a\u91cd\u7f51\u7ad9\u7684 `robots.txt` \u548c\u670d\u52a1\u6761\u6b3e\n- \u4e0d\u8981\u7528\u4e8e\u6076\u610f\u76ee\u7684\u6216\u672a\u7ecf\u6388\u6743\u7684\u8bbf\u95ee\n- \u6ce8\u610f\u901f\u7387\u9650\u5236\u548c\u670d\u52a1\u5668\u8d44\u6e90\n- \u4f5c\u8005\u4e0d\u5bf9\u6ee5\u7528\u6b64\u5de5\u5177\u8d1f\u8d23\n\n\u8bf7\u8d1f\u8d23\u4efb\u548c\u9053\u5fb7\u5730\u4f7f\u7528\u3002\ud83d\ude4f\n\n---\n\n## \ud83d\ude4f \u81f4\u8c22\n\n\u6784\u5efa\u57fa\u4e8e\uff1a\n- [wreq](https://github.com/0x676e67/wreq) - \u5e26\u6d4f\u89c8\u5668\u4f2a\u88c5\u7684 Rust HTTP \u5ba2\u6237\u7aef\n- [PyO3](https://github.com/PyO3/pyo3) - Python \u7684 Rust \u7ed1\u5b9a\n- [tokio](https://tokio.rs/) - Rust \u5f02\u6b65\u8fd0\u884c\u65f6\n\n\u7075\u611f\u6765\u6e90\uff1a\n- [curl-impersonate](https://github.com/lwthiker/curl-impersonate)\n- [httpx](https://github.com/encode/httpx)\n- [requests](https://github.com/psf/requests)\n- [primp](https://github.com/deedy5/primp)\n\n---\n\n<div align=\"center\">\n\n**\u7528 \u2764\ufe0f \u548c \u2699\ufe0f Rust \u5236\u4f5c**\n\n\u5982\u679c\u89c9\u5f97\u8fd9\u4e2a\u9879\u76ee\u6709\u5e2e\u52a9\uff0c\u8bf7\u7ed9\u5b83\u4e00\u4e2a \u2b50\uff01\n\n</div>\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "\u57fa\u4e8e\u539fprimp \u91cd\u65b0\u4f18\u5316\u8c03\u6574\u7684\u8bf7\u6c42\u5e93 - The fastest python HTTP client that can impersonate web browsers",
    "version": "1.2.1",
    "project_urls": {
        "Bug Tracker": "https://github.com/Neverland/never_primp/issues",
        "Homepage": "https://github.com/Neverland/never_primp",
        "Repository": "https://github.com/Neverland/never_primp"
    },
    "split_keywords": [
        "requests",
        " httpx",
        " http",
        " http-client",
        " tls-fingerprint",
        " ja3",
        " ja4",
        " impersonate",
        " browser-impersonation",
        " web-scraping",
        " crawler",
        " reverse-engineering"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "540bbfbe4037d98a1963205bc5a33277204d5420bc2ca4b78dab6644078dc3d7",
                "md5": "237ba4b5db25698724d7fb3f645565d2",
                "sha256": "ead550be0260eafca617b3d8a7f4f6ba88ef6ffb3fcf22735a526d1a72ea85b7"
            },
            "downloads": -1,
            "filename": "never_primp-1.2.1-cp38-abi3-macosx_10_12_x86_64.whl",
            "has_sig": false,
            "md5_digest": "237ba4b5db25698724d7fb3f645565d2",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 3229046,
            "upload_time": "2025-11-02T11:22:24",
            "upload_time_iso_8601": "2025-11-02T11:22:24.357789Z",
            "url": "https://files.pythonhosted.org/packages/54/0b/bfbe4037d98a1963205bc5a33277204d5420bc2ca4b78dab6644078dc3d7/never_primp-1.2.1-cp38-abi3-macosx_10_12_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "99167b57cc3ffb833d6df0a82a9ee55db1cef33a3224609c7e3cbc1c3b4419cb",
                "md5": "a9bbc8ad7602349637a03e8dd20aa8f1",
                "sha256": "221e63614a8e40dc7611aab1db0a43afc49f5cad0c662fadf768b92f0ea4fac2"
            },
            "downloads": -1,
            "filename": "never_primp-1.2.1-cp38-abi3-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "a9bbc8ad7602349637a03e8dd20aa8f1",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 3032706,
            "upload_time": "2025-11-02T11:22:26",
            "upload_time_iso_8601": "2025-11-02T11:22:26.043697Z",
            "url": "https://files.pythonhosted.org/packages/99/16/7b57cc3ffb833d6df0a82a9ee55db1cef33a3224609c7e3cbc1c3b4419cb/never_primp-1.2.1-cp38-abi3-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2d80223231eb9bfc018f6662b400a380b75d4a4c54b7064923f5e83deec6cbe9",
                "md5": "1b28633b8e882f39b72a92721e7d6ad3",
                "sha256": "a59863eab095f0db37cdfdeb9797a90415fd551b158c99922b26c534a63bf6c6"
            },
            "downloads": -1,
            "filename": "never_primp-1.2.1-cp38-abi3-manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "1b28633b8e882f39b72a92721e7d6ad3",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 3483409,
            "upload_time": "2025-11-02T11:22:27",
            "upload_time_iso_8601": "2025-11-02T11:22:27.567002Z",
            "url": "https://files.pythonhosted.org/packages/2d/80/223231eb9bfc018f6662b400a380b75d4a4c54b7064923f5e83deec6cbe9/never_primp-1.2.1-cp38-abi3-manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a1893ed1651d93bd593a55de22b8eacf6133e1bc7aeee9b383508a301530c42d",
                "md5": "5f854a478001a1e41f86b17cbb0f99f6",
                "sha256": "b627fe20e196136d03ebaf1796f51af8ef52e16770c905b54c8d7945c016f70c"
            },
            "downloads": -1,
            "filename": "never_primp-1.2.1-cp38-abi3-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "5f854a478001a1e41f86b17cbb0f99f6",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": ">=3.8",
            "size": 3165042,
            "upload_time": "2025-11-02T11:22:28",
            "upload_time_iso_8601": "2025-11-02T11:22:28.822225Z",
            "url": "https://files.pythonhosted.org/packages/a1/89/3ed1651d93bd593a55de22b8eacf6133e1bc7aeee9b383508a301530c42d/never_primp-1.2.1-cp38-abi3-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e73b00e72d0f23cfeab47e9fbf6972878820ec868fb80e4c894915cbf255ae84",
                "md5": "8f03e55cae891d8c424960baf7235e30",
                "sha256": "04c710da294412f970a3a4f7c1bebf26ab8b058ec61633adc5a70620e5c03eab"
            },
            "downloads": -1,
            "filename": "never_primp-1.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "8f03e55cae891d8c424960baf7235e30",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 164943,
            "upload_time": "2025-11-02T11:22:30",
            "upload_time_iso_8601": "2025-11-02T11:22:30.642428Z",
            "url": "https://files.pythonhosted.org/packages/e7/3b/00e72d0f23cfeab47e9fbf6972878820ec868fb80e4c894915cbf255ae84/never_primp-1.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-11-02 11:22:30",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Neverland",
    "github_project": "never_primp",
    "github_not_found": true,
    "lcname": "never-primp"
}
        
Elapsed time: 2.63330s