# Requests-Keeper
一个功能强大的HTTP会话持久化工具,支持会话保存、自动重试、请求拦截器等功能。
## 特性
- 🔄 **会话持久化** - 自动保存和恢复HTTP会话,包括cookies、headers等
- ⚡ **自动重试** - 内置智能重试机制,处理网络波动和服务器错误
- 🎯 **拦截器系统** - 支持请求和响应拦截器,方便添加认证、日志等功能
- 📝 **便捷的JSON API** - 提供get_json、post_json等便捷方法
- 🛡️ **错误处理** - 完善的错误处理和日志记录
- ⏱️ **频率限制** - 内置请求频率控制
- 🔧 **高度可配置** - 支持自定义超时、重试策略等
## 安装
```bash
pip install reqkeeper
```
## 快速开始
### 基本使用
```python
from reqkeeper import PersistentSession
# 创建持久化会话
with PersistentSession() as session:
# GET请求
response = session.get('https://httpbin.org/get')
print(response.json())
# POST请求
data = session.post_json('https://httpbin.org/post', json={'key': 'value'})
print(data)
# 会话会自动保存cookies等信息
```
### 添加拦截器
```python
from reqkeeper import PersistentSession, auth_interceptor, logging_request_interceptor
with PersistentSession() as session:
# 添加认证拦截器
session.add_request_interceptor(auth_interceptor("your_token_here"))
# 添加日志拦截器
session.add_request_interceptor(logging_request_interceptor)
# 现在所有请求都会自动添加认证头和日志
response = session.get('https://api.example.com/protected')
```
### 自定义配置
```python
from reqkeeper import PersistentSession
session = PersistentSession(
session_file='./my_session.pkl', # 自定义会话文件位置
retries=5, # 重试次数
timeout=60, # 请求超时
auto_save=True # 自动保存会话
)
```
## 内置拦截器
### 认证拦截器
```python
from reqkeeper import auth_interceptor
# Bearer token
auth = auth_interceptor("your_token_here")
session.add_request_interceptor(auth)
# API Key
api_auth = auth_interceptor("your_api_key", auth_type="ApiKey")
session.add_request_interceptor(api_auth)
```
### 日志拦截器
```python
from reqkeeper import logging_request_interceptor, logging_response_interceptor
session.add_request_interceptor(logging_request_interceptor)
session.add_response_interceptor(logging_response_interceptor)
```
### 频率限制拦截器
```python
from reqkeeper import rate_limit_interceptor
# 每秒最多2个请求
rate_limiter = rate_limit_interceptor(2.0)
session.add_request_interceptor(rate_limiter)
```
### 错误处理拦截器
```python
from reqkeeper import error_handling_interceptor
session.add_response_interceptor(error_handling_interceptor)
```
## 完整示例
```python
import logging
from reqkeeper import (
PersistentSession,
auth_interceptor,
logging_request_interceptor,
logging_response_interceptor,
error_handling_interceptor,
rate_limit_interceptor
)
# 配置日志
logging.basicConfig(level=logging.INFO)
def main():
with PersistentSession(
session_file='./api_session.pkl',
retries=3,
timeout=30,
auto_save=True
) as session:
# 添加各种拦截器
session.add_request_interceptor(logging_request_interceptor)
session.add_request_interceptor(rate_limit_interceptor(2.0)) # 每秒2个请求
session.add_response_interceptor(logging_response_interceptor)
session.add_response_interceptor(error_handling_interceptor)
# 如果需要认证
# session.add_request_interceptor(auth_interceptor("your_token"))
try:
# API调用
user_data = session.get_json('https://api.example.com/user/profile')
print(f"用户数据: {user_data}")
# 提交数据
result = session.post_json(
'https://api.example.com/data',
json={'message': 'Hello from persistent-requests!'}
)
print(f"提交结果: {result}")
print(f"会话保存在: {session.get_session_file_path()}")
except Exception as e:
print(f"请求失败: {e}")
if __name__ == "__main__":
main()
```
## API参考
### Reqkeeper
主要的会话类,提供持久化HTTP请求功能。
#### 构造函数
```python
reqkeeper(
session_file: Optional[str] = None,
retries: int = 3,
backoff_factor: float = 0.3,
timeout: int = 30,
auto_save: bool = True
)
```
- `session_file`: 会话保存文件路径,默认为系统临时目录
- `retries`: 失败重试次数
- `backoff_factor`: 重试延迟倍数
- `timeout`: 请求超时时间(秒)
- `auto_save`: 是否在每次请求后自动保存会话
#### 请求方法
- `get(url, params=None, **kwargs)` - GET请求
- `post(url, data=None, json=None, **kwargs)` - POST请求
- `put(url, data=None, json=None, **kwargs)` - PUT请求
- `patch(url, data=None, json=None, **kwargs)` - PATCH请求
- `delete(url, **kwargs)` - DELETE请求
- `head(url, **kwargs)` - HEAD请求
- `options(url, **kwargs)` - OPTIONS请求
- `request(method, url, **kwargs)` - 通用请求方法
#### JSON便捷方法
- `get_json(url, params=None, **kwargs)` - GET请求并返回JSON
- `post_json(url, data=None, json=None, **kwargs)` - POST请求并返回JSON
- `request_json(method, url, **kwargs)` - 通用请求并返回JSON
#### 拦截器管理
- `add_request_interceptor(interceptor)` - 添加请求拦截器
- `add_response_interceptor(interceptor)` - 添加响应拦截器
- `remove_request_interceptor(interceptor)` - 移除请求拦截器
- `remove_response_interceptor(interceptor)` - 移除响应拦截器
- `clear_interceptors()` - 清除所有拦截器
#### 会话管理
- `save_session()` - 手动保存会话
- `get_session_file_path()` - 获取会话文件路径
- `close()` - 关闭会话
## 许可证
MIT License
## 更新日志
### v1.0.0
- 初始版本发布
- 支持会话持久化
- 内置重试机制
- 拦截器系统
- JSON便捷方法
- 完善的错误处理
## 贡献
欢迎提交Issue和Pull Request!
## 作者
Flikify - reqkeeper@92coco.cn
项目链接: https://github.com/Flikify/reqkeeper
Raw data
{
"_id": null,
"home_page": "https://github.com/Flikify/reqkeeper",
"name": "reqkeeper",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "http, requests, session, persistent, cookies, retry, interceptor",
"author": "Flikify",
"author_email": "Flikify <reqkeeper@92coco.cn>",
"download_url": "https://files.pythonhosted.org/packages/d0/46/aac0808424ea440920ce6528c0906cc5342509b30ccc90a8156d283f8c54/reqkeeper-1.0.0.tar.gz",
"platform": null,
"description": "# Requests-Keeper\n\n\u4e00\u4e2a\u529f\u80fd\u5f3a\u5927\u7684HTTP\u4f1a\u8bdd\u6301\u4e45\u5316\u5de5\u5177\uff0c\u652f\u6301\u4f1a\u8bdd\u4fdd\u5b58\u3001\u81ea\u52a8\u91cd\u8bd5\u3001\u8bf7\u6c42\u62e6\u622a\u5668\u7b49\u529f\u80fd\u3002\n\n## \u7279\u6027\n\n- \ud83d\udd04 **\u4f1a\u8bdd\u6301\u4e45\u5316** - \u81ea\u52a8\u4fdd\u5b58\u548c\u6062\u590dHTTP\u4f1a\u8bdd\uff0c\u5305\u62eccookies\u3001headers\u7b49\n- \u26a1 **\u81ea\u52a8\u91cd\u8bd5** - \u5185\u7f6e\u667a\u80fd\u91cd\u8bd5\u673a\u5236\uff0c\u5904\u7406\u7f51\u7edc\u6ce2\u52a8\u548c\u670d\u52a1\u5668\u9519\u8bef\n- \ud83c\udfaf **\u62e6\u622a\u5668\u7cfb\u7edf** - \u652f\u6301\u8bf7\u6c42\u548c\u54cd\u5e94\u62e6\u622a\u5668\uff0c\u65b9\u4fbf\u6dfb\u52a0\u8ba4\u8bc1\u3001\u65e5\u5fd7\u7b49\u529f\u80fd\n- \ud83d\udcdd **\u4fbf\u6377\u7684JSON API** - \u63d0\u4f9bget_json\u3001post_json\u7b49\u4fbf\u6377\u65b9\u6cd5\n- \ud83d\udee1\ufe0f **\u9519\u8bef\u5904\u7406** - \u5b8c\u5584\u7684\u9519\u8bef\u5904\u7406\u548c\u65e5\u5fd7\u8bb0\u5f55\n- \u23f1\ufe0f **\u9891\u7387\u9650\u5236** - \u5185\u7f6e\u8bf7\u6c42\u9891\u7387\u63a7\u5236\n- \ud83d\udd27 **\u9ad8\u5ea6\u53ef\u914d\u7f6e** - \u652f\u6301\u81ea\u5b9a\u4e49\u8d85\u65f6\u3001\u91cd\u8bd5\u7b56\u7565\u7b49\n\n## \u5b89\u88c5\n\n```bash\npip install reqkeeper\n```\n\n## \u5feb\u901f\u5f00\u59cb\n\n### \u57fa\u672c\u4f7f\u7528\n\n```python\nfrom reqkeeper import PersistentSession\n\n# \u521b\u5efa\u6301\u4e45\u5316\u4f1a\u8bdd\nwith PersistentSession() as session:\n # GET\u8bf7\u6c42\n response = session.get('https://httpbin.org/get')\n print(response.json())\n \n # POST\u8bf7\u6c42\n data = session.post_json('https://httpbin.org/post', json={'key': 'value'})\n print(data)\n \n # \u4f1a\u8bdd\u4f1a\u81ea\u52a8\u4fdd\u5b58cookies\u7b49\u4fe1\u606f\n```\n\n### \u6dfb\u52a0\u62e6\u622a\u5668\n\n```python\nfrom reqkeeper import PersistentSession, auth_interceptor, logging_request_interceptor\n\nwith PersistentSession() as session:\n # \u6dfb\u52a0\u8ba4\u8bc1\u62e6\u622a\u5668\n session.add_request_interceptor(auth_interceptor(\"your_token_here\"))\n \n # \u6dfb\u52a0\u65e5\u5fd7\u62e6\u622a\u5668\n session.add_request_interceptor(logging_request_interceptor)\n \n # \u73b0\u5728\u6240\u6709\u8bf7\u6c42\u90fd\u4f1a\u81ea\u52a8\u6dfb\u52a0\u8ba4\u8bc1\u5934\u548c\u65e5\u5fd7\n response = session.get('https://api.example.com/protected')\n```\n\n### \u81ea\u5b9a\u4e49\u914d\u7f6e\n\n```python\nfrom reqkeeper import PersistentSession\n\nsession = PersistentSession(\n session_file='./my_session.pkl', # \u81ea\u5b9a\u4e49\u4f1a\u8bdd\u6587\u4ef6\u4f4d\u7f6e\n retries=5, # \u91cd\u8bd5\u6b21\u6570\n timeout=60, # \u8bf7\u6c42\u8d85\u65f6\n auto_save=True # \u81ea\u52a8\u4fdd\u5b58\u4f1a\u8bdd\n)\n```\n\n## \u5185\u7f6e\u62e6\u622a\u5668\n\n### \u8ba4\u8bc1\u62e6\u622a\u5668\n```python\nfrom reqkeeper import auth_interceptor\n\n# Bearer token\nauth = auth_interceptor(\"your_token_here\")\nsession.add_request_interceptor(auth)\n\n# API Key\napi_auth = auth_interceptor(\"your_api_key\", auth_type=\"ApiKey\")\nsession.add_request_interceptor(api_auth)\n```\n\n### \u65e5\u5fd7\u62e6\u622a\u5668\n```python\nfrom reqkeeper import logging_request_interceptor, logging_response_interceptor\n\nsession.add_request_interceptor(logging_request_interceptor)\nsession.add_response_interceptor(logging_response_interceptor)\n```\n\n### \u9891\u7387\u9650\u5236\u62e6\u622a\u5668\n```python\nfrom reqkeeper import rate_limit_interceptor\n\n# \u6bcf\u79d2\u6700\u591a2\u4e2a\u8bf7\u6c42\nrate_limiter = rate_limit_interceptor(2.0)\nsession.add_request_interceptor(rate_limiter)\n```\n\n### \u9519\u8bef\u5904\u7406\u62e6\u622a\u5668\n```python\nfrom reqkeeper import error_handling_interceptor\n\nsession.add_response_interceptor(error_handling_interceptor)\n```\n\n## \u5b8c\u6574\u793a\u4f8b\n\n```python\nimport logging\nfrom reqkeeper import (\n PersistentSession,\n auth_interceptor,\n logging_request_interceptor,\n logging_response_interceptor,\n error_handling_interceptor,\n rate_limit_interceptor\n)\n\n# \u914d\u7f6e\u65e5\u5fd7\nlogging.basicConfig(level=logging.INFO)\n\ndef main():\n with PersistentSession(\n session_file='./api_session.pkl',\n retries=3,\n timeout=30,\n auto_save=True\n ) as session:\n \n # \u6dfb\u52a0\u5404\u79cd\u62e6\u622a\u5668\n session.add_request_interceptor(logging_request_interceptor)\n session.add_request_interceptor(rate_limit_interceptor(2.0)) # \u6bcf\u79d22\u4e2a\u8bf7\u6c42\n \n session.add_response_interceptor(logging_response_interceptor)\n session.add_response_interceptor(error_handling_interceptor)\n \n # \u5982\u679c\u9700\u8981\u8ba4\u8bc1\n # session.add_request_interceptor(auth_interceptor(\"your_token\"))\n \n try:\n # API\u8c03\u7528\n user_data = session.get_json('https://api.example.com/user/profile')\n print(f\"\u7528\u6237\u6570\u636e: {user_data}\")\n \n # \u63d0\u4ea4\u6570\u636e\n result = session.post_json(\n 'https://api.example.com/data',\n json={'message': 'Hello from persistent-requests!'}\n )\n print(f\"\u63d0\u4ea4\u7ed3\u679c: {result}\")\n \n print(f\"\u4f1a\u8bdd\u4fdd\u5b58\u5728: {session.get_session_file_path()}\")\n \n except Exception as e:\n print(f\"\u8bf7\u6c42\u5931\u8d25: {e}\")\n\nif __name__ == \"__main__\":\n main()\n```\n\n## API\u53c2\u8003\n\n### Reqkeeper\n\n\u4e3b\u8981\u7684\u4f1a\u8bdd\u7c7b\uff0c\u63d0\u4f9b\u6301\u4e45\u5316HTTP\u8bf7\u6c42\u529f\u80fd\u3002\n\n#### \u6784\u9020\u51fd\u6570\n\n```python\nreqkeeper(\n session_file: Optional[str] = None,\n retries: int = 3,\n backoff_factor: float = 0.3,\n timeout: int = 30,\n auto_save: bool = True\n)\n```\n\n- `session_file`: \u4f1a\u8bdd\u4fdd\u5b58\u6587\u4ef6\u8def\u5f84\uff0c\u9ed8\u8ba4\u4e3a\u7cfb\u7edf\u4e34\u65f6\u76ee\u5f55\n- `retries`: \u5931\u8d25\u91cd\u8bd5\u6b21\u6570\n- `backoff_factor`: \u91cd\u8bd5\u5ef6\u8fdf\u500d\u6570\n- `timeout`: \u8bf7\u6c42\u8d85\u65f6\u65f6\u95f4\uff08\u79d2\uff09\n- `auto_save`: \u662f\u5426\u5728\u6bcf\u6b21\u8bf7\u6c42\u540e\u81ea\u52a8\u4fdd\u5b58\u4f1a\u8bdd\n\n#### \u8bf7\u6c42\u65b9\u6cd5\n\n- `get(url, params=None, **kwargs)` - GET\u8bf7\u6c42\n- `post(url, data=None, json=None, **kwargs)` - POST\u8bf7\u6c42\n- `put(url, data=None, json=None, **kwargs)` - PUT\u8bf7\u6c42\n- `patch(url, data=None, json=None, **kwargs)` - PATCH\u8bf7\u6c42\n- `delete(url, **kwargs)` - DELETE\u8bf7\u6c42\n- `head(url, **kwargs)` - HEAD\u8bf7\u6c42\n- `options(url, **kwargs)` - OPTIONS\u8bf7\u6c42\n- `request(method, url, **kwargs)` - \u901a\u7528\u8bf7\u6c42\u65b9\u6cd5\n\n#### JSON\u4fbf\u6377\u65b9\u6cd5\n\n- `get_json(url, params=None, **kwargs)` - GET\u8bf7\u6c42\u5e76\u8fd4\u56deJSON\n- `post_json(url, data=None, json=None, **kwargs)` - POST\u8bf7\u6c42\u5e76\u8fd4\u56deJSON\n- `request_json(method, url, **kwargs)` - \u901a\u7528\u8bf7\u6c42\u5e76\u8fd4\u56deJSON\n\n#### \u62e6\u622a\u5668\u7ba1\u7406\n\n- `add_request_interceptor(interceptor)` - \u6dfb\u52a0\u8bf7\u6c42\u62e6\u622a\u5668\n- `add_response_interceptor(interceptor)` - \u6dfb\u52a0\u54cd\u5e94\u62e6\u622a\u5668\n- `remove_request_interceptor(interceptor)` - \u79fb\u9664\u8bf7\u6c42\u62e6\u622a\u5668\n- `remove_response_interceptor(interceptor)` - \u79fb\u9664\u54cd\u5e94\u62e6\u622a\u5668\n- `clear_interceptors()` - \u6e05\u9664\u6240\u6709\u62e6\u622a\u5668\n\n#### \u4f1a\u8bdd\u7ba1\u7406\n\n- `save_session()` - \u624b\u52a8\u4fdd\u5b58\u4f1a\u8bdd\n- `get_session_file_path()` - \u83b7\u53d6\u4f1a\u8bdd\u6587\u4ef6\u8def\u5f84\n- `close()` - \u5173\u95ed\u4f1a\u8bdd\n\n## \u8bb8\u53ef\u8bc1\n\nMIT License\n\n## \u66f4\u65b0\u65e5\u5fd7\n\n### v1.0.0\n\n- \u521d\u59cb\u7248\u672c\u53d1\u5e03\n- \u652f\u6301\u4f1a\u8bdd\u6301\u4e45\u5316\n- \u5185\u7f6e\u91cd\u8bd5\u673a\u5236\n- \u62e6\u622a\u5668\u7cfb\u7edf\n- JSON\u4fbf\u6377\u65b9\u6cd5\n- \u5b8c\u5584\u7684\u9519\u8bef\u5904\u7406\n\n## \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4Issue\u548cPull Request\uff01\n\n## \u4f5c\u8005\n\nFlikify - reqkeeper@92coco.cn\n\n\u9879\u76ee\u94fe\u63a5: https://github.com/Flikify/reqkeeper\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "\u4e00\u4e2a\u529f\u80fd\u5f3a\u5927\u7684HTTP\u4f1a\u8bdd\u6301\u4e45\u5316\u5de5\u5177",
"version": "1.0.0",
"project_urls": {
"Bug Tracker": "https://github.com/Flikify/reqkeeper/issues",
"Documentation": "https://github.com/Flikify/reqkeeper#readme",
"Homepage": "https://github.com/Flikify/reqkeeper",
"Source Code": "https://github.com/Flikify/reqkeeper"
},
"split_keywords": [
"http",
" requests",
" session",
" persistent",
" cookies",
" retry",
" interceptor"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "99aedd4e117f1bbb7ae63a7f972a20b29448ca1ca2b9d9d45eb20f7e252e6eb8",
"md5": "87ae5526555c85087fea1b15677b4d70",
"sha256": "1ef6a3ca6a34c4a9bd8ea0a2efd9f234ef75e9198d0be88cb73044b757f13b4b"
},
"downloads": -1,
"filename": "reqkeeper-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "87ae5526555c85087fea1b15677b4d70",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 9897,
"upload_time": "2025-08-12T03:13:01",
"upload_time_iso_8601": "2025-08-12T03:13:01.235683Z",
"url": "https://files.pythonhosted.org/packages/99/ae/dd4e117f1bbb7ae63a7f972a20b29448ca1ca2b9d9d45eb20f7e252e6eb8/reqkeeper-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "d046aac0808424ea440920ce6528c0906cc5342509b30ccc90a8156d283f8c54",
"md5": "4d091b351fb1f52b7728c4deeefa3bb2",
"sha256": "6d095b842daab1ce726d58d92cfbe9b16231943bd279945beb72095bb5850d1b"
},
"downloads": -1,
"filename": "reqkeeper-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "4d091b351fb1f52b7728c4deeefa3bb2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 12312,
"upload_time": "2025-08-12T03:13:02",
"upload_time_iso_8601": "2025-08-12T03:13:02.905996Z",
"url": "https://files.pythonhosted.org/packages/d0/46/aac0808424ea440920ce6528c0906cc5342509b30ccc90a8156d283f8c54/reqkeeper-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-12 03:13:02",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Flikify",
"github_project": "reqkeeper",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "requests",
"specs": [
[
">=",
"2.25.0"
]
]
},
{
"name": "tenacity",
"specs": [
[
">=",
"8.0.0"
]
]
},
{
"name": "urllib3",
"specs": [
[
">=",
"1.26.0"
]
]
}
],
"lcname": "reqkeeper"
}