mpdt — 公众号运营数据,抓回本机,一键周报
WeChat Official Account analytics, fully local — fetch, store, and report your own data via one CLI.
公众号后台(mp.weixin.qq.com)的运营数据散落在三个页面,官方不提供导出,mpdt 把它们自动抓回本机 SQLite,并生成 Markdown 周报:
- 发表列表:阅读 / 分享 / 点赞 / 评论(实时累计口径)
- datacube 文章级:完读率 / 阅读率 / 送达 pv(发表后 7 天窗口,T+1)
- 单篇渠道页:逐篇阅读人数、完读率、平均时长、渠道构成(推荐 / 搜一搜 / 公众号消息…,30 天窗口)
为什么做这个
- 官方不提供导出:后台数据只能一屏一屏翻页看,换设备、离职交接、跨年对比都无从下手
- 商业工具 ¥99/月起:第三方 SaaS 要么按月收费,要么要求交出账号托管,个人号主用不起也不敢用
- 个人号主被忽视:官方与商业工具都面向机构运营团队,一个人打理的号缺少趁手的本地工具
mpdt 的答案:数据 100% 留在本机(SQLite + 本地文件),复用你已登录的 Chrome,不托管、不上传、不收费。
⚠️ 口径警告:三源同名指标口径不同(统计窗口 / 分母各异)——发表列表是实时累计,datacube 是发表后 7 天窗口 T+1,单篇渠道页是 30 天窗口。跨源比较前先对齐口径,周报文首附完整口径说明。
特性
- 零扫码:复用本机已登录 Chrome 的登录态(CDP 远程调试),token 从页面 URL 自动刷新
- 全本地:数据只存本机 SQLite(
~/.mpdt/mpdt.sqlite3),凭据文件 600 权限、打印永不回显 - 幂等:同一天重复抓取 upsert 不重复;
log_run记录每次运行 - 礼貌限速:请求间隔 ≥ 1s
- 错误语义明确:退出码
0成功(含空数据)|2配置问题|3凭据/登录态问题|4上游接口异常(附原始返回片段)|130用户中断(幂等设计,重跑安全) - 机器可读输出:全局
--json参数——stdout 恰好一行 JSON({ok, cmd, data, meta}),适合脚本/管道串联 - 非交互友好:stdout 非 TTY(管道 / 重定向 / cron)时自动静默过程输出
- 零框架测试:98 个 unittest,零第三方测试依赖,
python3 tests/test_fetchers.py直跑
安装
# 推荐:pip 安装
pip install mpdt
# 或本地安装
git clone https://github.com/ttxs69/mpdt.git
cd mpdt && pip install .
未安装到环境时,
python3 -m mpdt与mpdt命令完全等价——从仓库根目录直接运行即可。
依赖:Python 3.10+、requests、websocket-client(其余全标准库)。
Quick Start(30 秒)
# ① 以调试端口启动 Chrome 并登录公众号后台
google-chrome --remote-debugging-port=9222
# 打开 https://mp.weixin.qq.com 扫码登录,保持该标签页存在
# ② 初始化配置(生成 ~/.mpdt/config.json,600 权限)
mpdt init
# ③ 抓数据 → 出周报
mpdt fetch --backfill 7 # 抓最近 7 天(默认仅昨天,T+1 口径)
mpdt detail --recent 7 # 单篇渠道构成(最近 7 天发表的)
mpdt report # → mpdt-reports/weekly-YYYY-Www.md
已在跑的 Chrome 需先完全退出再用该参数重启;介意隔离可用独立 profile:
--user-data-dir=/tmp/mpdt-chrome --remote-debugging-port=9222
命令一览
| 命令 | 作用 | 常用参数 |
|---|---|---|
mpdt init |
生成配置 | --db PATH 自定义数据库位置 |
mpdt fetch |
发表列表 + datacube 文章级快照 | --backfill N / --from/--to YYYY-MM-DD / --count N |
mpdt detail |
单篇渠道页(完读率 + 渠道构成) | --recent N,或 --msgid ID --publish-date D [--item-idx 1] |
mpdt report |
生成周报 Markdown + HTML | --week 2026-W42 |
mpdt export |
导出快照 CSV(附口径元数据 *.metrics.csv) |
--source SOURCE --out OUT(--no-meta 关闭伴随文件) |
mpdt metrics |
列出全部指标及口径(按概念分组) | 可选位置参数按 概念名/显示名/源/字段 子串过滤 |
所有命令支持全局 --json(stdout 恰好一行 JSON)。
指标口径(CONCEPTS · 按概念分组)
完读率(read_completion,单位:比例(0-1))
完读率是同一概念下的两个口径,窗口与分母均不同
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
dc7 |
finish_read_rate |
datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | 7 天窗口内阅读人数 | datacube 7 天窗口·阅读人数分母 |
ad30 |
finished_read_pv_ratio |
article_detail | 发表后 30 天窗口 | 30 | 阅读次数(pv) | 单篇页 30 天窗口·pv 分母 |
阅读量(read_volume,单位:人次/次/人(按 series 而定))
三个 series 口径不同:实时累计 vs 7 天 pv vs 30 天 uv
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
pl |
read_num |
publish_list | 实时累计(拉取时点全量) | 0 | - | publish_list 实时累计,无窗口无去重 |
dc7 |
total_pv |
datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·全渠道阅读次数(≈量级) |
ad30 |
read_uv |
article_detail | 发表后 30 天窗口 | 30 | 「全部」渠道去重 | 单篇页 30 天窗口·全渠道去重阅读人数 |
分享(share,单位:次/人(按 series 而定))
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
pl |
share_num |
publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计分享次数 |
dc7 |
total_share |
datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·分享次数 |
ad30 |
share_uv |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·分享人数 |
点赞(like,单位:次)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
pl |
like_num |
publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计点赞数 |
ad30 |
like_cnt |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·点赞数 |
在看(wow,单位:次)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
ad30 |
zaikan_cnt |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·「在看」数(与点赞不同概念) |
评论(comment,单位:条)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
pl |
comment_num |
publish_list | 实时累计(拉取时点全量) | 0 | - | 实时累计评论数 |
ad30 |
comment_cnt |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·评论数 |
送达人数(delivery,单位:人)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
dc7 |
send_succ |
datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·送达人数(分母=送达) |
完读次数(finish_count,单位:次)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
dc7 |
total_read_finish |
datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | - | datacube 7 天窗口·完读次数 |
阅读率(read_rate,单位:比例(0-1))
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
dc7 |
read_rate |
datacube_article | 发表后 7 天窗口,T+1 出数 | 7 | 送达人数(send_succ) | datacube 阅读 pv / 送达 |
阅读后关注人数(follow_after_read,单位:人)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
ad30 |
follow_after_read_uv |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·阅读后关注人数 |
收藏人数(collection,单位:人)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
ad30 |
collection_uv |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·收藏人数 |
听读人数(listen_people,单位:人)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
ad30 |
listen_uv |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·听读人数(与听读次数不同概念) |
听读次数(listen_plays,单位:次)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
ad30 |
listen_pv |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·听读次数(与听读人数不同概念) |
平均阅读时长(avg_read_time,单位:秒)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
ad30 |
avg_article_read_time |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·平均阅读时长(秒) |
赞赏金额(praise_money,单位:上游金额单位)
| series_key | 源字段 | 所属源 | 窗口 | 窗口天数 | 分母 | 备注 |
|---|---|---|---|---|---|---|
ad30 |
praise_money |
article_detail | 发表后 30 天窗口 | 30 | - | 单篇页 30 天窗口·赞赏金额 |
元数据字段(非指标:快照日 / 派生列 / 结构列)
| 规范名 | 字段 | 源 | 窗口 | 类型 | 备注 |
|---|---|---|---|---|---|
refdate |
refdate |
datacube_article | 发表后 7 天窗口,T+1 出数 | snapshot | 文章口径日(快照行 stat_date 是拉取日,两者不同) |
publish_date |
publish_date |
article_detail | 发表后 30 天窗口 | snapshot | 单篇页 30 天窗口·文章发表日 |
window_days |
window_days |
article_detail | 发表后 30 天窗口 | derived | mpdt 写入的派生列(页面固定 30 天) |
total_read_user |
total_read_user |
article_detail | 发表后 30 天窗口 | derived | mpdt 派生列:「全部」渠道逐日 read_user 求和 |
channel_breakdown |
channel_breakdown |
article_detail | 发表后 30 天窗口 | structured | mpdt 派生列;同一用户多渠道重复计数 → 占比之和可 >100%(仅「全部」去重) |
旧版字段(保留登记;不参与对照 / 不出现在 metrics 视图)
旧版字段保留在注册表里是为了让
mpdt/metrics.py仍能识别上游接口历史返回的字段(CSV 导出元数据*.metrics.csv会标出口径),但不参与周报对照、metrics 视图与自动配对。
old_like_num→like_num:旧版字段(保留登记),口径与 like_num 相当
自动推导的易混淆配对(同一概念多 series)
| 概念 | 不可直接比的 series 配对 | 主要差异 |
|---|---|---|
完读率(read_completion,1 对) |
dc7 vs ad30 |
分母、窗口 |
阅读量(read_volume,3 对) |
pl vs dc7;pl vs ad30;dc7 vs ad30 |
分母、窗口 |
分享(share,3 对) |
pl vs dc7;pl vs ad30;dc7 vs ad30 |
窗口 |
点赞(like,1 对) |
pl vs ad30 |
窗口 |
评论(comment,1 对) |
pl vs ad30 |
窗口 |
本节由
mpdt/metrics.pyCONCEPTS 自动生成(python3 -c "from mpdt.metrics import readme_section; print(readme_section())")。改口径请改 CONCEPTS,再运行mpdt metrics校对。
FAQ
- fetch 提示「该日期范围无数据」:不是错误(退出码 0)。datacube 为 T+1 口径,当天数据明天可得。
- 退出码 3(AuthError):CDP 9222 上没有已登录的 mp.weixin 标签页——回 Quick Start ① 检查 Chrome 参数与登录态。
- 退出码 4(UpstreamError):微信接口返回了未识别结构——错误信息附原始返回片段,提 issue 时请一并贴出。
- 换机器 / 重置:删除
~/.mpdt/后重跑mpdt init。数据库与配置都在该目录(除非--db另指定)。 - 会碰我的 Chrome 吗:只通过 CDP 读取已登录标签页的 URL 与发起后台 API 请求,不注入脚本、不改动页面。
文档
边界与合规
- 只读取你自己公众号后台的数据;不提供任何刷量 / 代抓他人数据能力
- 自动化访问后台属微信 ToS 灰色地带,本项目仅限个人备份分析用途,风险自担
License
MIT © ttxs69
Metadata
Release files for mpdt 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mpdt-0.2.1.tar.gz | 68.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mpdt-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 115.2 kB
Release files / mpdt-0.2.1.tar.gz
| Download URL | mpdt-0.2.1.tar.gz |
|---|---|
| Size | 68.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ba119e92f3debcef229a2704301a28e05bf0c1a2d91a3c9cc9bc665568625bf3
|
|
BLAKE2b-256 checksum How to use checksums |
0d951057cb203776ba2c2cacf332a7d7c87c46178512a7c49f578f073c09ed0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / mpdt-0.2.1-py3-none-any.whl
| Download URL | mpdt-0.2.1-py3-none-any.whl |
|---|---|
| Size | 46.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
26667f9ea029b75333a94483a1ba1ffc8da550f4560d98afd6cceb18dad6b133
|
|
BLAKE2b-256 checksum How to use checksums |
4afb6dbc5c283e39eb30f52695d231e543094f50b28fe619430aad970cd96ae4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for mpdt 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.