添加 Cookie 组件 (#633)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
2024-10-31 12:56:15 +08:00
committed by GitHub
parent 3bdc79162e
commit 97a0f04808
63 changed files with 6119 additions and 806 deletions
+19 -1
View File
@@ -23,11 +23,29 @@ export default navbar([
link: "",
activeMatch: "^/usage/?$",
},
{
text: "Cookie 使用",
icon: "cookie",
link: "cookie",
},
],
},
{
text: "开发",
icon: "flask",
link: "/dev/",
prefix: "/dev/",
children: [
{
text: "基本开发",
icon: "tools",
link: "",
activeMatch: "^/dev/?$",
},
{
text: "Cookie 开发",
icon: "cookie",
link: "cookie",
},
],
},
]);
Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

+1 -3
View File
@@ -80,6 +80,7 @@ export default hopeTheme({
sup: true,
tabs: true,
vPre: true,
mermaid: true,
// 在启用之前安装 chart.js
// chart: true,
@@ -101,9 +102,6 @@ export default hopeTheme({
// 在启用之前安装 mathjax-full
// mathjax: true,
// 在启用之前安装 mermaid
// mermaid: true,
// playground: {
// presets: ["ts", "vue"],
// },
+5
View File
@@ -1,3 +1,8 @@
---
prev: /usage/install
next: /dev/cookie
---
# 基本开发须知
## 语言以及工具
+157
View File
@@ -0,0 +1,157 @@
---
prev: /usage/
#next: /dev/cookie
---
# Cookie 开发须知
本项目将大部分 Cookie 相关逻辑提出到了 Site 及 ClientManger 模块中,只需要继承相关类即可获得使用 Cookie 的能力。
::: tip
在开发 Cookie 功能之前,你应该对[基本开发](/dev/#基本开发)有一定的了解。
:::
## Cookie 相关的基本概念
- `nonebot_bison.config.db_model.Cookie`: 用于存储 Cookie 的实体类,包含了 Cookie 的名称、内容、状态等信息
- `nonebot_bison.config.db_model.CookieTarget`: 用于存储 Cookie 与订阅的关联关系
- `nonebot_bison.utils.site.CookieClientManager`: 添加了 Cookie 功能的 ClientManager,是 Cookie 管理功能的核心,调度 Cookie 的功能就在这里实现
## 快速上手
例如,现在有一个这样子的 Site 类:
```python
class WeiboSite(Site):
name = "weibo.com"
schedule_type = "interval"
schedule_setting = {"seconds": 3}
```
简而言之,要让站点获得 Cookie 能力,只需要:
为 Site 类添加一个`client_mgr`字段,值为`CookieClientManager.from_name(name)`,其中`name`为站点名称,这是默认的 Cookie 管理器。
```python {5}
class WeiboSite(Site):
name = "weibo.com"
schedule_type = "interval"
schedule_setting = {"seconds": 3}
client_mgr = CookieClientManager.from_name(name)
```
至此,站点就可以使用 Cookie 了!
## 更好的体验
为了给用户提供更好的体验,还可以创建自己的 `ClientManager`:继承 `CookieClientManager` 并重写`validate_cookie`和`get_target_name`方法。
- `async def validate_cookie(cls, content: str) -> bool`该方法将会在 Cookie 添加时被调用,可以在这里验证 Cookie 的有效性
- `async def get_cookie_name(cls, content: str) -> str`该方法将会在验证 Cookie 成功后被调用,可以在这里设置 Cookie 的名字并展示给用户
## 自定义 Cookie 调度策略
当默认的 Cookie 调度逻辑无法满足需求时,可以重写`CookieClientManager`的`_choose_cookie`方法。
目前整体的调度逻辑是:
```mermaid
sequenceDiagram
participant Scheduler
participant Platform
participant CookieClientManager
participant DB
participant Internet
Scheduler->>Platform: exec_fetch
Platform->>Platform: do_fetch_new_post(SubUnit)
Platform->>Platform: get_sub_list(Target)
Platform->>CookieClientManager: get_client(Target)
CookieClientManager->>CookieClientManager: _choose_cookie(Target)
CookieClientManager->>DB: get_cookies()
CookieClientManager->>CookieClientManager: _assemble_client(Target, cookie)
CookieClientManager->>Platform: client
Platform->>Internet: client.get(Target)
Internet->>Platform: response
Platform->>CookieClientManager: _response_hook()
CookieClientManager->>DB: update_cookie()
```
目前 CookieClientManager 具有以下方法
- `refresh_anonymous_cookie(cls)` 移除已有的匿名 cookie,添加一个新的匿名 cookie,应该在 CCM 初始化时调用
- `add_user_cookie(cls, content: str)` 添加用户 cookie,在这里对 Cookie 进行检查并获取 cookie_name,写入数据库
- `_generate_hook(self, cookie: Cookie) -> Callable` hook 函数生成器,用于回写请求状态到数据库
- `_choose_cookie(self, target: Target) -> Cookie` 选择 cookie 的具体算法
- `add_user_cookie(cls, content: str, cookie_name: str | None = None) -> Cookie` 对外的接口,添加用户 cookie,内部会调用 Site 的方法进行检查
- `get_client(self, target: Target | None) -> AsyncClient` 对外的接口,获取 client,根据 target 选择 cookie
- `_assemble_client(self, client, cookie) -> AsyncClient` 组装 client,可以自定义 cookie 对象的 content 装配到 client 中的方式
::: details 大致流程
1. `Platfrom` 调用 `CookieClientManager.get_client` 方法,传入 `Target` 对象
2. `CookieClientManager` 根据 `Target` 选择一个 `Cookie` 对象
3. `CookieClientManager` 调用 `CookieClientManager._assemble_client` 方法,将 Cookie 装配到 `Client` 中
4. `Platform` 使用 `Client` 进行请求
:::
简单来说:
- 如果需要修改 Cookie 的默认参数,可以重写`add_user_cookie`方法,这里设置需要的字段
- 如果需要修改选择 Cookie 的逻辑,可以重写`_choose_cookie`方法,使用自己的算法选择合适的 Cookie 并返回
- 如果需要自定义 Cookie 的格式,可以重写`valid_cookie`方法,自定义验证 Cookie 的逻辑,并重写`_assemble_client`方法,自定义将 Cookie 装配到 Client 中的逻辑
- 如果要在请求结束后做一些操作(例如保存此次请求的结果/状态),可以重写`_response_hook`方法,自定义请求结束后的行为
- 如果需要跳过一次请求,可以在 `get_client` 方法中抛出 `SkipRequestException` 异常,调度器会捕获该异常并跳过此次请求
## 实名 Cookie 和匿名 Cookie
部分站点所有接口都需要携带 Cookie,对于匿名用户(未登录)也会发放一个临时 Cookie,本项目称为匿名 Cookie。
在此基础上,我们添加了用户上传 Cookie 的功能,这种 Cookie 本项目称为实名 Cookie。
匿名 Cookie 和实名 Cookie 在同一个框架下统一调度,实名 Cookie 优先级高于匿名 Cookie。为了调度,Cookie 对象有以下字段:
```python
# 最后使用的时刻
last_usage: Mapped[datetime.datetime] = mapped_column(DateTime, default=datetime.datetime(1970, 1, 1))
# Cookie 当前的状态
status: Mapped[str] = mapped_column(String(20), default="")
# 使用一次之后,需要的冷却时间
cd_milliseconds: Mapped[int] = mapped_column(default=0)
# 是否是通用 Cookie(对所有 Target 都有效)
is_universal: Mapped[bool] = mapped_column(default=False)
# 是否是匿名 Cookie
is_anonymous: Mapped[bool] = mapped_column(default=False)
# 标签,扩展用
tags: Mapped[dict[str, Any]] = mapped_column(JSON().with_variant(JSONB, "postgresql"), default={})
```
其中:
- **is_universal**:用于标记 Cookie 是否为通用 Cookie,即对所有 Target 都有效。可以理解为是一种特殊的 target,添加 Cookie 和获取 Cookie 时通过传入参数进行设置。
- **is_anonymous**:用于标记 Cookie 是否为匿名 Cookie,目前的定义是:可以由程序自动生成的,适用于所有 Target 的 Cookie。目前的逻辑是 bison 启动时,生成一个新的匿名 Cookie 并替换掉原有的匿名 Cookie。
- **无 Target 平台的 Cookie 处理方式**
对于不存在 Target 的平台,如小刻食堂,可以重写 add_user_cookie 方法,为用户 Cookie 设置 is_universal 字段。这样,在获取 Client 时,由于传入的 Target 为空,就只会选择 is_universal 的 cookie。实现了无 Target 平台的用户 Cookie 调度。
## 默认的调度策略
默认的调度策略在 CookieClientManager 的 `_choose_cookie` 方法中实现:
```python
async def _choose_cookie(self, target: Target | None) -> Cookie:
"""选择 cookie 的具体算法"""
cookies = await config.get_cookie(self._site_name, target)
cookies = (cookie for cookie in cookies if cookie.last_usage + cookie.cd < datetime.now())
cookie = min(cookies, key=lambda x: x.last_usage)
return cookie
```
简而言之,会选择最近使用时间最早的 Cookie,且不在冷却时间内的 Cookie。
在默认情况下,匿名 Cookie 的冷却时间为 0,实名 Cookie 的冷却时间为 10 秒。也就是说,调度时,如果没有可用的实名 Cookie,则会选择匿名 Cookie。
+16 -1
View File
@@ -1,6 +1,6 @@
---
prev: /usage/install
next: /usage/easy-use
next: /usage/cookie
---
# 全方位了解 Bison 的自行车
@@ -272,6 +272,21 @@ Bison 在处理每条推送时,会按照以下规则顺序检查推送中的 T
3. **需订阅 Tag** 列表为空
- **发送**该推送到群中,检查结束
#### Cookie 功能
Bison 支持携带 Cookie 进行请求。
目前支持的平台有:
- `rss`: RSS
- `weibo`: 新浪微博
::: warning 使用须知
Cookie 全局生效,这意味着,通过你的 Cookie 获取到的内容,可能会被发给其他用户。
:::
管理员可以通过**命令**或**管理后台**给 Bison 设置 Cookie。
<script setup lang="ts">
import { ref, computed } from 'vue';
+113
View File
@@ -0,0 +1,113 @@
---
prev: /usage/
next: /usage/install
---
# :cookie: Bison 的自行车电助力装置
Bison 支持 Cookie 啦,你可以将 Cookie 关联到订阅以获得更好的体验。
但是,盲目使用 Cookie 功能并不能解决问题,反而可能为你的账号带来风险。请阅读完本文档后再决定是否使用 Cookie 功能。
::: warning 免责声明
Bison 具有良好的风控应对机制,我们会尽力保护你的账户,但是无法保证绝对的安全。
nonebot-bison 开发者及 MountainDash 社区不对因使用 Cookie 导致的任何问题负责。
:::
## :monocle_face: 什么时候需要 Cookie
首先,请确认 Cookie 的使用场景,并了解注意事项。
在绝大多数情况下,Bison 不需要 Cookie 即可正常工作。但是,部分平台只能够获取有限的内容,此时,Cookie 就可以帮助 Bison 获取更多的内容。
例如,微博平台可以设置微博为“仅粉丝可见”,正常情况下 Bison 无法获取到这些内容。如果你的账号是该博主的粉丝,那么你可以将你的 Cookie 关联到 Bison,这样 Bison 就可以获取到这些受限内容。
::: warning 使用须知
Cookie 全局生效,这意味着,通过你的 Cookie 获取到的内容,可能会被共享给其他用户。
当然,Bison 不会将你的 Cookie 透露给其他用户。但是,管理员或其他可以接触的数据库的人员可以看到**所有 Cookie**的内容。所以,在上传 Cookie 之前,请确保管理人员可信。
:::
## :wheelchair: 我该怎么使用 Cookie
首先,需要明确的是,因为 Cookie 具有隐私性,所有与 Cookie 相关的操作,仅支持**管理员**通过**私聊**或者通过**WebUI**进行管理。
目前,使用 Cookie 主要有两个步骤:
- **添加 Cookie**: 将 Cookie 发给 Bison
- **关联 Cookie**: 告诉 Bison,你希望在什么时候使用这个 Cookie
## :nerd_face: 如何获取 Cookie
对于大部分平台,Bison 支持 JSON 格式的 Cookie,你可以通过浏览器的开发者工具获取。
- RSS: 对于各种 RSS 订阅,你需要自行准备需要的 Cookie,以 JSON 格式添加即可
- 微博:Bison 兼容 RSSHub 的 Cookie,以下方法引用自[RSSHub 的文档](https://docs.rsshub.app/zh/deploy/config#%E5%BE%AE%E5%8D%9A)
> 1. 打开并登录 https://m.weibo.cn(确保打开页面为手机版,如果强制跳转电脑端可尝试使用可更改 UserAgent 的浏览器插件)
> 2. 按下 F12 打开控制台,切换至 Network(网络)面板
> 3. 在该网页切换至任意关注分组,并在面板打开最先捕获到的请求(该情形下捕获到的请求路径应包含/feed/group
> 4. 查看该请求的 Headers(请求头), 找到 Cookie 字段并复制内容
- Bilibili: Bison 兼容 RSSHub 的 Cookie,以下方法引用自[RSSHub 的文档](https://docs.rsshub.app/zh/deploy/config#bilibili)
> 1. 打开 https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new?uid=0&type=8
> 2. 打开控制台,切换到 Network 面板,刷新
> 3. 点击 dynamic_new 请求,找到 Cookie
> 4. 视频和专栏,UP 主粉丝及关注只要求 SESSDATA 字段,动态需复制整段 Cookie
## :sparkles: 给 Bison 添加 Cookie
打开 Bison 的私聊,发送 `添加cookie` 命令,Bison 会开始添加 Cookie 流程。
![add cookie](/images/add-cookie.png)
然后,依次输入平台名称和 Cookie 内容。
![add cookie 2](/images/add-cookie-2.png)
看到 Bison 的回复之后,Cookie 就添加成功啦!
## :children_crossing: 关联 Cookie 到具体的订阅
接下来要关联 Cookie 到一个具体的订阅。
输入 `添加关联cookie` 命令,Bison 就会列出当前所有的订阅。
我们选择一个订阅,Bison 会列出所有的可以选择的 Cookie。
![add-cookie-target.png](/images/add-cookie-target.png)
再选择需要关联的 Cookie。
至此,Bison 便会携带我们的 Cookie 去请求订阅目标啦!
## :stethoscope: 取消关联 Cookie
如果你想取消关联某个 Cookie,可以发送 `取消关联cookie` 命令,Bison 会列出所有已被关联的订阅和 Cookie。
选择需要取消关联的 CookieBison 会取消此 Cookie 对该订阅的关联。
这是 `添加关联cookie` 的逆向操作。
## :wastebasket: 删除 Cookie
如果你想删除某个 Cookie,可以发送 `删除cookie` 命令,Bison 会列出所有已添加的 Cookie。
选择需要删除的 CookieBison 会删除此 Cookie。
::: tip
只能删除未被关联的 Cookie。
也就是说,你需要先取消一个 Cookie 的所有关联,才能删除。
:::
这是 `添加cookie` 的逆向操作。
## :globe_with_meridians: 使用 WebUI 管理 Cookie
同样的,Bison 提供了一个网页管理 Cookie 的功能,即 WebUI,你可以在网页上查看、添加、删除 Cookie。
使用方法参见 [使用网页管理订阅](/usage/easy-use#使用网页管理订阅)。
## :tada: 完成!
至此,你已经掌握了使用 Cookie 的方法。
Congratulations! 🎉