mpdt 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mpdt-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ttxs69
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
mpdt-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,258 @@
1
+ Metadata-Version: 2.4
2
+ Name: mpdt
3
+ Version: 0.2.0
4
+ Summary: 公众号运营数据本地 CLI:把后台三源数据抓回本机 SQLite,一键生成周报
5
+ Author: ttxs69
6
+ License: MIT
7
+ Keywords: wechat,weixin,mp,official-account,analytics,cli
8
+ Classifier: Environment :: Console
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Office/Business
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: requests
20
+ Requires-Dist: websocket-client
21
+ Dynamic: license-file
22
+
23
+ # mpdt — 公众号运营数据,抓回本机,一键周报
24
+
25
+ > WeChat Official Account analytics, fully local — fetch, store, and report your own data via one CLI.
26
+
27
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)]()
28
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)]()
29
+ [![CI](https://github.com/ttxs69/mpdt/actions/workflows/tests.yml/badge.svg)](https://github.com/ttxs69/mpdt/actions/workflows/tests.yml)
30
+ [![Tests](https://img.shields.io/badge/tests-98%20passing-brightgreen)]()
31
+ [![Dependencies](https://img.shields.io/badge/dependencies-requests%20%2B%20websocket--client-orange)]()
32
+
33
+ 公众号后台(mp.weixin.qq.com)的运营数据散落在三个页面,官方不提供导出,mpdt 把它们自动抓回本机 SQLite,并生成 Markdown 周报:
34
+
35
+ - **发表列表**:阅读 / 分享 / 点赞 / 评论(实时累计口径)
36
+ - **datacube 文章级**:完读率 / 阅读率 / 送达 pv(发表后 7 天窗口,T+1)
37
+ - **单篇渠道页**:逐篇阅读人数、完读率、平均时长、渠道构成(推荐 / 搜一搜 / 公众号消息…,30 天窗口)
38
+
39
+ ## 为什么做这个
40
+
41
+ - **官方不提供导出**:后台数据只能一屏一屏翻页看,换设备、离职交接、跨年对比都无从下手
42
+ - **商业工具 ¥99/月起**:第三方 SaaS 要么按月收费,要么要求交出账号托管,个人号主用不起也不敢用
43
+ - **个人号主被忽视**:官方与商业工具都面向机构运营团队,一个人打理的号缺少趁手的本地工具
44
+
45
+ mpdt 的答案:**数据 100% 留在本机**(SQLite + 本地文件),复用你已登录的 Chrome,不托管、不上传、不收费。
46
+
47
+ > ⚠️ **口径警告**:三源同名指标口径不同(统计窗口 / 分母各异)——发表列表是实时累计,datacube 是发表后 7 天窗口 T+1,单篇渠道页是 30 天窗口。**跨源比较前先对齐口径**,周报文首附完整口径说明。
48
+
49
+ ## 特性
50
+
51
+ - **零扫码**:复用本机已登录 Chrome 的登录态(CDP 远程调试),token 从页面 URL 自动刷新
52
+ - **全本地**:数据只存本机 SQLite(`~/.mpdt/mpdt.sqlite3`),凭据文件 600 权限、打印永不回显
53
+ - **幂等**:同一天重复抓取 upsert 不重复;`log_run` 记录每次运行
54
+ - **礼貌限速**:请求间隔 ≥ 1s
55
+ - **错误语义明确**:退出码 `0` 成功(含空数据)|`2` 配置问题|`3` 凭据/登录态问题|`4` 上游接口异常(附原始返回片段)|`130` 用户中断(幂等设计,重跑安全)
56
+ - **机器可读输出**:全局 `--json` 参数——stdout 恰好一行 JSON(`{ok, cmd, data, meta}`),适合脚本/管道串联
57
+ - **非交互友好**:stdout 非 TTY(管道 / 重定向 / cron)时自动静默过程输出
58
+ - **零框架测试**:98 个 unittest,零第三方测试依赖,`python3 tests/test_fetchers.py` 直跑
59
+
60
+ ## 安装
61
+
62
+ ```bash
63
+ # 推荐:pip 安装
64
+ pip install git+https://github.com/ttxs69/mpdt.git
65
+
66
+ # 或本地安装
67
+ git clone https://github.com/ttxs69/mpdt.git
68
+ cd mpdt && pip install .
69
+ ```
70
+
71
+ > 未安装到环境时,`python3 -m mpdt` 与 `mpdt` 命令完全等价——从仓库根目录直接运行即可。
72
+
73
+ 依赖:Python 3.10+、`requests`、`websocket-client`(其余全标准库)。
74
+
75
+ ## Quick Start(30 秒)
76
+
77
+ ```bash
78
+ # ① 以调试端口启动 Chrome 并登录公众号后台
79
+ google-chrome --remote-debugging-port=9222
80
+ # 打开 https://mp.weixin.qq.com 扫码登录,保持该标签页存在
81
+
82
+ # ② 初始化配置(生成 ~/.mpdt/config.json,600 权限)
83
+ mpdt init
84
+
85
+ # ③ 抓数据 → 出周报
86
+ mpdt fetch --backfill 7 # 抓最近 7 天(默认仅昨天,T+1 口径)
87
+ mpdt detail --recent 7 # 单篇渠道构成(最近 7 天发表的)
88
+ mpdt report # → mpdt-reports/weekly-YYYY-Www.md
89
+ ```
90
+
91
+ > 已在跑的 Chrome 需先完全退出再用该参数重启;介意隔离可用独立 profile:
92
+ > `--user-data-dir=/tmp/mpdt-chrome --remote-debugging-port=9222`
93
+
94
+ ## 命令一览
95
+
96
+ | 命令 | 作用 | 常用参数 |
97
+ |---|---|---|
98
+ | `mpdt init` | 生成配置 | `--db PATH` 自定义数据库位置 |
99
+ | `mpdt fetch` | 发表列表 + datacube 文章级快照 | `--backfill N` / `--from/--to YYYY-MM-DD` / `--count N` |
100
+ | `mpdt detail` | 单篇渠道页(完读率 + 渠道构成) | `--recent N`,或 `--msgid ID --publish-date D [--item-idx 1]` |
101
+ | `mpdt report` | 生成周报 Markdown + HTML | `--week 2026-W42` |
102
+ | `mpdt export` | 导出快照 CSV(附口径元数据 `*.metrics.csv`) | `--source SOURCE --out OUT`(`--no-meta` 关闭伴随文件) |
103
+ | `mpdt metrics` | 列出全部指标及口径(按概念分组) | 可选位置参数按 概念名/显示名/源/字段 子串过滤 |
104
+
105
+ 所有命令支持全局 `--json`(stdout 恰好一行 JSON)。
106
+
107
+ ## 指标口径(CONCEPTS · 按概念分组)
108
+
109
+ #### 完读率(`read_completion`,单位:比例(0-1))
110
+ > 完读率是同一概念下的两个口径,窗口与分母均不同
111
+
112
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
113
+ |---|---|---|---|---|---|---|
114
+ | `dc7` | `finish_read_rate` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | 7 天窗口内阅读人数 | datacube 7 天窗口·阅读人数分母 |
115
+ | `ad30` | `finished_read_pv_ratio` | article_detail | 发表后 30 天窗口 | 30 | 阅读次数(pv) | 单篇页 30 天窗口·pv 分母 |
116
+
117
+ #### 阅读量(`read_volume`,单位:人次/次/人(按 series 而定))
118
+ > 三个 series 口径不同:实时累计 vs 7 天 pv vs 30 天 uv
119
+
120
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
121
+ |---|---|---|---|---|---|---|
122
+ | `pl` | `read_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | publish_list 实时累计,无窗口无去重 |
123
+ | `dc7` | `total_pv` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·全渠道阅读次数(≈量级) |
124
+ | `ad30` | `read_uv` | article_detail | 发表后 30 天窗口 | 30 | 「全部」渠道去重 | 单篇页 30 天窗口·全渠道去重阅读人数 |
125
+
126
+ #### 分享(`share`,单位:次/人(按 series 而定))
127
+
128
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
129
+ |---|---|---|---|---|---|---|
130
+ | `pl` | `share_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计分享次数 |
131
+ | `dc7` | `total_share` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·分享次数 |
132
+ | `ad30` | `share_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·分享人数 |
133
+
134
+ #### 点赞(`like`,单位:次)
135
+
136
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
137
+ |---|---|---|---|---|---|---|
138
+ | `pl` | `like_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计点赞数 |
139
+ | `ad30` | `like_cnt` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·点赞数 |
140
+
141
+ #### 在看(`wow`,单位:次)
142
+
143
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
144
+ |---|---|---|---|---|---|---|
145
+ | `ad30` | `zaikan_cnt` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·「在看」数(与点赞不同概念) |
146
+
147
+ #### 评论(`comment`,单位:条)
148
+
149
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
150
+ |---|---|---|---|---|---|---|
151
+ | `pl` | `comment_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计评论数 |
152
+ | `ad30` | `comment_cnt` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·评论数 |
153
+
154
+ #### 送达人数(`delivery`,单位:人)
155
+
156
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
157
+ |---|---|---|---|---|---|---|
158
+ | `dc7` | `send_succ` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·送达人数(分母=送达) |
159
+
160
+ #### 完读次数(`finish_count`,单位:次)
161
+
162
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
163
+ |---|---|---|---|---|---|---|
164
+ | `dc7` | `total_read_finish` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·完读次数 |
165
+
166
+ #### 阅读率(`read_rate`,单位:比例(0-1))
167
+
168
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
169
+ |---|---|---|---|---|---|---|
170
+ | `dc7` | `read_rate` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | 送达人数(send_succ) | datacube 阅读 pv / 送达 |
171
+
172
+ #### 阅读后关注人数(`follow_after_read`,单位:人)
173
+
174
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
175
+ |---|---|---|---|---|---|---|
176
+ | `ad30` | `follow_after_read_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·阅读后关注人数 |
177
+
178
+ #### 收藏人数(`collection`,单位:人)
179
+
180
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
181
+ |---|---|---|---|---|---|---|
182
+ | `ad30` | `collection_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·收藏人数 |
183
+
184
+ #### 听读人数(`listen_people`,单位:人)
185
+
186
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
187
+ |---|---|---|---|---|---|---|
188
+ | `ad30` | `listen_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·听读人数(与听读次数不同概念) |
189
+
190
+ #### 听读次数(`listen_plays`,单位:次)
191
+
192
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
193
+ |---|---|---|---|---|---|---|
194
+ | `ad30` | `listen_pv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·听读次数(与听读人数不同概念) |
195
+
196
+ #### 平均阅读时长(`avg_read_time`,单位:秒)
197
+
198
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
199
+ |---|---|---|---|---|---|---|
200
+ | `ad30` | `avg_article_read_time` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·平均阅读时长(秒) |
201
+
202
+ #### 赞赏金额(`praise_money`,单位:上游金额单位)
203
+
204
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
205
+ |---|---|---|---|---|---|---|
206
+ | `ad30` | `praise_money` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·赞赏金额 |
207
+
208
+ ### 元数据字段(非指标:快照日 / 派生列 / 结构列)
209
+
210
+ | 规范名 | 字段 | 源 | 窗口 | 类型 | 备注 |
211
+ |---|---|---|---|---|---|
212
+ | `refdate` | `refdate` | datacube_article | 发表后 7 天窗口,T+1 出数 | snapshot | 文章口径日(快照行 stat_date 是拉取日,两者不同) |
213
+ | `publish_date` | `publish_date` | article_detail | 发表后 30 天窗口 | snapshot | 单篇页 30 天窗口·文章发表日 |
214
+ | `window_days` | `window_days` | article_detail | 发表后 30 天窗口 | derived | mpdt 写入的派生列(页面固定 30 天) |
215
+ | `total_read_user` | `total_read_user` | article_detail | 发表后 30 天窗口 | derived | mpdt 派生列:「全部」渠道逐日 read_user 求和 |
216
+ | `channel_breakdown` | `channel_breakdown` | article_detail | 发表后 30 天窗口 | structured | mpdt 派生列;同一用户多渠道重复计数 → 占比之和可 >100%(仅「全部」去重) |
217
+
218
+ ### 旧版字段(保留登记;不参与对照 / 不出现在 metrics 视图)
219
+
220
+ > 旧版字段保留在注册表里是为了让 `mpdt/metrics.py` 仍能识别上游接口历史返回的字段(CSV 导出元数据 `*.metrics.csv` 会标出口径),但不参与周报对照、metrics 视图与自动配对。
221
+ - `old_like_num` → `like_num`:旧版字段(保留登记),口径与 like_num 相当
222
+
223
+ ### 自动推导的易混淆配对(同一概念多 series)
224
+
225
+ | 概念 | 不可直接比的 series 配对 | 主要差异 |
226
+ |---|---|---|
227
+ | 完读率(`read_completion`,1 对) | `dc7` vs `ad30` | 分母、窗口 |
228
+ | 阅读量(`read_volume`,3 对) | `pl` vs `dc7`;`pl` vs `ad30`;`dc7` vs `ad30` | 分母、窗口 |
229
+ | 分享(`share`,3 对) | `pl` vs `dc7`;`pl` vs `ad30`;`dc7` vs `ad30` | 窗口 |
230
+ | 点赞(`like`,1 对) | `pl` vs `ad30` | 窗口 |
231
+ | 评论(`comment`,1 对) | `pl` vs `ad30` | 窗口 |
232
+
233
+ > 本节由 `mpdt/metrics.py` CONCEPTS 自动生成(`python3 -c "from mpdt.metrics import readme_section; print(readme_section())"`)。改口径请改 CONCEPTS,再运行 `mpdt metrics` 校对。
234
+
235
+ ## FAQ
236
+
237
+ - **fetch 提示「该日期范围无数据」**:不是错误(退出码 0)。datacube 为 T+1 口径,当天数据明天可得。
238
+ - **退出码 3(AuthError)**:CDP 9222 上没有已登录的 mp.weixin 标签页——回 Quick Start ① 检查 Chrome 参数与登录态。
239
+ - **退出码 4(UpstreamError)**:微信接口返回了未识别结构——错误信息附原始返回片段,提 issue 时请一并贴出。
240
+ - **换机器 / 重置**:删除 `~/.mpdt/` 后重跑 `mpdt init`。数据库与配置都在该目录(除非 `--db` 另指定)。
241
+ - **会碰我的 Chrome 吗**:只通过 CDP 读取已登录标签页的 URL 与发起后台 API 请求,不注入脚本、不改动页面。
242
+
243
+ ## 文档
244
+
245
+ - [需求背景](docs/requirements.md)
246
+ - [产品需求(PRD)](docs/product-requirements.md)
247
+ - [技术设计](docs/technical-design.md)
248
+ - [冷启动记录](docs/coldstart.md)
249
+ - 答疑:[提 issue](https://github.com/ttxs69/mpdt/issues)
250
+
251
+ ## 边界与合规
252
+
253
+ - 只读取**你自己**公众号后台的数据;不提供任何刷量 / 代抓他人数据能力
254
+ - 自动化访问后台属微信 ToS 灰色地带,本项目仅限个人备份分析用途,风险自担
255
+
256
+ ## License
257
+
258
+ [MIT](LICENSE) © ttxs69
mpdt-0.2.0/README.md ADDED
@@ -0,0 +1,236 @@
1
+ # mpdt — 公众号运营数据,抓回本机,一键周报
2
+
3
+ > WeChat Official Account analytics, fully local — fetch, store, and report your own data via one CLI.
4
+
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)]()
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)]()
7
+ [![CI](https://github.com/ttxs69/mpdt/actions/workflows/tests.yml/badge.svg)](https://github.com/ttxs69/mpdt/actions/workflows/tests.yml)
8
+ [![Tests](https://img.shields.io/badge/tests-98%20passing-brightgreen)]()
9
+ [![Dependencies](https://img.shields.io/badge/dependencies-requests%20%2B%20websocket--client-orange)]()
10
+
11
+ 公众号后台(mp.weixin.qq.com)的运营数据散落在三个页面,官方不提供导出,mpdt 把它们自动抓回本机 SQLite,并生成 Markdown 周报:
12
+
13
+ - **发表列表**:阅读 / 分享 / 点赞 / 评论(实时累计口径)
14
+ - **datacube 文章级**:完读率 / 阅读率 / 送达 pv(发表后 7 天窗口,T+1)
15
+ - **单篇渠道页**:逐篇阅读人数、完读率、平均时长、渠道构成(推荐 / 搜一搜 / 公众号消息…,30 天窗口)
16
+
17
+ ## 为什么做这个
18
+
19
+ - **官方不提供导出**:后台数据只能一屏一屏翻页看,换设备、离职交接、跨年对比都无从下手
20
+ - **商业工具 ¥99/月起**:第三方 SaaS 要么按月收费,要么要求交出账号托管,个人号主用不起也不敢用
21
+ - **个人号主被忽视**:官方与商业工具都面向机构运营团队,一个人打理的号缺少趁手的本地工具
22
+
23
+ mpdt 的答案:**数据 100% 留在本机**(SQLite + 本地文件),复用你已登录的 Chrome,不托管、不上传、不收费。
24
+
25
+ > ⚠️ **口径警告**:三源同名指标口径不同(统计窗口 / 分母各异)——发表列表是实时累计,datacube 是发表后 7 天窗口 T+1,单篇渠道页是 30 天窗口。**跨源比较前先对齐口径**,周报文首附完整口径说明。
26
+
27
+ ## 特性
28
+
29
+ - **零扫码**:复用本机已登录 Chrome 的登录态(CDP 远程调试),token 从页面 URL 自动刷新
30
+ - **全本地**:数据只存本机 SQLite(`~/.mpdt/mpdt.sqlite3`),凭据文件 600 权限、打印永不回显
31
+ - **幂等**:同一天重复抓取 upsert 不重复;`log_run` 记录每次运行
32
+ - **礼貌限速**:请求间隔 ≥ 1s
33
+ - **错误语义明确**:退出码 `0` 成功(含空数据)|`2` 配置问题|`3` 凭据/登录态问题|`4` 上游接口异常(附原始返回片段)|`130` 用户中断(幂等设计,重跑安全)
34
+ - **机器可读输出**:全局 `--json` 参数——stdout 恰好一行 JSON(`{ok, cmd, data, meta}`),适合脚本/管道串联
35
+ - **非交互友好**:stdout 非 TTY(管道 / 重定向 / cron)时自动静默过程输出
36
+ - **零框架测试**:98 个 unittest,零第三方测试依赖,`python3 tests/test_fetchers.py` 直跑
37
+
38
+ ## 安装
39
+
40
+ ```bash
41
+ # 推荐:pip 安装
42
+ pip install git+https://github.com/ttxs69/mpdt.git
43
+
44
+ # 或本地安装
45
+ git clone https://github.com/ttxs69/mpdt.git
46
+ cd mpdt && pip install .
47
+ ```
48
+
49
+ > 未安装到环境时,`python3 -m mpdt` 与 `mpdt` 命令完全等价——从仓库根目录直接运行即可。
50
+
51
+ 依赖:Python 3.10+、`requests`、`websocket-client`(其余全标准库)。
52
+
53
+ ## Quick Start(30 秒)
54
+
55
+ ```bash
56
+ # ① 以调试端口启动 Chrome 并登录公众号后台
57
+ google-chrome --remote-debugging-port=9222
58
+ # 打开 https://mp.weixin.qq.com 扫码登录,保持该标签页存在
59
+
60
+ # ② 初始化配置(生成 ~/.mpdt/config.json,600 权限)
61
+ mpdt init
62
+
63
+ # ③ 抓数据 → 出周报
64
+ mpdt fetch --backfill 7 # 抓最近 7 天(默认仅昨天,T+1 口径)
65
+ mpdt detail --recent 7 # 单篇渠道构成(最近 7 天发表的)
66
+ mpdt report # → mpdt-reports/weekly-YYYY-Www.md
67
+ ```
68
+
69
+ > 已在跑的 Chrome 需先完全退出再用该参数重启;介意隔离可用独立 profile:
70
+ > `--user-data-dir=/tmp/mpdt-chrome --remote-debugging-port=9222`
71
+
72
+ ## 命令一览
73
+
74
+ | 命令 | 作用 | 常用参数 |
75
+ |---|---|---|
76
+ | `mpdt init` | 生成配置 | `--db PATH` 自定义数据库位置 |
77
+ | `mpdt fetch` | 发表列表 + datacube 文章级快照 | `--backfill N` / `--from/--to YYYY-MM-DD` / `--count N` |
78
+ | `mpdt detail` | 单篇渠道页(完读率 + 渠道构成) | `--recent N`,或 `--msgid ID --publish-date D [--item-idx 1]` |
79
+ | `mpdt report` | 生成周报 Markdown + HTML | `--week 2026-W42` |
80
+ | `mpdt export` | 导出快照 CSV(附口径元数据 `*.metrics.csv`) | `--source SOURCE --out OUT`(`--no-meta` 关闭伴随文件) |
81
+ | `mpdt metrics` | 列出全部指标及口径(按概念分组) | 可选位置参数按 概念名/显示名/源/字段 子串过滤 |
82
+
83
+ 所有命令支持全局 `--json`(stdout 恰好一行 JSON)。
84
+
85
+ ## 指标口径(CONCEPTS · 按概念分组)
86
+
87
+ #### 完读率(`read_completion`,单位:比例(0-1))
88
+ > 完读率是同一概念下的两个口径,窗口与分母均不同
89
+
90
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
91
+ |---|---|---|---|---|---|---|
92
+ | `dc7` | `finish_read_rate` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | 7 天窗口内阅读人数 | datacube 7 天窗口·阅读人数分母 |
93
+ | `ad30` | `finished_read_pv_ratio` | article_detail | 发表后 30 天窗口 | 30 | 阅读次数(pv) | 单篇页 30 天窗口·pv 分母 |
94
+
95
+ #### 阅读量(`read_volume`,单位:人次/次/人(按 series 而定))
96
+ > 三个 series 口径不同:实时累计 vs 7 天 pv vs 30 天 uv
97
+
98
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
99
+ |---|---|---|---|---|---|---|
100
+ | `pl` | `read_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | publish_list 实时累计,无窗口无去重 |
101
+ | `dc7` | `total_pv` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·全渠道阅读次数(≈量级) |
102
+ | `ad30` | `read_uv` | article_detail | 发表后 30 天窗口 | 30 | 「全部」渠道去重 | 单篇页 30 天窗口·全渠道去重阅读人数 |
103
+
104
+ #### 分享(`share`,单位:次/人(按 series 而定))
105
+
106
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
107
+ |---|---|---|---|---|---|---|
108
+ | `pl` | `share_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计分享次数 |
109
+ | `dc7` | `total_share` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·分享次数 |
110
+ | `ad30` | `share_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·分享人数 |
111
+
112
+ #### 点赞(`like`,单位:次)
113
+
114
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
115
+ |---|---|---|---|---|---|---|
116
+ | `pl` | `like_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计点赞数 |
117
+ | `ad30` | `like_cnt` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·点赞数 |
118
+
119
+ #### 在看(`wow`,单位:次)
120
+
121
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
122
+ |---|---|---|---|---|---|---|
123
+ | `ad30` | `zaikan_cnt` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·「在看」数(与点赞不同概念) |
124
+
125
+ #### 评论(`comment`,单位:条)
126
+
127
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
128
+ |---|---|---|---|---|---|---|
129
+ | `pl` | `comment_num` | publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计评论数 |
130
+ | `ad30` | `comment_cnt` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·评论数 |
131
+
132
+ #### 送达人数(`delivery`,单位:人)
133
+
134
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
135
+ |---|---|---|---|---|---|---|
136
+ | `dc7` | `send_succ` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·送达人数(分母=送达) |
137
+
138
+ #### 完读次数(`finish_count`,单位:次)
139
+
140
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
141
+ |---|---|---|---|---|---|---|
142
+ | `dc7` | `total_read_finish` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·完读次数 |
143
+
144
+ #### 阅读率(`read_rate`,单位:比例(0-1))
145
+
146
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
147
+ |---|---|---|---|---|---|---|
148
+ | `dc7` | `read_rate` | datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | 送达人数(send_succ) | datacube 阅读 pv / 送达 |
149
+
150
+ #### 阅读后关注人数(`follow_after_read`,单位:人)
151
+
152
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
153
+ |---|---|---|---|---|---|---|
154
+ | `ad30` | `follow_after_read_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·阅读后关注人数 |
155
+
156
+ #### 收藏人数(`collection`,单位:人)
157
+
158
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
159
+ |---|---|---|---|---|---|---|
160
+ | `ad30` | `collection_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·收藏人数 |
161
+
162
+ #### 听读人数(`listen_people`,单位:人)
163
+
164
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
165
+ |---|---|---|---|---|---|---|
166
+ | `ad30` | `listen_uv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·听读人数(与听读次数不同概念) |
167
+
168
+ #### 听读次数(`listen_plays`,单位:次)
169
+
170
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
171
+ |---|---|---|---|---|---|---|
172
+ | `ad30` | `listen_pv` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·听读次数(与听读人数不同概念) |
173
+
174
+ #### 平均阅读时长(`avg_read_time`,单位:秒)
175
+
176
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
177
+ |---|---|---|---|---|---|---|
178
+ | `ad30` | `avg_article_read_time` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·平均阅读时长(秒) |
179
+
180
+ #### 赞赏金额(`praise_money`,单位:上游金额单位)
181
+
182
+ | series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
183
+ |---|---|---|---|---|---|---|
184
+ | `ad30` | `praise_money` | article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·赞赏金额 |
185
+
186
+ ### 元数据字段(非指标:快照日 / 派生列 / 结构列)
187
+
188
+ | 规范名 | 字段 | 源 | 窗口 | 类型 | 备注 |
189
+ |---|---|---|---|---|---|
190
+ | `refdate` | `refdate` | datacube_article | 发表后 7 天窗口,T+1 出数 | snapshot | 文章口径日(快照行 stat_date 是拉取日,两者不同) |
191
+ | `publish_date` | `publish_date` | article_detail | 发表后 30 天窗口 | snapshot | 单篇页 30 天窗口·文章发表日 |
192
+ | `window_days` | `window_days` | article_detail | 发表后 30 天窗口 | derived | mpdt 写入的派生列(页面固定 30 天) |
193
+ | `total_read_user` | `total_read_user` | article_detail | 发表后 30 天窗口 | derived | mpdt 派生列:「全部」渠道逐日 read_user 求和 |
194
+ | `channel_breakdown` | `channel_breakdown` | article_detail | 发表后 30 天窗口 | structured | mpdt 派生列;同一用户多渠道重复计数 → 占比之和可 >100%(仅「全部」去重) |
195
+
196
+ ### 旧版字段(保留登记;不参与对照 / 不出现在 metrics 视图)
197
+
198
+ > 旧版字段保留在注册表里是为了让 `mpdt/metrics.py` 仍能识别上游接口历史返回的字段(CSV 导出元数据 `*.metrics.csv` 会标出口径),但不参与周报对照、metrics 视图与自动配对。
199
+ - `old_like_num` → `like_num`:旧版字段(保留登记),口径与 like_num 相当
200
+
201
+ ### 自动推导的易混淆配对(同一概念多 series)
202
+
203
+ | 概念 | 不可直接比的 series 配对 | 主要差异 |
204
+ |---|---|---|
205
+ | 完读率(`read_completion`,1 对) | `dc7` vs `ad30` | 分母、窗口 |
206
+ | 阅读量(`read_volume`,3 对) | `pl` vs `dc7`;`pl` vs `ad30`;`dc7` vs `ad30` | 分母、窗口 |
207
+ | 分享(`share`,3 对) | `pl` vs `dc7`;`pl` vs `ad30`;`dc7` vs `ad30` | 窗口 |
208
+ | 点赞(`like`,1 对) | `pl` vs `ad30` | 窗口 |
209
+ | 评论(`comment`,1 对) | `pl` vs `ad30` | 窗口 |
210
+
211
+ > 本节由 `mpdt/metrics.py` CONCEPTS 自动生成(`python3 -c "from mpdt.metrics import readme_section; print(readme_section())"`)。改口径请改 CONCEPTS,再运行 `mpdt metrics` 校对。
212
+
213
+ ## FAQ
214
+
215
+ - **fetch 提示「该日期范围无数据」**:不是错误(退出码 0)。datacube 为 T+1 口径,当天数据明天可得。
216
+ - **退出码 3(AuthError)**:CDP 9222 上没有已登录的 mp.weixin 标签页——回 Quick Start ① 检查 Chrome 参数与登录态。
217
+ - **退出码 4(UpstreamError)**:微信接口返回了未识别结构——错误信息附原始返回片段,提 issue 时请一并贴出。
218
+ - **换机器 / 重置**:删除 `~/.mpdt/` 后重跑 `mpdt init`。数据库与配置都在该目录(除非 `--db` 另指定)。
219
+ - **会碰我的 Chrome 吗**:只通过 CDP 读取已登录标签页的 URL 与发起后台 API 请求,不注入脚本、不改动页面。
220
+
221
+ ## 文档
222
+
223
+ - [需求背景](docs/requirements.md)
224
+ - [产品需求(PRD)](docs/product-requirements.md)
225
+ - [技术设计](docs/technical-design.md)
226
+ - [冷启动记录](docs/coldstart.md)
227
+ - 答疑:[提 issue](https://github.com/ttxs69/mpdt/issues)
228
+
229
+ ## 边界与合规
230
+
231
+ - 只读取**你自己**公众号后台的数据;不提供任何刷量 / 代抓他人数据能力
232
+ - 自动化访问后台属微信 ToS 灰色地带,本项目仅限个人备份分析用途,风险自担
233
+
234
+ ## License
235
+
236
+ [MIT](LICENSE) © ttxs69
@@ -0,0 +1,9 @@
1
+ """mpdt — 公众号运营数据自动化工具(C1 / mp-data-tool)
2
+
3
+ 错误语义(FR6/T1 三态分离):
4
+ 0 成功(含"该日期范围无数据")
5
+ 2 配置问题(未 init / 配置缺失)
6
+ 3 凭据问题(token 刷新失败)
7
+ 4 上游接口异常(结构变更,含原始返回片段)
8
+ """
9
+ __version__ = '0.2.0'
@@ -0,0 +1,7 @@
1
+ """python3 -m mpdt <子命令> 入口(等价于 python3 -c 'from mpdt.cli import main; ...')。"""
2
+ import sys
3
+
4
+ from .cli import main
5
+
6
+ if __name__ == '__main__':
7
+ sys.exit(main())