简介:这是一款面向技术开发者与学术研究者的实时微信聊天记录监控与分析工具,聚焦微信平台对话数据的即时采集与标准化调用。它支持对指定群聊及一对一私聊内容进行实时抓取,并提供符合规范的REST API接口,便于团队将数据接入自有系统,同时架构预留了公开浏览、AI话题趋势分析、远程服务器存储等扩展方向,适合具备一定Python与接口开发基础、需要做社交数据研究或系统集成的读者。资源包共16个文件,约264KB,以py脚本为核心,涵盖HTTP服务、聊天历史处理与数据源工具等模块,另含zbak备份、png界面截图、txt依赖说明、md文档、license及gitignore等辅助文件,结构紧凑、便于快速理解项目组织方式。目前已有127人学习浏览。通过阅读源码与说明文档,读者可掌握实时采集、接口封装与数据落地的整体思路,并在此基础上按需扩展分析能力。
1. 从一份聊天记录到一套可调用的数据服务
微信聊天记录的价值,往往在需要它的时候才显现出来。做社群运营的想知道三个月前某次活动后群里的真实反馈,做学术研究的需要把某个课题讨论群的对话整理成可分析的语料,做产品的想从用户吐槽里提炼高频问题。手动翻聊天记录这件事,翻过的人都知道有多痛苦——消息刷得太快、关键词搜不全、跨设备同步麻烦,最后往往不了了之。
WeChatMsgHistory_real-main 这个项目,走的是另一条路:把微信聊天记录变成一套可以实时查看、可以通过 REST API 调用的数据服务。它的核心是一个 Python 写的服务端,配合微信客户端的数据源,把群聊和私聊的消息采集出来,存进本地数据库,再通过标准 HTTP 接口对外提供查询能力。适合谁用?有 Python 基础、能看懂配置文件、愿意花半小时把环境跑起来的开发者。如果你只是想找个开箱即用的软件,这个项目可能不太适合你;但如果你想在聊天数据之上做二次开发,比如接个分析脚本、做个看板、跑个关键词监控,那它的架构是留了口子的。
压缩包里的文件结构不算复杂:httpMain.py是主入口,server/目录下是服务端核心逻辑,HttpServer.py负责 HTTP 服务,ChatHistory.py处理聊天记录,DataSouceUtils.py管数据源,config/放配置,requirements.txt列依赖。下面从环境搭建开始,一步步把它跑起来。
2. 环境搭建与数据源接入:从解压到第一条记录落库
2.1 依赖安装与 Python 版本选择
拿到压缩包后先别急着pip install,第一件事是确认 Python 版本。这个项目的代码风格偏 3.8 到 3.10 之间,太新的版本(比如 3.12)可能会在部分依赖上遇到编译问题。我一般会先用python --version看一眼,如果本机是 3.11 以上,建议用 conda 单独建一个 3.9 的环境,省得后面跟系统包打架。
# 创建独立环境,避免污染系统 Python conda create -n wechat_history python=3.9 -y conda activate wechat_history # 进入项目目录后安装依赖 cd WeChatMsgHistory_real-main pip install -r requirements.txtrequirements.txt里主要包含几类东西:HTTP 服务框架(通常是 Flask 或 FastAPI 这类轻量级方案)、数据库驱动(SQLite 或 MySQL 的连接库)、以及一些数据处理工具。安装过程中如果遇到mysqlclient编译失败,常见原因是本机缺 MySQL 开发头文件,Ubuntu 下装libmysqlclient-dev,macOS 下装mysql-client即可。如果只是本地跑跑,SQLite 方案不需要额外装数据库服务,更省事。
提示:
requirements.txt.zbak是备份文件,内容跟正式版可能有细微差异,以requirements.txt为准。
2.2 配置文件解读与数据源参数
项目根目录下的config/是整个服务的控制中心。打开后你会看到数据库连接、服务端口、数据源路径这几类配置。DataSouceUtils.py负责读取这些配置并初始化数据源,它的逻辑是:先检查配置里的数据源类型,然后尝试连接,连接失败会写日志到LoggerSetup.py定义的日志文件里。
# config 目录下通常有一个 settings.py 或 config.yaml # 以 settings.py 为例,关键参数如下: DATABASE = { "type": "sqlite", # 可选 sqlite / mysql "path": "./data/chat.db", # sqlite 模式下的数据库文件路径 "host": "127.0.0.1", # mysql 模式下的主机 "port": 3306, "user": "root", "password": "your_password", "dbname": "wechat_history" } SERVER = { "host": "0.0.0.0", # 监听地址,0.0.0.0 表示允许局域网访问 "port": 5000, # HTTP 服务端口 "debug": False # 生产环境务必关掉 } DATA_SOURCE = { "type": "wechat", # 数据源类型 "poll_interval": 5, # 轮询间隔,单位秒 "batch_size": 100 # 每次拉取的最大消息条数 }这里有几个参数值得展开说。poll_interval控制的是采集频率,设得太小(比如 1 秒)会给微信客户端带来明显压力,设得太大(比如 30 秒)又会导致消息延迟,5 到 10 秒是比较稳妥的区间。batch_size决定了单次写入数据库的消息量,如果你的群消息量特别大,可以适当调高到 200 到 500,但要注意内存占用。host如果设成0.0.0.0,同一局域网内的其他设备也能访问 API,方便你做远程调用,但前提是你清楚网络环境是可控的。
2.3 启动服务与验证数据落库
配置改好后,启动入口是httpMain.py。这个文件做的事情很清晰:初始化日志、加载配置、启动数据源采集线程、启动 HTTP 服务。两个线程各跑各的,采集线程负责往数据库写,HTTP 线程负责往外读。
# 启动主程序 python httpMain.py # 看到类似输出说明启动成功: # [INFO] Logger initialized # [INFO] Database connected: ./data/chat.db # [INFO] Data source started, polling every 5s # [INFO] HTTP server running on 0.0.0.0:5000启动之后别急着调 API,先确认数据有没有落库。最直接的办法是用 SQLite 命令行查一下:
sqlite3 ./data/chat.db # 查看表结构 .tables # 通常会看到 messages、contacts、groups 这几张表 # 查最近 10 条消息 SELECT * FROM messages ORDER BY create_time DESC LIMIT 10;如果messages表是空的,说明采集环节有问题。先看日志文件里有没有Data source connection failed之类的报错,再检查微信客户端是否在运行、数据源路径是否指向了正确的账号目录。常见的情况是微信装了但没登录,或者登录的账号跟配置里指定的不一致。DataSouceUtils.py里通常有一个账号识别逻辑,会去读微信的本地数据目录,路径不对就什么都采不到。
3. REST API 调用与数据查询:把聊天记录变成可编程接口
3.1 接口清单与请求格式
服务跑起来之后,HttpServer.py会注册一组路由。从项目结构和常见实现来看,核心接口大概有这几类:查联系人列表、查群组列表、按条件查消息、按关键词搜消息。请求方式以 GET 为主,返回格式是 JSON。下面这张表是我根据HttpServer.py的路由注册逻辑整理出来的,实际路径以你本地跑起来的为准。
| 接口路径 | 方法 | 参数 | 返回内容 |
|---|---|---|---|
/api/contacts | GET | 无 | 所有联系人列表 |
/api/groups | GET | 无 | 所有群组列表 |
/api/messages | GET | chat_id、limit、offset | 指定会话的消息记录 |
/api/search | GET | keyword、start_time、end_time | 匹配关键词的消息 |
/api/status | GET | 无 | 服务运行状态与采集统计 |
chat_id这个参数需要特别注意,它不是你微信里看到的群名称,而是数据源内部使用的唯一标识。通常是一串哈希值或者wxid_开头的字符串。怎么拿到?先调/api/groups或/api/contacts,返回的 JSON 里每个对象都有一个id字段,那个就是。
3.2 用 Python 脚本调用 API 做关键词监控
光有接口还不够,实际用的时候往往是写个脚本定时拉数据、做过滤、存结果。下面这段代码演示的是:每隔 60 秒查一次最近 5 分钟内的消息,筛出包含指定关键词的记录,打印出来。
import requests import time from datetime import datetime, timedelta API_BASE = "http://127.0.0.1:5000/api" KEYWORDS = ["退款", "投诉", "卡顿"] # 你要监控的词 def fetch_recent_messages(minutes=5): """拉取最近 N 分钟的消息""" end_time = datetime.now() start_time = end_time - timedelta(minutes=minutes) params = { "start_time": start_time.strftime("%Y-%m-%d %H:%M:%S"), "end_time": end_time.strftime("%Y-%m-%d %H:%M:%S"), "limit": 500 } resp = requests.get(f"{API_BASE}/messages", params=params, timeout=10) if resp.status_code != 200: print(f"[ERROR] API returned {resp.status_code}") return [] return resp.json().get("data", []) def filter_by_keywords(messages, keywords): """按关键词过滤消息""" hit = [] for msg in messages: content = msg.get("content", "") for kw in keywords: if kw in content: hit.append({ "time": msg.get("create_time"), "sender": msg.get("sender_name"), "content": content, "keyword": kw }) break return hit if __name__ == "__main__": while True: msgs = fetch_recent_messages(minutes=5) hits = filter_by_keywords(msgs, KEYWORDS) for h in hits: print(f"[{h['time']}] {h['sender']}: {h['content']} (命中: {h['keyword']})") if not hits: print(f"[{datetime.now()}] 本轮无命中") time.sleep(60)这段脚本的逻辑分三层:fetch_recent_messages负责跟 API 通信,把时间窗口内的消息拉回来;filter_by_keywords在本地做关键词匹配,不走 API 的搜索接口是为了减少服务端压力;主循环控制节奏,60 秒一轮。参数上,limit设成 500 是防止单次拉太多导致响应变慢,如果你的群特别活跃,可以拆成多次分页拉取。timeout=10是必须的,不然 API 卡住的时候脚本会一直挂着。
3.3 数据导出与二次分析衔接
采集到的数据最终要落到分析环节。ChatHistory.py里通常会有导出方法,但更灵活的方式是直接从数据库读,或者通过 API 批量拉取后自己处理。如果你要做词频统计、情感分析、话题聚类,建议先把数据导成 CSV 或 JSON Lines 格式,再喂给 pandas 或 jieba 这类工具。
import sqlite3 import csv # 直接从数据库导出,比走 API 快 conn = sqlite3.connect("./data/chat.db") cursor = conn.cursor() cursor.execute(""" SELECT create_time, sender_name, content FROM messages WHERE chat_id = ? ORDER BY create_time ASC """, ("your_chat_id_here",)) with open("export.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["time", "sender", "content"]) writer.writerows(cursor.fetchall()) conn.close() print("导出完成")导出之后,你可以用 jieba 做分词、用 wordcloud 做词云、用 snownlp 做情感倾向,这些跟本项目是解耦的,按需组合就行。关键是把chat_id替换成你真正要分析的会话 ID,别导错了群。
4. 避坑与排查:那些让你怀疑人生的报错
4.1 启动报错ModuleNotFoundError: No module named 'xxx'
现象:python httpMain.py直接报模块找不到,通常是flask、pymysql、requests这几个之一。
原因:依赖没装全,或者装到了错误的 Python 环境里。很多人系统里有多个 Python,pip和python指向的不是同一个。
解决:先which python和which pip确认路径一致,然后用pip list看缺哪个。如果确认装了还报错,试试python -m pip install -r requirements.txt,强制用当前解释器的 pip 装。
4.2 API 返回 200 但数据为空
现象:/api/messages能通,返回的 JSON 结构也对,但data字段是空数组。
原因:三种可能——chat_id传错了、时间范围没覆盖到任何消息、采集线程根本没写进数据。前两种是参数问题,第三种是采集问题。
解决:先调/api/status看采集统计里的消息总数。如果是 0,问题在采集端,去查日志和微信客户端状态。如果总数不为 0,拿/api/groups返回的真实id重新请求,时间范围放宽到最近 24 小时再试。
4.3 数据库写入越来越慢
现象:跑了一段时间后,消息落库明显变慢,API 响应也从几十毫秒涨到几秒。
原因:SQLite 在大量写入时如果没有建索引,查询会全表扫描。messages表如果没有chat_id和create_time的索引,数据量上到十万条以后就会很明显。
解决:手动加索引,或者改配置用 MySQL。SQLite 下执行:
CREATE INDEX idx_messages_chat_time ON messages (chat_id, create_time); CREATE INDEX idx_messages_content ON messages (content);加完之后查询速度会有肉眼可见的提升。但注意索引会拖慢写入速度,如果你的场景是写多读少,要权衡一下。
4.4 采集线程莫名停止
现象:服务启动时正常,跑几个小时后 API 还在响应,但数据不再更新。
原因:采集线程里某个异常没被捕获,线程直接退出了,而主线程和 HTTP 线程还在跑,所以表面上看服务没挂。
解决:在DataSouceUtils.py的采集循环外层加try/except,把异常写进日志而不是让线程死掉。同时加一个心跳检测,如果超过一定时间没有新数据写入,自动重启采集线程。这个改动不大,但能省掉很多半夜排查的麻烦。
4.5 端口被占用导致启动失败
现象:OSError: [Errno 98] Address already in use。
原因:5000 端口被其他程序占了,或者上一次的服务没退干净。
解决:lsof -i :5000找到占用进程,kill -9掉,或者改配置里的端口号换个没被占的。macOS 上 5000 端口经常被 AirPlay 接收器占用,换成 5001 或 8080 就行。
5. 进阶玩法:把采集数据接进分析流水线
5.1 用定时任务做增量导出
手动导出适合一次性分析,长期跑的话建议用 cron 或 APScheduler 做增量导出。思路是记录上次导出的最大时间戳,每次只导比它新的记录,避免重复处理。
import sqlite3 import json import os from datetime import datetime STATE_FILE = "./last_export.json" def load_last_ts(): if os.path.exists(STATE_FILE): with open(STATE_FILE) as f: return json.load(f).get("last_ts", "1970-01-01 00:00:00") return "1970-01-01 00:00:00" def save_last_ts(ts): with open(STATE_FILE, "w") as f: json.dump({"last_ts": ts}, f) def incremental_export(): last_ts = load_last_ts() conn = sqlite3.connect("./data/chat.db") cursor = conn.cursor() cursor.execute(""" SELECT create_time, sender_name, content FROM messages WHERE create_time > ? ORDER BY create_time ASC """, (last_ts,)) rows = cursor.fetchall() if not rows: print("无新数据") conn.close() return # 追加写入 JSON Lines with open("incremental.jsonl", "a", encoding="utf-8") as f: for row in rows: f.write(json.dumps({ "time": row[0], "sender": row[1], "content": row[2] }, ensure_ascii=False) + "\n") save_last_ts(rows[-1][0]) conn.close() print(f"导出 {len(rows)} 条,最新时间 {rows[-1][0]}") if __name__ == "__main__": incremental_export()这个脚本的关键在于last_export.json这个状态文件,它记录了上次导出的边界时间。每次跑只拉新数据,导出格式用 JSON Lines 而不是普通 JSON,是因为追加写入更方便,不用每次解析整个文件。配合 crontab 每 10 分钟跑一次,就能做到准实时地把数据推到下游。
5.2 接大模型做话题提取的注意点
现在很多人想把聊天记录接给大模型做话题分析,这个思路没问题,但有几个坑得提前知道。第一是数据量,一个活跃群一天几千条消息,全塞给模型既贵又慢,正确做法是先做一轮本地过滤,比如只取长度超过 20 字的消息、或者只取包含特定关键词的消息。第二是隐私,聊天记录里可能有手机号、地址、身份证号,送出去之前最好做一遍脱敏,正则替换掉数字串和敏感词。第三是接口稳定性,大模型 API 偶尔会超时或限流,脚本里必须加重试和降级逻辑,不能因为一次调用失败就丢掉整批数据。
我一般会先把数据按小时聚合,每个小时取 top 50 条最长消息,再送给模型做摘要。这样既控制了 token 消耗,又能抓住主要话题。模型返回的结果存回数据库或者单独写一张分析表,跟原始消息通过时间戳关联,方便回溯。
5.3 验证数据完整性的一个笨办法
最后分享一个我每次部署完都会做的检查:随机抽三个时间段,手动在微信里翻到对应位置,数一下消息条数,跟数据库里的 count 对一下。听起来很笨,但能快速发现采集漏消息的问题。漏消息的原因通常是轮询间隔太长、或者微信客户端在采集间隙收到了消息但没被捕获。如果发现漏得比较多,把poll_interval调小到 2 到 3 秒再观察。
从那以后我每次部署这类采集服务,都会先跑一轮完整性抽查再交给别人用。数据这东西,少几条可能没人发现,但真到用的时候缺了关键记录,后悔药没地方买。希望帮到你。
本文还有配套的精品资源,点击获取