用户发来 https://mp.weixin.qq.com/s/ZEOsi4R4JcmZ_mhS6qpcww,存进库的正文只有 67 个字符 ("原文链接 + 一个句号")。复盘发现公众号换了渲染方式:新版页面把整篇塞进 window.cgiDataNew 这个 JS 对象由前端渲染,页面里根本没有 id="js_content"; 三种 UA 拿到的字节数完全一样,也不是 UA 的问题。 - 从 JS 字符串字面量里读正文(content_noencode / desc),按 \xNN、\uNNNN 反转义, 话题标签是双重转义过的 HTML,先 unescape 再走 DOM。 - 配图字段排在文字之后,所以前后各找 2500 字符合图;剩下没用过的 mmbiz 图按 12 张上限补在末尾(图文型文章靠就近配对会漏)。 - 解析顺序:旧 DOM → 新版 JS 数据 → 通用抽取,一层层退。 实测两篇:2373 字符 + 12 张图、2772 字符 + 13 张图,作者也都取到了。 同时补上用户提的两件: - 知识能删了:DELETE /knowledge/{id}?confirm=true,软删 + 真删检索切片, 只有作者或 owner/admin 能删;列表卡片(悬停出现)和阅读页动作行各一个入口。 删完详情也回 7001,否则收藏的链接还能打开一篇已删除的知识。 - 分类下面有标签清单了:GET /knowledge/tags 按标签数"有多少条知识用了它", 侧栏渲染成 #标签 + 条数,点一下筛选、再点取消。
This commit is contained in:
+26
-2
@@ -513,7 +513,30 @@ Web 端未读数由 `AppShell` 每 30 秒轮询一次;在通知页标已读后
|
||||
|
||||
### 5.2 `GET /knowledge/{item_id}`
|
||||
|
||||
详情,附最近 50 条 `activities`。不存在或跨租户统一 `7001`。
|
||||
详情,附最近 50 条 `activities`。不存在、跨租户、**已经删掉**的统一 `7001`
|
||||
(删除是软删,但对读的人来说就是"没了",否则收藏的链接还会打开一篇已删除的知识)。
|
||||
|
||||
### 5.2.1 `GET /knowledge/tags` — 侧栏那串标签
|
||||
|
||||
```
|
||||
GET /knowledge/tags?status=published&status=in_review
|
||||
```
|
||||
|
||||
```json
|
||||
{"items": [{"name": "发布", "count": 12}, {"name": "回滚", "count": 3}]}
|
||||
```
|
||||
|
||||
- `count` 是**有多少条知识用了它**(`count(distinct item_id)`),不是引用次数。
|
||||
- 只统计未删除的知识;带了 `status` 就只数这些状态,和列表的 tab 对得上。
|
||||
- 按条数从多到少排,同数按名字。标签是分类之外的第二根轴:分类回答"属于哪一块",标签回答"跟什么有关"。
|
||||
|
||||
### 5.2.2 `DELETE /knowledge/{item_id}?confirm=true` — 删除
|
||||
|
||||
- 必须显式带 `confirm=true`,否则 `1002`「删除不能撤销,带 confirm=true 再来一次」(防手滑)。
|
||||
- 只有**作者本人**或 `owner`/`admin` 能删,否则 `3004`。
|
||||
- 软删:`item.deleted_at` 落时间戳,列表、详情、检索、标签统计里都不再出现;
|
||||
**检索切片真删**(`chunk` 表),否则"删掉的知识还能被搜出来"比删不掉更吓人。
|
||||
- 重复删不回错误,回 `message: "已经删过了"`,让重试的客户端不必区分。
|
||||
|
||||
### 5.3 `POST /knowledge` — 手记或指定来源
|
||||
|
||||
@@ -758,7 +781,8 @@ Query:
|
||||
|---|---|
|
||||
| 判断 | `extract_url()`:去掉首尾标点后只剩一个链接;带了别的话("看下 https://… 这个")仍按任务处理 |
|
||||
| 抓取 | `httpx` 取页面(25 秒超时、8 MB 上限),`trafilatura` 抽正文;标题取 `og:title`/`<h1>`/`<title>` |
|
||||
| 公众号 | `mp.weixin.qq.com` 单独走 DOM:标题 `#activity-name`、作者 `#js_name`、正文 `#js_content`,图片取 `data-src`(通用抽取器会把公众号的图丢光) |
|
||||
| 公众号(旧页) | `mp.weixin.qq.com` 且页面有 `#js_content`:标题 `#activity-name`、作者 `#js_name`、正文 `#js_content`,图片取 `data-src`(通用抽取器会把公众号的图丢光) |
|
||||
| 公众号(新版页) | 没有 `#js_content` 时(`appmsg_type = '9'` / `'10002'`)整篇在 `window.cgiDataNew` 里:从 `content_noencode` / `desc` 的 JS 字符串字面量读正文,按 `\xNN`、`\uNNNN` 反转义,话题标签先 `html.unescape` 再走 DOM;配图字段(`cdn_url`/`img_url`/`pic_url`)排在文字之后,前后各找 2500 字符合图;作者兜底取 `nick_name` |
|
||||
| 清洗 | 导航/页脚按行边界裁掉(`_trim_chrome`);`trafilatura` 结果太短(<120 字)就退到容器打分兜底 |
|
||||
| 配图 | 正文里的外链图下载进我们自己的存储,最多 12 张、单张 8 MB,正文改写成 `/attachments/{id}/raw?签名`——公众号一换图,外链就是一排红叉 |
|
||||
| 落库 | 知识草稿(`status="draft"`,`doc_type="note"`),正文首行是 `> 原文:<url>` |
|
||||
|
||||
@@ -857,7 +857,37 @@
|
||||
`lxml / courlan / htmldate / jusText / lxml_html_clean / …` 再 `pip install --no-deps trafilatura`;
|
||||
`lxml` 6 起 `lxml.html.clean` 拆成 `lxml_html_clean`,不装就 `ImportError`。
|
||||
|
||||
### 13.9 还没做
|
||||
#### 13.8.1 用户发来真链接,结果只抓到一个「。」
|
||||
|
||||
上线后用户发了 `https://mp.weixin.qq.com/s/ZEOsi4R4JcmZ_mhS6qpcww`,库里只有 67 个字符的正文。
|
||||
复盘:**公众号换了渲染方式**——新版页面(`window.appmsg_type = '9'` / `'10002'`)整篇塞进
|
||||
`window.cgiDataNew` 这个 JS 对象、由前端渲染,页面里根本没有 `id="js_content"`;
|
||||
三种 UA(桌面 / iPhone Safari / MicroMessenger)拿到的字节数完全一样,所以也不是 UA 的问题。
|
||||
|
||||
修法(`backend/app/services/article.py`):
|
||||
|
||||
- 从 JS 字符串字面量里读正文:`content_noencode` / `desc`,按 `\xNN`、`\uNNNN` 反转义;
|
||||
话题标签是双重转义的 HTML(`\x26lt;a class=\x26quot;wx_topic_link\x26quot;\x26gt;#调料…`),
|
||||
先 `html.unescape` 再走 DOM。
|
||||
- 配图字段(`cdn_url` / `img_url` / `pic_url`)**排在文字字段之后**,所以配图要前后各找 2500 字符;
|
||||
剩下没用过的 `mmbiz.qpic.cn` 图按 12 张上限补在末尾(图文型「小绿书」的图不在文字附近)。
|
||||
- 解析顺序:旧 DOM(`#js_content`)→ 新版 JS 数据 → 通用抽取,一层层退。
|
||||
- 作者兜底从 `nick_name` 取,标题取 `og:title`。
|
||||
|
||||
结果:那篇 2373 字符 + 12 张图,蒜蓉酱那篇 2772 字符 + 13 张图,作者都取到了。
|
||||
**教训:抓取器写死在一种页面结构上,等于给自己埋一个定时炸弹;线上先看真实 HTML 再改。**
|
||||
|
||||
### 13.9 知识库:标签清单与删除
|
||||
|
||||
用户提两件:"文章都缺少删除功能"、"分类有列表显示,但是分类的下面应该还有标签的列表"。
|
||||
|
||||
- `GET /knowledge/tags`:按标签统计"有多少条知识用了它",带 `status` 就跟着 tab 数;
|
||||
侧栏在分类树下面渲染成一排 `#标签 + 条数`,点一下筛选、再点取消。
|
||||
- `DELETE /knowledge/{item_id}?confirm=true`:软删 + 真删检索切片;只有作者或 `owner`/`admin` 能删;
|
||||
列表卡片(悬停出现)和阅读页动作行各有一个入口。删完详情也回 `7001`,
|
||||
否则收藏的链接还能打开一篇"已经删掉的知识"。
|
||||
|
||||
### 13.10 还没做
|
||||
|
||||
- 只做了"进"(收消息建事项),没做"出"(任务有进展回一条微信通知)。
|
||||
- 消息不认人:按通道创建者记账;要认人得先做微信身份绑定。
|
||||
|
||||
Reference in New Issue
Block a user