p123client


Namep123client JSON
Version 0.0.8.8 PyPI version JSON
download
home_pagehttps://github.com/ChenyangGao/p123client
SummaryPython 123 webdisk client.
upload_time2025-07-25 18:18:31
maintainerNone
docs_urlNone
authorChenyangGao
requires_python<4.0,>=3.12
licenseMIT
keywords 123 webdisk client
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Python 123 网盘客户端

![PyPI - Python Version](https://img.shields.io/pypi/pyversions/p123client)
![PyPI - Version](https://img.shields.io/pypi/v/p123client)
![PyPI - Downloads](https://img.shields.io/pypi/dm/p123client)
![PyPI - Format](https://img.shields.io/pypi/format/p123client)
![PyPI - Status](https://img.shields.io/pypi/status/p123client)

## 0. 安装

你可以从 [pypi](https://pypi.org/project/p123client/) 安装最新版本

```console
pip install -U p123client
```

## 1. 导入模块和创建实例

首先导入模块

```python
from p123client import P123Client
```

### 1. 用 token 创建实例

创建客户端对象,需要传入 JWT <kbd>token</kbd>,也就是 `access_token`

```python
# TODO: 访问令牌
token = "..."

client = P123Client(token=token)
```

或者直接写作

```python
client = P123Client(token)
```

不过我更推荐把 <kbd>token</kbd> 写入一个文件中,例如在 `~/123-token.txt`

```python
from pathlib import Path

client = P123Client(token=Path("~/123-token.txt").expanduser())
```

或者直接写作

```python
client = P123Client(Path("~/123-token.txt").expanduser())
```

### 2. 账号和密码登录

```python
# TODO: 手机号或者邮箱
passport = "..." 
# TODO: 密码
password = "..."

client = P123Client(passport=passport, password=passport)
```

或者直接写作

```python
client = P123Client(passport, passport)
```

### 3. client_id 和 client_secret 登录

需要先申请成为开发者

https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/hpengmyg32blkbg8

```python
# TODO: 应用标识,创建应用时分配的 appId
client_id = "..." 
# TODO: 应用密钥,创建应用时分配的 secretId
client_secret = "..."

client = P123Client(client_id=client_id, client_secret=client_secret)
```

或者直接写作

```python
client = P123Client(client_id, client_secret)
```

### 4. refresh_token 登录

```python
# TODO: 刷新令牌
refresh_token = "..."

client = P123Client(refresh_token=refresh_token)
```

或者直接写作

```python
client = P123Client(refresh_token)
```

**注意**:使用 refresh_token(或者说 oauth 登录),只允许访问 open 接口

### 5. oauth 登录

需要先去开发者后台设置一下回调链接,审核通过后才可用

```python
# TODO: 应用标识,创建应用时分配的 appId
client_id = "..." 
# TODO: 应用密钥,创建应用时分配的 secretId
client_secret = "..."
# TODO: 回调链接
redirect_uri = "..."
# TODO: 访问令牌
token = "..."

resp = P123Client.login_with_oauth(
    client_id=client_id, 
    client_secret=client_secret, 
    redirect_uri=redirect_uri, 
    token=token, 
)
client = P123Client(
    client_id=client_id, 
    client_secret=client_secret, 
    token=resp["access_token"], 
    refresh_token=resp["refresh_token"], 
)
```

### 6. 扫码登录

当你什么都不传时,就会要求你扫码登录

```python
client = P123Client()
```

### 7. 用 token 来扫码新的 token

你可以用一个 token 去扫码获得另一个 token(仅当不是 oauth 登录时)

```python
client_new = client.login_another()
```

另外你也可以用 oauth 登录,虽然仅能访问 open 接口,但是 QPS 上放得更宽

下面我用 clouddrive 在 123 网盘上用 oauth 登录举例说明第三方挂载应用登录:

https://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/kf05anzt1r0qnudd

```python
import requests
from urllib.parse import parse_qsl, urlsplit

resp = client.login_oauth_authorize({
    "client_id": "7c278c60da9e43848c45ff8e6fa9da0a", 
    "redirect_uri": "https://redirect123pan.zhenyunpan.com/redirect_pan123", 
    "accessToken": client.token, 
    "state": "http://localhost:19798", 
})
with requests.get(resp["url"], allow_redirects=False, stream=True) as response:
    resp = dict(parse_qsl(urlsplit(response.headers["location"]).query))
client_new = P123Client(token=resp["access_token"], refresh_token=resp["refresh_token"])
```

### 8. 关于 token 的结构

<kbd>token</kbd> 中包含了一些信息,以 "." 进行分割,可以拆成 3 个部分:

- JWT 算法(经过 base64 加密)
- 用户信息(经过 base64 加密)
- 签名字符串

```python
from base64 import urlsafe_b64decode
from json import loads

token = client.token

method, user_info, sign = token.split(".", 2)
print("JWT 算法:", loads(urlsafe_b64decode(method)))
print("用户信息:", loads(urlsafe_b64decode(user_info+"==")))
print("签名:", sign)
```

## 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 p123client 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),则可以用 `p123client.check_response` 执行检查。首先会查看其中名为 "code" 的键的对应值,如果为 0 或 200 或者不存在,则原样返回被检查的数据;否则,抛出一个 `p123client.P123OSError` 的实例。

```python
from p123client import check_response

# 检查同步调用
data = check_response(client.method(payload))
# 检查异步调用
data = check_response(await client.method(payload, async_=True))
```

## 4. 辅助工具

一些简单的封装工具可能是必要的,特别是那种实现起来代码量比较少,可以封装成单个函数的。我把平常使用过程中,积累的一些经验具体化为一组工具函数。这些工具函数分别有着不同的功能,如果组合起来使用,或许能解决很多问题。

```python
from p123client import tool
```

## 5. 学习案例

### 1. 创建自定义 uri

```python
from p123client import P123Client
from p123client.tool import make_uri

# TODO: 改成你自己的账户和密码
client = P123Client(passport="手机号或邮箱", password="登录密码")

# TODO: 请改成你要处理的文件 id
file_id = 15688945
print(make_uri(client, file_id))
```

### 2. 由自定义 uri 转存文件到你的网盘

```python
from p123client import P123Client
from p123client.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 p123client import P123Client
from p123client.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. 直链服务

需要先安装 [blacksheep](https://www.neoteroi.dev/blacksheep/)

```console
pip install 'blacksheep[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 blacksheep import json, redirect, Application, Request
from p123client import P123Client
from p123client.tool import get_downurl

# TODO: 改成你自己的账户和密码
client = P123Client(passport="", password="")

app = Application(show_error_details=__debug__)

@app.router.route("/{path:uri}", methods=["GET", "HEAD"])
async def index(request: Request, uri: str):
    try:
        payload = int(uri)
    except ValueError:
        if uri.count("|") < 2:
            return json({"state": False, "message": f"bad uri: {uri!r}"}, 500)
        payload = uri
        if s3_key_flag := request.url.query:
            payload += "?" + s3_key_flag.decode("ascii")
    url = await get_downurl(client, payload, quoted=False, async_=True)
    return redirect(url)

if __name__ == "__main__":
    from uvicorn import run

    run(app, host="0.0.0.0", port=8123)
```

### 5. 遍历文件列表

导出的文件信息中,有个 `"uri"`,表示文件的自定义链接,前面以 `123://` 开头,你可以替换成 302 服务的地址,例如 `http://localhost:8123/`

#### 1. 遍历网盘中的文件列表

```python
from p123client import P123Client
from p123client.tool import iterdir

# TODO: 改成你自己的账户和密码
client = P123Client(passport="手机号或邮箱", password="登录密码")

for info in iterdir(client, parent_id=0, max_depth=-1):
    print(info)
```

#### 2. 遍历分享中的文件列表,不含目录

```python
from p123client.tool import share_iterdir

# NOTE: 无需登录
for info in share_iterdir(
    "https://www.123684.com/s/oec7Vv-CIYWh?提取码:ZY4K", 
    max_depth=-1, 
    predicate=lambda a: not a["is_dir"], 
):
    print(info)
```

#### 3. 导出分享中的文件列表到本地 .json 文件

```python
from orjson import dumps
from p123client.tool import share_iterdir

def export_share_files_json(
    link: str, 
    path: str = "", 
    cooldown: float = 0, 
):
    """把分享链接中的文件列表导出到 json 文件

    :param link: 分享链接,可以包含提取码
    :param path: 保存的路径,如果不提供则自动确定
    :param cooldown: 两次调用之间,冷却的时间(用两次调用开始时的时间差,而不是一次完成到下一次开始的时间差)
    """
    print("< 将拉取:", link)
    ls: list[dict] = []
    for i, a in enumerate(share_iterdir(link, max_depth=-1, cooldown=cooldown), 1):
        ls.append(a)
        print(i, a)
    if ls:
        info = ls[0]
        if not path:
            suffix = f"@{info['ShareKey']},{info['SharePwd']}.json"
            path = f"{info['name'][:255-len(suffix)]}{suffix}"
        open(path, "wb").write(dumps(ls))
        print()
        print("> 已拉取:", link)
        print("> 已保存:", path)

export_share_files_json("https://www.123684.com/s/oec7Vv-CIYWh?提取码:ZY4K")
```

### 6. 最新的操作记录

在网盘中,你可以按更新时间逆序查询,即可得到最新上传的文件列表

```python
client.fs_list_new({
    "orderBy": "update_time", 
    "orderDirection": "desc", 
    "SearchData": ".", 
})
```

更一般的,你可以在[同步空间](https://www.123pan.com/SynchronousSpace/main)中执行文件操作。

而在拉取文件列表时,需要指定

```python
client.fs_list_new({
    "operateType": "SyncSpacePage", 
    "event": "syncFileList", 
    "RequestSource": 1, 
})
```

同步空间中的增删改操作都有[操作记录](https://www.123pan.com/SynchronousSpace/record),你可以用接口

```python
client.fs_sync_log()
```

## 其它资源

- 如果你需要更详细的文档,特别是关于各种接口的信息,可以阅读

    [https://p123client.readthedocs.io/en/latest/](https://p123client.readthedocs.io/en/latest/)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ChenyangGao/p123client",
    "name": "p123client",
    "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/e4/85/3e0af42d5746361f2153ba3681887d18b17fed8c70eadf90c1d2d52834cc/p123client-0.0.8.8.tar.gz",
    "platform": null,
    "description": "# Python 123 \u7f51\u76d8\u5ba2\u6237\u7aef\n\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/p123client)\n![PyPI - Version](https://img.shields.io/pypi/v/p123client)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/p123client)\n![PyPI - Format](https://img.shields.io/pypi/format/p123client)\n![PyPI - Status](https://img.shields.io/pypi/status/p123client)\n\n## 0. \u5b89\u88c5\n\n\u4f60\u53ef\u4ee5\u4ece [pypi](https://pypi.org/project/p123client/) \u5b89\u88c5\u6700\u65b0\u7248\u672c\n\n```console\npip install -U p123client\n```\n\n## 1. \u5bfc\u5165\u6a21\u5757\u548c\u521b\u5efa\u5b9e\u4f8b\n\n\u9996\u5148\u5bfc\u5165\u6a21\u5757\n\n```python\nfrom p123client import P123Client\n```\n\n### 1. \u7528 token \u521b\u5efa\u5b9e\u4f8b\n\n\u521b\u5efa\u5ba2\u6237\u7aef\u5bf9\u8c61\uff0c\u9700\u8981\u4f20\u5165 JWT <kbd>token</kbd>\uff0c\u4e5f\u5c31\u662f `access_token`\n\n```python\n# TODO: \u8bbf\u95ee\u4ee4\u724c\ntoken = \"...\"\n\nclient = P123Client(token=token)\n```\n\n\u6216\u8005\u76f4\u63a5\u5199\u4f5c\n\n```python\nclient = P123Client(token)\n```\n\n\u4e0d\u8fc7\u6211\u66f4\u63a8\u8350\u628a <kbd>token</kbd> \u5199\u5165\u4e00\u4e2a\u6587\u4ef6\u4e2d\uff0c\u4f8b\u5982\u5728 `~/123-token.txt`\n\n```python\nfrom pathlib import Path\n\nclient = P123Client(token=Path(\"~/123-token.txt\").expanduser())\n```\n\n\u6216\u8005\u76f4\u63a5\u5199\u4f5c\n\n```python\nclient = P123Client(Path(\"~/123-token.txt\").expanduser())\n```\n\n### 2. \u8d26\u53f7\u548c\u5bc6\u7801\u767b\u5f55\n\n```python\n# TODO: \u624b\u673a\u53f7\u6216\u8005\u90ae\u7bb1\npassport = \"...\" \n# TODO: \u5bc6\u7801\npassword = \"...\"\n\nclient = P123Client(passport=passport, password=passport)\n```\n\n\u6216\u8005\u76f4\u63a5\u5199\u4f5c\n\n```python\nclient = P123Client(passport, passport)\n```\n\n### 3. client_id \u548c client_secret \u767b\u5f55\n\n\u9700\u8981\u5148\u7533\u8bf7\u6210\u4e3a\u5f00\u53d1\u8005\n\nhttps://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/hpengmyg32blkbg8\n\n```python\n# TODO: \u5e94\u7528\u6807\u8bc6\uff0c\u521b\u5efa\u5e94\u7528\u65f6\u5206\u914d\u7684 appId\nclient_id = \"...\" \n# TODO: \u5e94\u7528\u5bc6\u94a5\uff0c\u521b\u5efa\u5e94\u7528\u65f6\u5206\u914d\u7684 secretId\nclient_secret = \"...\"\n\nclient = P123Client(client_id=client_id, client_secret=client_secret)\n```\n\n\u6216\u8005\u76f4\u63a5\u5199\u4f5c\n\n```python\nclient = P123Client(client_id, client_secret)\n```\n\n### 4. refresh_token \u767b\u5f55\n\n```python\n# TODO: \u5237\u65b0\u4ee4\u724c\nrefresh_token = \"...\"\n\nclient = P123Client(refresh_token=refresh_token)\n```\n\n\u6216\u8005\u76f4\u63a5\u5199\u4f5c\n\n```python\nclient = P123Client(refresh_token)\n```\n\n**\u6ce8\u610f**\uff1a\u4f7f\u7528 refresh_token\uff08\u6216\u8005\u8bf4 oauth \u767b\u5f55\uff09\uff0c\u53ea\u5141\u8bb8\u8bbf\u95ee open \u63a5\u53e3\n\n### 5. oauth \u767b\u5f55\n\n\u9700\u8981\u5148\u53bb\u5f00\u53d1\u8005\u540e\u53f0\u8bbe\u7f6e\u4e00\u4e0b\u56de\u8c03\u94fe\u63a5\uff0c\u5ba1\u6838\u901a\u8fc7\u540e\u624d\u53ef\u7528\n\n```python\n# TODO: \u5e94\u7528\u6807\u8bc6\uff0c\u521b\u5efa\u5e94\u7528\u65f6\u5206\u914d\u7684 appId\nclient_id = \"...\" \n# TODO: \u5e94\u7528\u5bc6\u94a5\uff0c\u521b\u5efa\u5e94\u7528\u65f6\u5206\u914d\u7684 secretId\nclient_secret = \"...\"\n# TODO: \u56de\u8c03\u94fe\u63a5\nredirect_uri = \"...\"\n# TODO: \u8bbf\u95ee\u4ee4\u724c\ntoken = \"...\"\n\nresp = P123Client.login_with_oauth(\n    client_id=client_id, \n    client_secret=client_secret, \n    redirect_uri=redirect_uri, \n    token=token, \n)\nclient = P123Client(\n    client_id=client_id, \n    client_secret=client_secret, \n    token=resp[\"access_token\"], \n    refresh_token=resp[\"refresh_token\"], \n)\n```\n\n### 6. \u626b\u7801\u767b\u5f55\n\n\u5f53\u4f60\u4ec0\u4e48\u90fd\u4e0d\u4f20\u65f6\uff0c\u5c31\u4f1a\u8981\u6c42\u4f60\u626b\u7801\u767b\u5f55\n\n```python\nclient = P123Client()\n```\n\n### 7. \u7528 token \u6765\u626b\u7801\u65b0\u7684 token\n\n\u4f60\u53ef\u4ee5\u7528\u4e00\u4e2a token \u53bb\u626b\u7801\u83b7\u5f97\u53e6\u4e00\u4e2a token\uff08\u4ec5\u5f53\u4e0d\u662f oauth \u767b\u5f55\u65f6\uff09\n\n```python\nclient_new = client.login_another()\n```\n\n\u53e6\u5916\u4f60\u4e5f\u53ef\u4ee5\u7528 oauth \u767b\u5f55\uff0c\u867d\u7136\u4ec5\u80fd\u8bbf\u95ee open \u63a5\u53e3\uff0c\u4f46\u662f QPS \u4e0a\u653e\u5f97\u66f4\u5bbd\n\n\u4e0b\u9762\u6211\u7528 clouddrive \u5728 123 \u7f51\u76d8\u4e0a\u7528 oauth \u767b\u5f55\u4e3e\u4f8b\u8bf4\u660e\u7b2c\u4e09\u65b9\u6302\u8f7d\u5e94\u7528\u767b\u5f55\uff1a\n\nhttps://123yunpan.yuque.com/org-wiki-123yunpan-muaork/cr6ced/kf05anzt1r0qnudd\n\n```python\nimport requests\nfrom urllib.parse import parse_qsl, urlsplit\n\nresp = client.login_oauth_authorize({\n    \"client_id\": \"7c278c60da9e43848c45ff8e6fa9da0a\", \n    \"redirect_uri\": \"https://redirect123pan.zhenyunpan.com/redirect_pan123\", \n    \"accessToken\": client.token, \n    \"state\": \"http://localhost:19798\", \n})\nwith requests.get(resp[\"url\"], allow_redirects=False, stream=True) as response:\n    resp = dict(parse_qsl(urlsplit(response.headers[\"location\"]).query))\nclient_new = P123Client(token=resp[\"access_token\"], refresh_token=resp[\"refresh_token\"])\n```\n\n### 8. \u5173\u4e8e token \u7684\u7ed3\u6784\n\n<kbd>token</kbd> \u4e2d\u5305\u542b\u4e86\u4e00\u4e9b\u4fe1\u606f\uff0c\u4ee5 \".\" \u8fdb\u884c\u5206\u5272\uff0c\u53ef\u4ee5\u62c6\u6210 3 \u4e2a\u90e8\u5206\uff1a\n\n- JWT \u7b97\u6cd5\uff08\u7ecf\u8fc7 base64 \u52a0\u5bc6\uff09\n- \u7528\u6237\u4fe1\u606f\uff08\u7ecf\u8fc7 base64 \u52a0\u5bc6\uff09\n- \u7b7e\u540d\u5b57\u7b26\u4e32\n\n```python\nfrom base64 import urlsafe_b64decode\nfrom json import loads\n\ntoken = client.token\n\nmethod, user_info, sign = token.split(\".\", 2)\nprint(\"JWT \u7b97\u6cd5:\", loads(urlsafe_b64decode(method)))\nprint(\"\u7528\u6237\u4fe1\u606f:\", loads(urlsafe_b64decode(user_info+\"==\")))\nprint(\"\u7b7e\u540d:\", sign)\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 p123client 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 `p123client.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 `p123client.P123OSError` \u7684\u5b9e\u4f8b\u3002\n\n```python\nfrom p123client 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 p123client import tool\n```\n\n## 5. \u5b66\u4e60\u6848\u4f8b\n\n### 1. \u521b\u5efa\u81ea\u5b9a\u4e49 uri\n\n```python\nfrom p123client import P123Client\nfrom p123client.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 p123client import P123Client\nfrom p123client.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 p123client import P123Client\nfrom p123client.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 [blacksheep](https://www.neoteroi.dev/blacksheep/)\n\n```console\npip install 'blacksheep[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 blacksheep import json, redirect, Application, Request\nfrom p123client import P123Client\nfrom p123client.tool import get_downurl\n\n# TODO: \u6539\u6210\u4f60\u81ea\u5df1\u7684\u8d26\u6237\u548c\u5bc6\u7801\nclient = P123Client(passport=\"\", password=\"\")\n\napp = Application(show_error_details=__debug__)\n\n@app.router.route(\"/{path:uri}\", methods=[\"GET\", \"HEAD\"])\nasync def index(request: Request, uri: str):\n    try:\n        payload = int(uri)\n    except ValueError:\n        if uri.count(\"|\") < 2:\n            return json({\"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.decode(\"ascii\")\n    url = await get_downurl(client, payload, quoted=False, async_=True)\n    return redirect(url)\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\u5bfc\u51fa\u7684\u6587\u4ef6\u4fe1\u606f\u4e2d\uff0c\u6709\u4e2a `\"uri\"`\uff0c\u8868\u793a\u6587\u4ef6\u7684\u81ea\u5b9a\u4e49\u94fe\u63a5\uff0c\u524d\u9762\u4ee5 `123://` \u5f00\u5934\uff0c\u4f60\u53ef\u4ee5\u66ff\u6362\u6210 302 \u670d\u52a1\u7684\u5730\u5740\uff0c\u4f8b\u5982 `http://localhost:8123/`\n\n#### 1. \u904d\u5386\u7f51\u76d8\u4e2d\u7684\u6587\u4ef6\u5217\u8868\n\n```python\nfrom p123client import P123Client\nfrom p123client.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):\n    print(info)\n```\n\n#### 2. \u904d\u5386\u5206\u4eab\u4e2d\u7684\u6587\u4ef6\u5217\u8868\uff0c\u4e0d\u542b\u76ee\u5f55\n\n```python\nfrom p123client.tool import share_iterdir\n\n# NOTE: \u65e0\u9700\u767b\u5f55\nfor info in share_iterdir(\n    \"https://www.123684.com/s/oec7Vv-CIYWh?\u63d0\u53d6\u7801:ZY4K\", \n    max_depth=-1, \n    predicate=lambda a: not a[\"is_dir\"], \n):\n    print(info)\n```\n\n#### 3. \u5bfc\u51fa\u5206\u4eab\u4e2d\u7684\u6587\u4ef6\u5217\u8868\u5230\u672c\u5730 .json \u6587\u4ef6\n\n```python\nfrom orjson import dumps\nfrom p123client.tool import share_iterdir\n\ndef export_share_files_json(\n    link: str, \n    path: str = \"\", \n    cooldown: float = 0, \n):\n    \"\"\"\u628a\u5206\u4eab\u94fe\u63a5\u4e2d\u7684\u6587\u4ef6\u5217\u8868\u5bfc\u51fa\u5230 json \u6587\u4ef6\n\n    :param link: \u5206\u4eab\u94fe\u63a5\uff0c\u53ef\u4ee5\u5305\u542b\u63d0\u53d6\u7801\n    :param path: \u4fdd\u5b58\u7684\u8def\u5f84\uff0c\u5982\u679c\u4e0d\u63d0\u4f9b\u5219\u81ea\u52a8\u786e\u5b9a\n    :param cooldown: \u4e24\u6b21\u8c03\u7528\u4e4b\u95f4\uff0c\u51b7\u5374\u7684\u65f6\u95f4\uff08\u7528\u4e24\u6b21\u8c03\u7528\u5f00\u59cb\u65f6\u7684\u65f6\u95f4\u5dee\uff0c\u800c\u4e0d\u662f\u4e00\u6b21\u5b8c\u6210\u5230\u4e0b\u4e00\u6b21\u5f00\u59cb\u7684\u65f6\u95f4\u5dee\uff09\n    \"\"\"\n    print(\"< \u5c06\u62c9\u53d6:\", link)\n    ls: list[dict] = []\n    for i, a in enumerate(share_iterdir(link, max_depth=-1, cooldown=cooldown), 1):\n        ls.append(a)\n        print(i, a)\n    if ls:\n        info = ls[0]\n        if not path:\n            suffix = f\"@{info['ShareKey']},{info['SharePwd']}.json\"\n            path = f\"{info['name'][:255-len(suffix)]}{suffix}\"\n        open(path, \"wb\").write(dumps(ls))\n        print()\n        print(\"> \u5df2\u62c9\u53d6:\", link)\n        print(\"> \u5df2\u4fdd\u5b58:\", path)\n\nexport_share_files_json(\"https://www.123684.com/s/oec7Vv-CIYWh?\u63d0\u53d6\u7801:ZY4K\")\n```\n\n### 6. \u6700\u65b0\u7684\u64cd\u4f5c\u8bb0\u5f55\n\n\u5728\u7f51\u76d8\u4e2d\uff0c\u4f60\u53ef\u4ee5\u6309\u66f4\u65b0\u65f6\u95f4\u9006\u5e8f\u67e5\u8be2\uff0c\u5373\u53ef\u5f97\u5230\u6700\u65b0\u4e0a\u4f20\u7684\u6587\u4ef6\u5217\u8868\n\n```python\nclient.fs_list_new({\n    \"orderBy\": \"update_time\", \n    \"orderDirection\": \"desc\", \n    \"SearchData\": \".\", \n})\n```\n\n\u66f4\u4e00\u822c\u7684\uff0c\u4f60\u53ef\u4ee5\u5728[\u540c\u6b65\u7a7a\u95f4](https://www.123pan.com/SynchronousSpace/main)\u4e2d\u6267\u884c\u6587\u4ef6\u64cd\u4f5c\u3002\n\n\u800c\u5728\u62c9\u53d6\u6587\u4ef6\u5217\u8868\u65f6\uff0c\u9700\u8981\u6307\u5b9a\n\n```python\nclient.fs_list_new({\n    \"operateType\": \"SyncSpacePage\", \n    \"event\": \"syncFileList\", \n    \"RequestSource\": 1, \n})\n```\n\n\u540c\u6b65\u7a7a\u95f4\u4e2d\u7684\u589e\u5220\u6539\u64cd\u4f5c\u90fd\u6709[\u64cd\u4f5c\u8bb0\u5f55](https://www.123pan.com/SynchronousSpace/record)\uff0c\u4f60\u53ef\u4ee5\u7528\u63a5\u53e3\n\n```python\nclient.fs_sync_log()\n```\n\n## \u5176\u5b83\u8d44\u6e90\n\n- \u5982\u679c\u4f60\u9700\u8981\u66f4\u8be6\u7ec6\u7684\u6587\u6863\uff0c\u7279\u522b\u662f\u5173\u4e8e\u5404\u79cd\u63a5\u53e3\u7684\u4fe1\u606f\uff0c\u53ef\u4ee5\u9605\u8bfb\n\n    [https://p123client.readthedocs.io/en/latest/](https://p123client.readthedocs.io/en/latest/)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python 123 webdisk client.",
    "version": "0.0.8.8",
    "project_urls": {
        "Homepage": "https://github.com/ChenyangGao/p123client",
        "Repository": "https://github.com/ChenyangGao/p123client"
    },
    "split_keywords": [
        "123",
        " webdisk",
        " client"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "388b545b2e4662ae442133b909e1908c8fc7f2b17b429cb040721a4e057b6993",
                "md5": "3fdb01ed8a438922a0abca2c838aa7bb",
                "sha256": "1c1f2b0750c3a03a9bd7591e862912031081d8d77d12c77f951881db54d81ce7"
            },
            "downloads": -1,
            "filename": "p123client-0.0.8.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3fdb01ed8a438922a0abca2c838aa7bb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.12",
            "size": 62905,
            "upload_time": "2025-07-25T18:18:30",
            "upload_time_iso_8601": "2025-07-25T18:18:30.081129Z",
            "url": "https://files.pythonhosted.org/packages/38/8b/545b2e4662ae442133b909e1908c8fc7f2b17b429cb040721a4e057b6993/p123client-0.0.8.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e4853e0af42d5746361f2153ba3681887d18b17fed8c70eadf90c1d2d52834cc",
                "md5": "1d4ea27544c166cc6a2368b6d600c31c",
                "sha256": "1f4d6effc798505ddef1925beac60bc4231aa88ba0982c139f16b2b542292c1a"
            },
            "downloads": -1,
            "filename": "p123client-0.0.8.8.tar.gz",
            "has_sig": false,
            "md5_digest": "1d4ea27544c166cc6a2368b6d600c31c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.12",
            "size": 57812,
            "upload_time": "2025-07-25T18:18:31",
            "upload_time_iso_8601": "2025-07-25T18:18:31.790361Z",
            "url": "https://files.pythonhosted.org/packages/e4/85/3e0af42d5746361f2153ba3681887d18b17fed8c70eadf90c1d2d52834cc/p123client-0.0.8.8.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-25 18:18:31",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ChenyangGao",
    "github_project": "p123client",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "p123client"
}
        
Elapsed time: 0.52326s