soakes/telegram-message-exporter
GitHub: soakes/telegram-message-exporter
专为 macOS 原生 Telegram 客户端设计的离线消息恢复与导出工具,解密本地 SQLCipher 数据库并将聊天记录输出为 HTML、Markdown 或 CSV 格式。
Stars: 18 | Forks: 0
# 💬 Telegram for macOS 消息导出工具
[](https://github.com/soakes/telegram-message-exporter/actions/workflows/ci.yml)
[](https://www.python.org/downloads/)
[](#requirements)
[](https://macos.telegram.org/)
[](LICENSE)
[](https://black.readthedocs.io/)
[](https://docs.astral.sh/ruff/)
[](https://pylint.readthedocs.io/)
专为以下恢复场景构建:当 Telegram 对话仅存的最后副本是 Mac 上的加密本地缓存时。该工具会解密本地 `db_sqlite`,充分解析 Telegram 的 Postbox 存储以查找对话者和消息,然后将可读的聊天记录输出为 HTML、Markdown 或 CSV 格式。
本项目针对的是来自 [macos.telegram.org](https://macos.telegram.org/) 或 Homebrew `telegram` cask 的**原生 Telegram for macOS 应用**。它**不**适用于跨平台的 Telegram Desktop/Qt 应用、iOS 备份、Android 备份、Mac App Store 版本或 Telegram 云端导出格式。
**快速链接:** [🚀 快速开始](#quick-start) · [🔄 工作原理](#how-it-works) · [🧪 用法](#usage) · [🧰 CLI 参考](#cli-reference) · [🩺 故障排除](#troubleshooting) · [🙏 致谢](#credits)
## 🧭 目录
- [📖 概述](#overview)
- [✨ 功能特性](#capabilities)
- [🔄 工作原理](#how-it-works)
- [✅ 系统要求](#requirements)
- [🚀 快速开始](#quick-start)
- [🧪 用法](#usage)
- [🧰 CLI 参考](#cli-reference)
- [📄 输出格式](#output-formats)
- [🗺️ 关键路径](#key-paths)
- [🔐 安全与隐私](#safety-and-privacy)
- [🩺 故障排除](#troubleshooting)
- [⚠️ 限制](#limitations)
- [❓ 常见问题](#faq)
- [🔖 版本控制](#versioning)
- [🧹 质量检查](#quality-checks)
- [🗂️ 项目结构](#project-structure)
- [🙏 致谢](#credits)
- [🤝 贡献](#contributing)
- [📄 许可证](#license)
## 📖 概述
Telegram for macOS 将本地消息数据存储在一个加密的 SQLite 数据库中。当聊天记录从 Telegram 的云端状态中被删除时,只要本地缓存仍然存在于磁盘上且未被覆盖或同步清除,它就可能成为最后有用的证据来源。
`telegram-message-exporter` 提供了一条专注的恢复路径:
- 使用 `.tempkeyEncrypted` 解密本地 SQLCipher 数据库
- 检查解密后的纯文本 SQLite 副本
- 列出可能的对话者和联系人
- 将单个聊天或所有已解码的消息导出为整洁的聊天记录
该工具完全是离线的。它不会调用 Telegram API,不会将消息恢复回 Telegram,也不会将恢复的数据上传到任何地方。
### 首次恢复检查清单
1. 尽快停止在 Mac 上使用 Telegram。
2. 如果您试图保留最近删除的聊天记录,请保持 Mac 处于离线状态。
3. 在进行实验之前,将 Telegram 密钥和数据库复制到一个单独的工作目录中。
4. 在虚拟环境中安装该工具。
5. 解密至 `plaintext.db`。
6. 运行 `list-peers` 以查找您关心的聊天。
7. 优先导出 HTML 以供阅读,如果您需要在电子表格中进行分析,则导出 CSV。
8. 安全地存储 `plaintext.db` 和聊天记录文件;它们包含私人消息内容。
## ✨ 功能特性
- **离线解密**:从 Telegram 本地的 `.tempkeyEncrypted` 文件派生 SQLCipher 密钥
- **密码支持**:当启用 Telegram 密码锁时,接受 `--passcode` 或 `TG_LOCAL_PASSCODE`
- **Postbox 解析**:处理原生 macOS 应用的键/值 Postbox 表
- **对话者发现**:搜索本地对话者记录,以便在导出时尽可能使用名称代替原始 ID
- **定向导出**:按对话者 ID、联系人姓名、消息限制、开始日期和结束日期进行过滤
- **可读输出**:写入带有时间戳、发送者、消息方向和链接处理的带样式的 HTML、Markdown 或 CSV 文件
- **诊断功能**:当 Telegram 存储发生更改或缓存与预期结构不匹配时,对表和行进行采样
## 🔄 工作原理
正常的恢复流程分为两个阶段:解密数据库,然后从纯文本副本中导出。
```
flowchart TD
A[Native Telegram for macOS data] --> B[.tempkeyEncrypted]
A --> C[account-*/postbox/db/db_sqlite]
B --> D[telegram-exporter decrypt]
C --> D
D --> E[plaintext.db]
E --> F[list-peers]
E --> G[diagnose]
F --> H[export --peer-id or --contact]
G --> H
H --> I[HTML transcript]
H --> J[Markdown transcript]
H --> K[CSV dataset]
```
CLI 不需要 Telegram 网络访问权限。所有数据都来自 Mac 上已存在的本地文件。
```
sequenceDiagram
participant User
participant CLI as telegram-exporter
participant Key as .tempkeyEncrypted
participant DB as db_sqlite
participant Plain as plaintext.db
participant Out as transcript file
User->>CLI: decrypt --key --db --out plaintext.db
CLI->>Key: derive local key candidates
CLI->>DB: open encrypted SQLCipher database
CLI->>Plain: write plaintext SQLite copy
User->>CLI: list-peers --db plaintext.db
CLI->>Plain: inspect peer records
User->>CLI: export --db plaintext.db --peer-id ...
CLI->>Plain: parse messages and peer map
CLI->>Out: render HTML, Markdown, or CSV
```
## ✅ 系统要求
- 存在原生 Telegram for macOS 数据的 macOS 系统
- Python 3.10 或更高版本
- 支持 `sqlcipher3` Python 包的 SQLCipher
- Telegram 本地密码(如果启用了密码锁)
- 用于本地安装的虚拟环境
在 macOS 上,如果 `sqlcipher3` 构建失败,请先安装 SQLCipher:
```
brew install sqlcipher
```
## 🚀 快速开始
### 1. 安装
通过克隆仓库安装:
```
git clone https://github.com/soakes/telegram-message-exporter.git
cd telegram-message-exporter
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
```
或直接从 GitHub 安装最新版本:
```
pip install -U "git+https://github.com/soakes/telegram-message-exporter.git"
```
### 2. 定位 Telegram 数据库
原生 macOS 应用通常将其数据存储在以下路径下:
```
TELEGRAM_STABLE="$HOME/Library/Group Containers/6N38VWS5BX.ru.keepcoder.Telegram/stable"
ls -la "$TELEGRAM_STABLE"
ls "$TELEGRAM_STABLE"/account-*/postbox/db/db_sqlite
```
您需要:
- `.tempkeyEncrypted`,因为它以 `.` 开头,所以在普通的 `ls` 命令下是隐藏的
- 匹配的 `account-*/postbox/db/db_sqlite`
### 3. 解密到工作副本
```
telegram-exporter decrypt \
--key "$HOME/Library/Group Containers/6N38VWS5BX.ru.keepcoder.Telegram/stable/.tempkeyEncrypted" \
--db "$HOME/Library/Group Containers/6N38VWS5BX.ru.keepcoder.Telegram/stable/account-123456/postbox/db/db_sqlite" \
--out recovery/plaintext.db
```
如果启用了 Telegram 密码锁:
```
TG_LOCAL_PASSCODE="your-passcode" \
telegram-exporter decrypt \
--key "$HOME/Library/Group Containers/6N38VWS5BX.ru.keepcoder.Telegram/stable/.tempkeyEncrypted" \
--db "$HOME/Library/Group Containers/6N38VWS5BX.ru.keepcoder.Telegram/stable/account-123456/postbox/db/db_sqlite" \
--out recovery/plaintext.db
```
### 4. 查找对话者
```
telegram-exporter list-peers --db recovery/plaintext.db --search "Alex"
```
### 5. 导出聊天记录
```
telegram-exporter export \
--db recovery/plaintext.db \
--peer-id 123456789 \
--me-name "Me" \
--format html \
--out recovery/alex.html
```
## 🧪 用法
### 导出单个聊天的 HTML
```
telegram-exporter export \
--db recovery/plaintext.db \
--peer-id 123456789 \
--format html \
--me-name "Me" \
--out recovery/chat.html
```
### 按联系人姓名导出
```
telegram-exporter export \
--db recovery/plaintext.db \
--contact "Alex" \
--format md \
--out recovery/alex.md
```
如果匹配到多个对话者,命令将打印候选列表,并要求您使用 `--peer-id` 重新运行。
### 导出日期范围
```
telegram-exporter export \
--db recovery/plaintext.db \
--peer-id 123456789 \
--start-date 2024-01-01 \
--end-date 2024-12-31 \
--format html \
--out recovery/chat-2024.html
```
### 导出所有已解码消息
```
telegram-exporter export \
--db recovery/plaintext.db \
--format csv \
--out recovery/all-chats.csv
```
### 检查未知数据库
```
telegram-exporter diagnose --db recovery/plaintext.db
```
采样特定表:
```
telegram-exporter diagnose --db recovery/plaintext.db --table t7
```
### 调试解密
```
telegram-exporter decrypt \
--key /path/to/.tempkeyEncrypted \
--db /path/to/db_sqlite \
--out recovery/plaintext.db \
--debug
```
## 🧰 CLI 参考
| 命令 | 用途 |
| --- | --- |
| `decrypt` | 将 Telegram 加密的 `db_sqlite` 解密为纯文本 SQLite 文件 |
| `diagnose` | 列出纯文本数据库中的表、列和样本行 |
| `list-peers` | 按名称片段查找可能的对话者 ID |
| `export` | 将消息渲染为 HTML、Markdown 或 CSV |
### `decrypt`
| 标志 | 必需 | 描述 |
| --- | --- | --- |
| `--key` | 是 | `.tempkeyEncrypted` 的路径 |
| `--db` | 是 | 加密的 `db_sqlite` 的路径 |
| `--out` | 否 | 输出的纯文本数据库路径,默认为 `plaintext.db` |
| `--passcode` | 否 | Telegram 本地密码;也可使用 `TG_LOCAL_PASSCODE` |
| `--debug` | 否 | 打印密钥/配置文件诊断信息 |
### `diagnose`
| 标志 | 必需 | 描述 |
| --- | --- | --- |
| `--db` | 是 | 纯文本 SQLite 数据库的路径 |
| `--table` | 否 | 要采样的表;存在时默认为 `t7` |
### `list-peers`
| 标志 | 必需 | 描述 |
| --- | --- | --- |
| `--db` | 是 | 纯文本 SQLite 数据库的路径 |
| `--search` | 否 | 用于过滤对话者的名称片段 |
### `export`
| 标志 | 必需 | 描述 |
| --- | --- | --- |
| `--db` | 是 | 纯文本 SQLite 数据库的路径 |
| `--contact` | 否 | 要解析为对话者的联系人姓名 |
| `--peer-id` | 否 | 要导出的数字对话者 ID |
| `--table` | 否 | 覆盖已检测到的消息表 |
| `--limit` | 否 | 最大消息数 |
| `--start-date` | 否 | 开始日期,`YYYY-MM-DD` 或 ISO 日期时间 |
| `--end-date` | 否 | 结束日期,`YYYY-MM-DD` 或 ISO 日期时间 |
| `--format` | 否 | `html`、`md` 或 `csv`;默认为 `md` |
| `--out` | 否 | 输出路径;默认为 `chat_export.` |
| `--me-name` | 否 | 发出消息的显示标签;默认为 `Me` |
| `--show-direction` | 否 | 在 Markdown 中追加 `(in)` 或 `(out)` 标签 |
## 📄 输出格式
| 格式 | 最适合 | 备注 |
| --- | --- | --- |
| `html` | 阅读和分享精美的聊天记录 | 包括摘要卡片、日期跳转、返回顶部和链接处理 |
| `md` | 归档文本、笔记、版本控制 | 紧凑、便携且易于比较 |
| `csv` | 在电子表格或脚本中进行分析 | 包括日期、时间、Unix 时间戳、方向、发送者、文本、对话者 ID 和作者 ID |
### Markdown 片段
```
# Telegram 聊天记录: Alex Example
**Exported:** 2026-02-04 16:05:12
**Total Messages:** 418
---
## 2026年2月4日 星期三
**14:13:09 — Me**
3h48 is good also
```
### CSV 片段
```
date,time,timestamp,direction,speaker,text,peer_id,author_id
2026-02-04,14:13:09,1770214389,out,Me,"3h48 is good also",123456789,123456789
```
## 🗺️ 关键路径
原生 Telegram for macOS 通常将恢复相关的文件存储在此处:
```
~/Library/Group Containers/6N38VWS5BX.ru.keepcoder.Telegram/stable/
├── .tempkeyEncrypted
└── account-*/
└── postbox/
└── db/
└── db_sqlite
```
`account-*` 目录必须与您正在解密的数据库相匹配。如果有多个账户,请在解密每个账户后尝试 `list-peers`,并记录哪个纯文本数据库来自哪个账户目录。
## 🔐 安全与隐私
- 尽可能使用 Telegram 文件的副本进行操作。
- 在时间紧迫的恢复过程中,保持 Mac 离线以避免同步更改。
- 将 `plaintext.db`、HTML、Markdown 和 CSV 输出视为敏感私人数据。
- 恢复工作完成后,删除或加密中间文件。
- 该工具只读取本地文件并写入本地输出;它不会联系 Telegram 或任何第三方恢复服务。
## 🩺 故障排除
| 症状 | 检查内容 |
| --- | --- |
| `Key file not found` | 确认 `.tempkeyEncrypted` 路径,并为包含空格的路径加上引号 |
| `Database file not found` | 确认所选的 `account-*` 目录中包含 `postbox/db/db_sqlite` |
| `Failed to decrypt database` | 验证密钥和数据库是否属于同一个 Telegram 账户;如果启用了密码锁,请传入 `--passcode` |
| `file is not a database` | 通常是密钥/数据库对不匹配或不受支持的 SQLCipher 配置文件 |
| `No peer records found` | 运行 `diagnose` 并确认这是原生 macOS Telegram 数据库 |
| `No messages found with the current filters` | 移除日期过滤器,确认 `--peer-id`,或尝试导出所有已解码消息 |
| `sqlcipher3` 安装失败 | 使用 Homebrew 安装 SQLCipher,然后在干净的虚拟环境中重新安装该包 |
遇到解密问题时,请使用 `--debug` 重新运行:
```
telegram-exporter decrypt \
--key /path/to/.tempkeyEncrypted \
--db /path/to/db_sqlite \
--out recovery/plaintext.db \
--debug
```
## ⚠️ 限制
- 不会将消息恢复到 Telegram 中。
- 不会绕过 Telegram 本地密码;您需要提供密码。
- 无法恢复本地缓存中已不存在的消息。
- 不会从 Telegram 服务器下载内容。
- 目前无法从 Telegram 的文件缓存中提取媒体文件。
- 某些较新或不常见的 Telegram 消息负载可能只能部分解码。
不支持 Telegram Desktop/Qt、Mac App Store 版本、移动设备备份或 Telegram 云端导出存档。
## ❓ 常见问题
### 这能恢复 Telegram 内已删除的聊天吗?
不能。它是从本地数据导出聊天记录;不会将消息写回 Telegram。
### 我应该直接使用原始的 Telegram 数据库吗?
该命令可以读取它,但对于恢复工作来说,将密钥和数据库复制到单独的工作目录并从该副本解密会更安全。
### 为什么这只支持 Telegram for macOS?
原生 macOS 应用使用与 Telegram Desktop/Qt 和移动客户端不同的存储布局。本项目是围绕原生应用的本地 Postbox/SQLCipher 数据构建的。
### 它适用于 Mac App Store 版本吗?
不适用。本项目目前针对的是从 macos.telegram.org 直接下载/Homebrew 安装的版本。Mac App Store 版本使用不同的应用打包和存储设置,因此不在此工具支持的恢复范围内。
### 它能恢复照片、视频或文档吗?
目前不能。导出工具侧重于已解码的消息文本和聊天记录元数据。
## 🔖 版本控制
规范版本号存储在 [`VERSION`](VERSION) 中,并由 CLI 公开:
```
telegram-exporter --version
```
在准备版本升级时使用辅助脚本:
```
.github/scripts/bump_version.py patch
.github/scripts/bump_version.py minor
.github/scripts/bump_version.py major
.github/scripts/bump_version.py --set 1.2.3
```
## 🧹 质量检查
CI 工作流在 Python 3.10 到 3.13 的环境中运行 Black、Ruff 和 Pylint。
```
pip install black ruff pylint
black --check src/telegram_message_exporter telegram_exporter.py .github/scripts/bump_version.py
ruff check src/telegram_message_exporter telegram_exporter.py .github/scripts/bump_version.py
pylint src/telegram_message_exporter telegram_exporter.py
```
## 🗂️ 项目结构
```
telegram-message-exporter/
├── .github/
│ ├── dependabot.yml # Dependency update schedule
│ ├── scripts/
│ │ └── bump_version.py # Version helper
│ └── workflows/
│ └── ci.yml # Python lint matrix
├── pyproject.toml # Packaging metadata and CLI entrypoint
├── telegram_exporter.py # Convenience wrapper for source checkouts
├── src/
│ └── telegram_message_exporter/
│ ├── __init__.py # Version metadata
│ ├── __main__.py # python -m entrypoint
│ ├── cli.py # Argument parsing and commands
│ ├── crypto.py # SQLCipher and tempkey handling
│ ├── db.py # DB heuristics and message extraction
│ ├── exporters.py # HTML, Markdown, and CSV renderers
│ ├── hashing.py # MurmurHash helper
│ ├── models.py # Message data model
│ ├── postbox.py # Postbox parsing utilities
│ └── utils.py # Date parsing and link helpers
├── requirements.txt # Runtime dependencies
├── VERSION # Canonical package version
├── LICENSE
└── README.md
```
## 🙏 致谢
本项目建立在社区逆向工程工作的基础之上。特别感谢 **[@stek29](https://github.com/stek29)** 对 Telegram for macOS 本地密钥格式和 Postbox 结构的[最初研究和参考实现](https://gist.github.com/stek29/8a7ac0e673818917525ec4031d77a713)。
## 🤝 贡献
欢迎提交 Issue 和 Pull Request,特别是关于以下方面:
- 其他 Telegram for macOS 存储变体
- 更安全的恢复工作流
- 更好的 Postbox 解码
- 导出格式改进
- 针对真实缓存结构的测试
在分享示例时,请牢记恢复和隐私问题。请勿将私人 Telegram 数据库或聊天记录附加到公开的 Issue 中。
## 📄 许可证
本项目采用 MIT 许可证授权。有关详细信息,请参阅 [`LICENSE`](LICENSE)。
标签:CSV, db_sqlite, HTML, HTTP工具, Markdown, Postbox, Python, SQLCipher, Telegram, Telegram for macOS, 二进制发布, 加密数据库, 即时通讯安全, 域渗透, 库, 应急响应, 开源工具, 数字取证, 数据导出, 数据库解析, 数据恢复, 数据泄露, 数据解密, 文档结构分析, 无后门, 本地缓存解密, 电子数据取证, 离线恢复, 聊天记录导出, 自动化脚本, 逆向工具, 通讯记录提取