From cc337391bc247231ded28107ff26553ef10ef804 Mon Sep 17 00:00:00 2001 From: xaoyaoo Date: Sat, 20 Apr 2024 17:54:54 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=AF=BC=E5=87=BAcsv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pywxdump/api/api.py | 45 ++++++++++++++--- pywxdump/dbpreprocess/__init__.py | 4 +- pywxdump/dbpreprocess/export/exportCSV.py | 61 +++++++++++++++++++++++ pywxdump/dbpreprocess/parsingMSG.py | 2 +- pywxdump/dbpreprocess/parsingMicroMsg.py | 2 +- pywxdump/wx_info/merge_db.py | 2 +- 6 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 pywxdump/dbpreprocess/export/exportCSV.py diff --git a/pywxdump/api/api.py b/pywxdump/api/api.py index 93d0cbf..ef03c7c 100644 --- a/pywxdump/api/api.py +++ b/pywxdump/api/api.py @@ -23,6 +23,7 @@ from pywxdump import read_info, VERSION_LIST, batch_decrypt, BiasAddr, merge_db, import pywxdump from pywxdump.dbpreprocess import wxid2userinfo, ParsingMSG, get_user_list, get_recent_user_list, ParsingMediaMSG, \ download_file +from pywxdump.dbpreprocess import export_csv # app = Flask(__name__, static_folder='../ui/web/dist', static_url_path='/') @@ -440,7 +441,7 @@ def get_file(filePath): # start 导出聊天记录 ***************************************************************************************************** @api.route('/api/export_endb', methods=["GET", 'POST']) -def export_endb(): +def get_export_endb(): """ 导出加密数据库 :return: @@ -472,7 +473,7 @@ def export_endb(): @api.route('/api/export_dedb', methods=["GET", "POST"]) -def export_dedb(): +def get_export_dedb(): """ 导出解密数据库 :return: @@ -483,15 +484,47 @@ def export_dedb(): key = request.json.get("key", read_session(g.sf, my_wxid, "key")) wx_path = request.json.get("wx_path", read_session(g.sf, my_wxid, "wx_path")) + if not key: + return ReJson(1002, body=f"key is required: {key}") + if not wx_path: + return ReJson(1002, body=f"wx_path is required: {wx_path}") + if not os.path.exists(wx_path): + return ReJson(1001, body=f"wx_path not exists: {wx_path}") + outpath = os.path.join(g.tmp_path, "export", my_wxid, "dedb") if not os.path.exists(outpath): os.makedirs(outpath) - merge_path = read_session(g.sf, my_wxid, "merge_path") - assert isinstance(outpath, str) # 为了解决pycharm的警告, 无实际意义 - shutil.copy(merge_path, os.path.join(outpath, os.path.basename(merge_path))) + code, merge_save_path = decrypt_merge(wx_path=wx_path, key=key, outpath=outpath) + time.sleep(1) + if code: + return ReJson(0, body=merge_save_path) + else: + return ReJson(2001, body=merge_save_path) - return ReJson(0, body=outpath) + +@api.route('/api/export_csv', methods=["GET", 'POST']) +def get_export_csv(): + """ + 导出csv + :return: + """ + my_wxid = read_session(g.sf, "test", "last") + if not my_wxid: return ReJson(1001, body="my_wxid is required") + + wxid = request.json.get("wxid") + if not wxid: + return ReJson(1002, body=f"username is required: {wxid}") + + outpath = os.path.join(g.tmp_path, "export", my_wxid, "csv", wxid) + if not os.path.exists(outpath): + os.makedirs(outpath) + + code, ret = export_csv(wxid, outpath, read_session(g.sf, my_wxid, "msg_path")) + if code: + return ReJson(0, ret) + else: + return ReJson(2001, body=ret) @api.route('/api/export', methods=["GET", 'POST']) diff --git a/pywxdump/dbpreprocess/__init__.py b/pywxdump/dbpreprocess/__init__.py index f3d3837..c247efd 100644 --- a/pywxdump/dbpreprocess/__init__.py +++ b/pywxdump/dbpreprocess/__init__.py @@ -13,6 +13,8 @@ from .parsingMediaMSG import ParsingMediaMSG from .parsingOpenIMContact import ParsingOpenIMContact from .utils import download_file +from .export.exportCSV import export_csv + def get_user_list(MicroMsg_db_path, OpenIMContact_db_path=None, word=None): """ @@ -65,7 +67,7 @@ def wxid2userinfo(MicroMsg_db_path, OpenIMContact_db_path, wxid): """ 获取联系人信息 :param MicroMsg_db_path: MicroMsg.db 文件路径 - :param wxid: 微信id + :param wxid: 微信id,可以是单个id,也可以是多个id,使用list传入 :return: 联系人信息 {wxid: {wxid: wxid, nickname: nickname, remark: remark, account: account, describe: describe, headImgUrl: headImgUrl}} """ # 连接 MicroMsg.db 数据库,并执行查询 diff --git a/pywxdump/dbpreprocess/export/exportCSV.py b/pywxdump/dbpreprocess/export/exportCSV.py new file mode 100644 index 0000000..73c5b93 --- /dev/null +++ b/pywxdump/dbpreprocess/export/exportCSV.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*-# +# ------------------------------------------------------------------------------- +# Name: exportCSV.py +# Description: +# Author: xaoyaoo +# Date: 2024/04/20 +# ------------------------------------------------------------------------------- +import csv +import json +import os +from ..parsingMSG import ParsingMSG + + +def export_csv(wxid, outpath, msg_path, page_size=5000): + if not os.path.exists(outpath): + outpath = os.path.join(os.getcwd(), "export" + os.sep + wxid) + if not os.path.exists(outpath): + os.makedirs(outpath) + + pmsg = ParsingMSG(msg_path) + + count = pmsg.msg_count(wxid) + chatCount = count.get(wxid, 0) + if chatCount == 0: + return False, "没有聊天记录" + + if page_size > chatCount: + page_size = chatCount + 1 + + for i in range(0, chatCount, page_size): + start_index = i + data, wxid_list = pmsg.msg_list(wxid, start_index, page_size) + + if len(data) == 0: + return False, "没有聊天记录" + + save_path = os.path.join(outpath, f"{wxid}_{i}_{i + page_size}.csv") + + with open(save_path, "w", encoding="utf-8", newline='') as f: + csv_writer = csv.writer(f, quoting=csv.QUOTE_MINIMAL) + + csv_writer.writerow(["id", "MsgSvrID", "type_name", "is_sender", "talker", "room_name", "content", + "CreateTime"]) + for row in data: + id = row.get("id", "") + MsgSvrID = row.get("MsgSvrID", "") + type_name = row.get("type_name", "") + is_sender = row.get("is_sender", "") + talker = row.get("talker", "") + room_name = row.get("room_name", "") + content = row.get("content", "") + CreateTime = row.get("CreateTime", "") + + content = json.dumps(content, ensure_ascii=False) + csv_writer.writerow([id, MsgSvrID, type_name, is_sender, talker, room_name, content, CreateTime]) + + return True, f"导出成功: {outpath}" + + +if __name__ == '__main__': + pass diff --git a/pywxdump/dbpreprocess/parsingMSG.py b/pywxdump/dbpreprocess/parsingMSG.py index b3a70d9..06282d2 100644 --- a/pywxdump/dbpreprocess/parsingMSG.py +++ b/pywxdump/dbpreprocess/parsingMSG.py @@ -50,7 +50,7 @@ class ParsingMSG(DatabaseBase): """ 获取聊天记录数量,根据wxid获取单个联系人的聊天记录数量,不传wxid则获取所有联系人的聊天记录数量 :param MSG_db_path: MSG.db 文件路径 - :return: 聊天记录数量列表 + :return: 聊天记录数量列表 {wxid: chat_count} """ if wxid: sql = f"SELECT StrTalker, COUNT(*) FROM MSG WHERE StrTalker='{wxid}';" diff --git a/pywxdump/dbpreprocess/parsingMicroMsg.py b/pywxdump/dbpreprocess/parsingMicroMsg.py index 1ad1fad..4d3da3b 100644 --- a/pywxdump/dbpreprocess/parsingMicroMsg.py +++ b/pywxdump/dbpreprocess/parsingMicroMsg.py @@ -42,7 +42,7 @@ class ParsingMicroMsg(DatabaseBase): def wxid2userinfo(self, wxid): """ 获取单个联系人信息 - :param wxid: 微信id + :param wxid: 微信id,可以是单个id,也可以是id列表 :return: 联系人信息 """ if isinstance(wxid, str): diff --git a/pywxdump/wx_info/merge_db.py b/pywxdump/wx_info/merge_db.py index 62ac6f7..f4d1448 100644 --- a/pywxdump/wx_info/merge_db.py +++ b/pywxdump/wx_info/merge_db.py @@ -291,7 +291,7 @@ def merge_db(db_paths, save_path="merge.db", CreateTime: int = 0, endCreateTime: def decrypt_merge(wx_path, key, outpath="", CreateTime: int = 0, endCreateTime: int = 0) -> (bool, str): """ - 解密合并数据库 msg.db, microMsg.db, media.db + 解密合并数据库 msg.db, microMsg.db, media.db,注意:会删除原数据库 :param wx_path: 微信路径 eg: C:\*******\WeChat Files\wxid_********* :param key: 解密密钥 :return: (true,解密后的数据库路径) or (false,错误信息)