# Python 123 网盘客户端
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-123-client)
![PyPI - Version](https://img.shields.io/pypi/v/python-123-client)
![PyPI - Downloads](https://img.shields.io/pypi/dm/python-123-client)
![PyPI - Format](https://img.shields.io/pypi/format/python-123-client)
![PyPI - Status](https://img.shields.io/pypi/status/python-123-client)
## 安装
你可以从 [pypi](https://pypi.org/project/python-123-client/) 安装最新版本
```console
pip install -U python-123-client
```
## 入门介绍
### 1. 导入模块和创建实例
导入模块
```python
from p123 import P123Client
```
创建客户端对象,需要传入 JWT <kbd>token</kbd>
```python
token = "..."
client = P123Client(token=token)
```
你也可以用账户和密码登录
```python
passport = "..." # 手机号或者邮箱
password = "..." # 密码
client = P123Client(passport, password)
```
### 2. 接口调用
所有需要直接或间接执行 HTTP 请求的接口,都有同步和异步的调用方式,且默认是采用 POST 发送 JSON 请求数据
```python
# 同步调用
client.method(payload)
client.method(payload, async_=False)
# 异步调用
await client.method(payload, async_=True)
```
从根本上讲,除了几个 `staticmethod`,它们都会调用 `P123Client.request`
```python
url = "https://www.123pan.com/api/someapi"
response = client.request(url=url, json={...})
```
当你需要构建自己的扩展模块,以增加一些新的 123 web 接口时,就需要用到此方法了
```python
from collections.abc import Coroutine
from typing import overload, Any, Literal
from p123 import P123Client
class MyCustom123Client(P123Client):
@overload
def foo(
self,
payload: dict,
/,
async_: Literal[False] = False,
**request_kwargs,
) -> dict:
...
@overload
def foo(
self,
payload: dict,
/,
async_: Literal[True],
**request_kwargs,
) -> Coroutine[Any, Any, dict]:
...
def foo(
self,
payload: dict,
/,
async_: bool = False,
**request_kwargs,
) -> dict | Coroutine[Any, Any, dict]:
api = "https://www.123pan.com/api/foo"
return self.request(
api,
method="GET",
params=payload,
async_=async_,
**request_kwargs,
)
@overload
def bar(
self,
payload: dict,
/,
async_: Literal[False] = False,
**request_kwargs,
) -> dict:
...
@overload
def bar(
self,
payload: dict,
/,
async_: Literal[True],
**request_kwargs,
) -> Coroutine[Any, Any, dict]:
...
def bar(
self,
payload: dict,
/,
async_: bool = False,
**request_kwargs,
) -> dict | Coroutine[Any, Any, dict]:
api = "https://www.123pan.com/api/bar"
return self.request(
api,
method="POST",
json=payload,
async_=async_,
**request_kwargs,
)
```
### 3. 检查响应
接口被调用后,如果返回的是 dict 类型的数据(说明原本是 JSON),则可以用 `p123.check_response` 执行检查。首先会查看其中名为 "code" 的键的对应值,如果为 0 或 200 或者不存在,则原样返回被检查的数据;否则,抛出一个 `p123.P123OSError` 的实例。
```python
from p123 import check_response
# 检查同步调用
data = check_response(client.method(payload))
# 检查异步调用
data = check_response(await client.method(payload, async_=True))
```
### 4. 辅助工具
一些简单的封装工具可能是必要的,特别是那种实现起来代码量比较少,可以封装成单个函数的。我把平常使用过程中,积累的一些经验具体化为一组工具函数。这些工具函数分别有着不同的功能,如果组合起来使用,或许能解决很多问题。
```python
from p123 import tool
```
#### 1. 创建自定义 uri
```python
from p123 import P123Client
from p123.tool import make_uri
# TODO: 改成你自己的账户和密码
client = P123Client(passport="手机号或邮箱", password="登录密码")
# TODO: 请改成你要处理的文件 id
file_id = 15688945
print(make_uri(client, file_id))
```
#### 2. 由自定义 uri 转存文件到你的网盘
```python
from p123 import P123Client
from p123.tool import upload_uri
# TODO: 改成你自己的账户和密码
client = P123Client(passport="手机号或邮箱", password="登录密码")
uri = "123://torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd"
print(upload_uri(client, uri, duplicate=1))
```
#### 3. 由自定义 uri 获取下载直链
```python
from p123 import P123Client
from p123.tool import get_downurl
# TODO: 改成你自己的账户和密码
client = P123Client(passport="手机号或邮箱", password="登录密码")
# 带 s3_key_flag
print(get_downurl(client, "123://torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd?1812602326-0"))
# 不带 s3_key_flag(会转存)
print(get_downurl(client, "123://torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd"))
```
#### 4. 直链服务
需要先安装 [fastapi](https://pypi.org/project/fastapi/)
```console
pip install 'fastapi[uvicorn]'
```
然后启动如下服务,就可以访问以获取直链了
**带 s3_key_flag**
http://localhost:8123/torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd?1812602326-0
**不带 s3_key_flag(会转存)**
http://localhost:8123/torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd
```python
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, RedirectResponse
from p123 import P123Client
from p123.tool import get_downurl
# TODO: 改成你自己的账户和密码
client = P123Client(passport="手机号或邮箱", password="登录密码")
app = FastAPI(debug=True)
@app.get("/{uri:path}")
@app.head("/{uri:path}")
async def index(request: Request, uri: str):
try:
payload = int(uri)
except ValueError:
if uri.count("|") < 2:
return JSONResponse({"state": False, "message": f"bad uri: {uri!r}"}, 500)
payload = uri
if s3_key_flag := request.url.query:
payload += "?" + s3_key_flag
url = await get_downurl(client, payload, quoted=False, async_=True)
return RedirectResponse(url, 302)
if __name__ == "__main__":
from uvicorn import run
run(app, host="0.0.0.0", port=8123)
```
#### 5. 遍历文件列表
**遍历网盘中的文件列表**
```python
from p123 import P123Client
from p123.tool import iterdir
# TODO: 改成你自己的账户和密码
client = P123Client(passport="手机号或邮箱", password="登录密码")
for info in iterdir(client, parent_id=0, max_depth=-1, predicate=lambda a: not a["is_dir"]):
print(info)
```
**遍历分享中的文件列表(无需登录)**
```python
from p123.tool import share_iterdir
# TODO: 分享码
share_key = "g0n0Vv-2sbI"
# TODO: 密码
share_pwd = ""
for info in share_iterdir(share_key, share_pwd, parent_id=0, max_depth=-1, predicate=lambda a: not a["is_dir"]):
print(info)
```
Raw data
{
"_id": null,
"home_page": "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-123-client",
"name": "python-123-client",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.12",
"maintainer_email": null,
"keywords": "123, webdisk, client",
"author": "ChenyangGao",
"author_email": "wosiwujm@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/b4/ea/029445bbac5d4692d51db5843d4d3d2791e8feb7ab605f2e22f65a222511/python_123_client-0.0.4.0.1.tar.gz",
"platform": null,
"description": "# Python 123 \u7f51\u76d8\u5ba2\u6237\u7aef\n\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-123-client)\n![PyPI - Version](https://img.shields.io/pypi/v/python-123-client)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/python-123-client)\n![PyPI - Format](https://img.shields.io/pypi/format/python-123-client)\n![PyPI - Status](https://img.shields.io/pypi/status/python-123-client)\n\n## \u5b89\u88c5\n\n\u4f60\u53ef\u4ee5\u4ece [pypi](https://pypi.org/project/python-123-client/) \u5b89\u88c5\u6700\u65b0\u7248\u672c\n\n```console\npip install -U python-123-client\n```\n\n## \u5165\u95e8\u4ecb\u7ecd\n\n### 1. \u5bfc\u5165\u6a21\u5757\u548c\u521b\u5efa\u5b9e\u4f8b\n\n\u5bfc\u5165\u6a21\u5757\n\n```python\nfrom p123 import P123Client\n```\n\n\u521b\u5efa\u5ba2\u6237\u7aef\u5bf9\u8c61\uff0c\u9700\u8981\u4f20\u5165 JWT <kbd>token</kbd>\n\n```python\ntoken = \"...\"\nclient = P123Client(token=token)\n```\n\n\u4f60\u4e5f\u53ef\u4ee5\u7528\u8d26\u6237\u548c\u5bc6\u7801\u767b\u5f55\n\n```python\npassport = \"...\" # \u624b\u673a\u53f7\u6216\u8005\u90ae\u7bb1\npassword = \"...\" # \u5bc6\u7801\nclient = P123Client(passport, password)\n```\n\n### 2. \u63a5\u53e3\u8c03\u7528\n\n\u6240\u6709\u9700\u8981\u76f4\u63a5\u6216\u95f4\u63a5\u6267\u884c HTTP \u8bf7\u6c42\u7684\u63a5\u53e3\uff0c\u90fd\u6709\u540c\u6b65\u548c\u5f02\u6b65\u7684\u8c03\u7528\u65b9\u5f0f\uff0c\u4e14\u9ed8\u8ba4\u662f\u91c7\u7528 POST \u53d1\u9001 JSON \u8bf7\u6c42\u6570\u636e\n\n```python\n# \u540c\u6b65\u8c03\u7528\nclient.method(payload)\nclient.method(payload, async_=False)\n\n# \u5f02\u6b65\u8c03\u7528\nawait client.method(payload, async_=True)\n```\n\n\u4ece\u6839\u672c\u4e0a\u8bb2\uff0c\u9664\u4e86\u51e0\u4e2a `staticmethod`\uff0c\u5b83\u4eec\u90fd\u4f1a\u8c03\u7528 `P123Client.request`\n\n```python\nurl = \"https://www.123pan.com/api/someapi\"\nresponse = client.request(url=url, json={...})\n```\n\n\u5f53\u4f60\u9700\u8981\u6784\u5efa\u81ea\u5df1\u7684\u6269\u5c55\u6a21\u5757\uff0c\u4ee5\u589e\u52a0\u4e00\u4e9b\u65b0\u7684 123 web \u63a5\u53e3\u65f6\uff0c\u5c31\u9700\u8981\u7528\u5230\u6b64\u65b9\u6cd5\u4e86\n\n```python\nfrom collections.abc import Coroutine\nfrom typing import overload, Any, Literal\n\nfrom p123 import P123Client\n\nclass MyCustom123Client(P123Client):\n\n @overload\n def foo(\n self, \n payload: dict, \n /, \n async_: Literal[False] = False, \n **request_kwargs, \n ) -> dict:\n ...\n @overload\n def foo(\n self, \n payload: dict, \n /, \n async_: Literal[True], \n **request_kwargs, \n ) -> Coroutine[Any, Any, dict]:\n ...\n def foo(\n self, \n payload: dict, \n /, \n async_: bool = False, \n **request_kwargs, \n ) -> dict | Coroutine[Any, Any, dict]:\n api = \"https://www.123pan.com/api/foo\"\n return self.request(\n api, \n method=\"GET\", \n params=payload, \n async_=async_, \n **request_kwargs, \n )\n\n @overload\n def bar(\n self, \n payload: dict, \n /, \n async_: Literal[False] = False, \n **request_kwargs, \n ) -> dict:\n ...\n @overload\n def bar(\n self, \n payload: dict, \n /, \n async_: Literal[True], \n **request_kwargs, \n ) -> Coroutine[Any, Any, dict]:\n ...\n def bar(\n self, \n payload: dict, \n /, \n async_: bool = False, \n **request_kwargs, \n ) -> dict | Coroutine[Any, Any, dict]:\n api = \"https://www.123pan.com/api/bar\"\n return self.request(\n api, \n method=\"POST\", \n json=payload, \n async_=async_, \n **request_kwargs, \n )\n```\n\n### 3. \u68c0\u67e5\u54cd\u5e94\n\n\u63a5\u53e3\u88ab\u8c03\u7528\u540e\uff0c\u5982\u679c\u8fd4\u56de\u7684\u662f dict \u7c7b\u578b\u7684\u6570\u636e\uff08\u8bf4\u660e\u539f\u672c\u662f JSON\uff09\uff0c\u5219\u53ef\u4ee5\u7528 `p123.check_response` \u6267\u884c\u68c0\u67e5\u3002\u9996\u5148\u4f1a\u67e5\u770b\u5176\u4e2d\u540d\u4e3a \"code\" \u7684\u952e\u7684\u5bf9\u5e94\u503c\uff0c\u5982\u679c\u4e3a 0 \u6216 200 \u6216\u8005\u4e0d\u5b58\u5728\uff0c\u5219\u539f\u6837\u8fd4\u56de\u88ab\u68c0\u67e5\u7684\u6570\u636e\uff1b\u5426\u5219\uff0c\u629b\u51fa\u4e00\u4e2a `p123.P123OSError` \u7684\u5b9e\u4f8b\u3002\n\n```python\nfrom p123 import check_response\n\n# \u68c0\u67e5\u540c\u6b65\u8c03\u7528\ndata = check_response(client.method(payload))\n# \u68c0\u67e5\u5f02\u6b65\u8c03\u7528\ndata = check_response(await client.method(payload, async_=True))\n```\n\n### 4. \u8f85\u52a9\u5de5\u5177\n\n\u4e00\u4e9b\u7b80\u5355\u7684\u5c01\u88c5\u5de5\u5177\u53ef\u80fd\u662f\u5fc5\u8981\u7684\uff0c\u7279\u522b\u662f\u90a3\u79cd\u5b9e\u73b0\u8d77\u6765\u4ee3\u7801\u91cf\u6bd4\u8f83\u5c11\uff0c\u53ef\u4ee5\u5c01\u88c5\u6210\u5355\u4e2a\u51fd\u6570\u7684\u3002\u6211\u628a\u5e73\u5e38\u4f7f\u7528\u8fc7\u7a0b\u4e2d\uff0c\u79ef\u7d2f\u7684\u4e00\u4e9b\u7ecf\u9a8c\u5177\u4f53\u5316\u4e3a\u4e00\u7ec4\u5de5\u5177\u51fd\u6570\u3002\u8fd9\u4e9b\u5de5\u5177\u51fd\u6570\u5206\u522b\u6709\u7740\u4e0d\u540c\u7684\u529f\u80fd\uff0c\u5982\u679c\u7ec4\u5408\u8d77\u6765\u4f7f\u7528\uff0c\u6216\u8bb8\u80fd\u89e3\u51b3\u5f88\u591a\u95ee\u9898\u3002\n\n```python\nfrom p123 import tool\n```\n\n#### 1. \u521b\u5efa\u81ea\u5b9a\u4e49 uri\n\n```python\nfrom p123 import P123Client\nfrom p123.tool import make_uri\n\n# TODO: \u6539\u6210\u4f60\u81ea\u5df1\u7684\u8d26\u6237\u548c\u5bc6\u7801\nclient = P123Client(passport=\"\u624b\u673a\u53f7\u6216\u90ae\u7bb1\", password=\"\u767b\u5f55\u5bc6\u7801\")\n\n# TODO: \u8bf7\u6539\u6210\u4f60\u8981\u5904\u7406\u7684\u6587\u4ef6 id\nfile_id = 15688945\nprint(make_uri(client, file_id))\n```\n\n#### 2. \u7531\u81ea\u5b9a\u4e49 uri \u8f6c\u5b58\u6587\u4ef6\u5230\u4f60\u7684\u7f51\u76d8\n\n```python\nfrom p123 import P123Client\nfrom p123.tool import upload_uri\n\n# TODO: \u6539\u6210\u4f60\u81ea\u5df1\u7684\u8d26\u6237\u548c\u5bc6\u7801\nclient = P123Client(passport=\"\u624b\u673a\u53f7\u6216\u90ae\u7bb1\", password=\"\u767b\u5f55\u5bc6\u7801\")\n\nuri = \"123://torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd\"\nprint(upload_uri(client, uri, duplicate=1))\n```\n\n#### 3. \u7531\u81ea\u5b9a\u4e49 uri \u83b7\u53d6\u4e0b\u8f7d\u76f4\u94fe\n\n```python\nfrom p123 import P123Client\nfrom p123.tool import get_downurl\n\n# TODO: \u6539\u6210\u4f60\u81ea\u5df1\u7684\u8d26\u6237\u548c\u5bc6\u7801\nclient = P123Client(passport=\"\u624b\u673a\u53f7\u6216\u90ae\u7bb1\", password=\"\u767b\u5f55\u5bc6\u7801\")\n\n# \u5e26 s3_key_flag\nprint(get_downurl(client, \"123://torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd?1812602326-0\"))\n# \u4e0d\u5e26 s3_key_flag\uff08\u4f1a\u8f6c\u5b58\uff09\nprint(get_downurl(client, \"123://torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd\"))\n```\n\n#### 4. \u76f4\u94fe\u670d\u52a1\n\n\u9700\u8981\u5148\u5b89\u88c5 [fastapi](https://pypi.org/project/fastapi/)\n\n```console\npip install 'fastapi[uvicorn]'\n```\n\n\u7136\u540e\u542f\u52a8\u5982\u4e0b\u670d\u52a1\uff0c\u5c31\u53ef\u4ee5\u8bbf\u95ee\u4ee5\u83b7\u53d6\u76f4\u94fe\u4e86\n\n**\u5e26 s3_key_flag**\n\nhttp://localhost:8123/torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd?1812602326-0\n\n**\u4e0d\u5e26 s3_key_flag\uff08\u4f1a\u8f6c\u5b58\uff09**\n\nhttp://localhost:8123/torrentgalaxy.db|1976025090|582aa8bfb0ad8e6f512d9661f6243bdd\n\n```python\nfrom fastapi import FastAPI, Request\nfrom fastapi.responses import JSONResponse, RedirectResponse\nfrom p123 import P123Client\nfrom p123.tool import get_downurl\n\n# TODO: \u6539\u6210\u4f60\u81ea\u5df1\u7684\u8d26\u6237\u548c\u5bc6\u7801\nclient = P123Client(passport=\"\u624b\u673a\u53f7\u6216\u90ae\u7bb1\", password=\"\u767b\u5f55\u5bc6\u7801\")\n\napp = FastAPI(debug=True)\n\n@app.get(\"/{uri:path}\")\n@app.head(\"/{uri:path}\")\nasync def index(request: Request, uri: str):\n try:\n payload = int(uri)\n except ValueError:\n if uri.count(\"|\") < 2:\n return JSONResponse({\"state\": False, \"message\": f\"bad uri: {uri!r}\"}, 500)\n payload = uri\n if s3_key_flag := request.url.query:\n payload += \"?\" + s3_key_flag\n url = await get_downurl(client, payload, quoted=False, async_=True)\n return RedirectResponse(url, 302)\n\nif __name__ == \"__main__\":\n from uvicorn import run\n\n run(app, host=\"0.0.0.0\", port=8123)\n```\n\n#### 5. \u904d\u5386\u6587\u4ef6\u5217\u8868\n\n**\u904d\u5386\u7f51\u76d8\u4e2d\u7684\u6587\u4ef6\u5217\u8868**\n\n```python\nfrom p123 import P123Client\nfrom p123.tool import iterdir\n\n# TODO: \u6539\u6210\u4f60\u81ea\u5df1\u7684\u8d26\u6237\u548c\u5bc6\u7801\nclient = P123Client(passport=\"\u624b\u673a\u53f7\u6216\u90ae\u7bb1\", password=\"\u767b\u5f55\u5bc6\u7801\")\n\nfor info in iterdir(client, parent_id=0, max_depth=-1, predicate=lambda a: not a[\"is_dir\"]):\n print(info)\n```\n\n**\u904d\u5386\u5206\u4eab\u4e2d\u7684\u6587\u4ef6\u5217\u8868\uff08\u65e0\u9700\u767b\u5f55\uff09**\n\n```python\nfrom p123.tool import share_iterdir\n\n# TODO: \u5206\u4eab\u7801\nshare_key = \"g0n0Vv-2sbI\"\n# TODO: \u5bc6\u7801\nshare_pwd = \"\"\n\nfor info in share_iterdir(share_key, share_pwd, parent_id=0, max_depth=-1, predicate=lambda a: not a[\"is_dir\"]):\n print(info)\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python wrapper for 123 webdisk.",
"version": "0.0.4.0.1",
"project_urls": {
"Homepage": "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-123-client",
"Repository": "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-123-client"
},
"split_keywords": [
"123",
" webdisk",
" client"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "6f9a27a2ced944b797e411201b5ae9a430f64d41180622c3c1f1833a7472888e",
"md5": "11c098f45ee9c78db0080d9077afcd7c",
"sha256": "b6d2eb169208c0e35b3167df0b8891f0b6c95897c47b137173c4a06efbdcf7ce"
},
"downloads": -1,
"filename": "python_123_client-0.0.4.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "11c098f45ee9c78db0080d9077afcd7c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.12",
"size": 21628,
"upload_time": "2025-01-20T06:42:50",
"upload_time_iso_8601": "2025-01-20T06:42:50.172695Z",
"url": "https://files.pythonhosted.org/packages/6f/9a/27a2ced944b797e411201b5ae9a430f64d41180622c3c1f1833a7472888e/python_123_client-0.0.4.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "b4ea029445bbac5d4692d51db5843d4d3d2791e8feb7ab605f2e22f65a222511",
"md5": "68e19729579422301bcadecf595e58fe",
"sha256": "167e0e58b5c0b5fd1194eb80339b2535346706351c50a9f5e19c6f3b727722b3"
},
"downloads": -1,
"filename": "python_123_client-0.0.4.0.1.tar.gz",
"has_sig": false,
"md5_digest": "68e19729579422301bcadecf595e58fe",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.12",
"size": 19277,
"upload_time": "2025-01-20T06:42:52",
"upload_time_iso_8601": "2025-01-20T06:42:52.723920Z",
"url": "https://files.pythonhosted.org/packages/b4/ea/029445bbac5d4692d51db5843d4d3d2791e8feb7ab605f2e22f65a222511/python_123_client-0.0.4.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-20 06:42:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ChenyangGao",
"github_project": "web-mount-packs",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "python-123-client"
}