Skip to content

Commit

Permalink
增加聊天记录导出为html
Browse files Browse the repository at this point in the history
  • Loading branch information
xaoyaoo committed Nov 16, 2023
1 parent 447dec7 commit 21fe2bb
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 15 deletions.
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<details>
<summary><strong>更新日志(点击展开):</strong></summary>

* 2023.11.16 增加聊天记录导出为html
* 2023.11.15 添加test文件,添加自动构建可执行文件的脚本,添加版本描述
* 2023.11.15 [v2.2.5变化较大]重构解密脚本的返回值,重构命令行参数
* 2023.11.15 修复无法获取wxid的bug
Expand Down Expand Up @@ -48,7 +49,7 @@

## 1. 项目简介

PyWxDump可用于:获取用户个人信息(昵称/账号/手机/邮箱/数据库密钥(用来解密聊天记录));数据库读取、解密脚本;聊天记录查看工具
PyWxDump可用于:获取用户个人信息(昵称/账号/手机/邮箱/数据库密钥(用来解密聊天记录));数据库读取、解密脚本;聊天记录查看导出工具

支持多账户信息获取,支持所有微信版本。

Expand All @@ -66,6 +67,7 @@ PyWxDump可用于:获取用户个人信息(昵称/账号/手机/邮箱/数据
* (6)提供数据库部分字段说明
* (7)支持微信多开场景,获取多用户信息等
* (8)微信需要登录状态才能获取数据库密钥
* (9)支持导出聊天记录为html

**版本差异**

Expand Down Expand Up @@ -119,6 +121,7 @@ PyWxDump
[PyWxDump](https://github.com/xaoyaoo/PyWxDump)[SharpWxDump](https://github.com/AdminTest0/SharpWxDump)
的经过重构python语言版本,同时添加了一些新的功能。

* 目前只在windows下测试过,linux下可能会存在问题。
* 如发现[version_list.json](pywxdump/version_list.json)缺失或错误,
请提交[issues](https://github.com/xaoyaoo/PyWxDump/issues).
* 如发现bug或有改进意见, 请提交[issues](https://github.com/xaoyaoo/PyWxDump/issues).
Expand Down Expand Up @@ -148,6 +151,9 @@ pip install pywxdump

### 1.2 从源码安装

<details>
<summary>点击展开</summary>

```shell script
pip install git+git://github.com/xaoyaoo/PyWxDump.git
```
Expand All @@ -159,6 +165,7 @@ git clone https://github.com/xaoyaoo/PyWxDump.git
cd PyWxDump
python -m pip install -U .
```
</details>

## 2. 使用

Expand All @@ -174,11 +181,15 @@ wxdump 模式 [参数]
# db_path 获取微信文件夹路径
# decrypt 解密微信数据库
# dbshow 聊天记录查看[需要安装flask]
# export 聊天记录导出为html[需要安装flask]
# all 获取微信信息,解密微信数据库,查看聊天记录
```

*示例*

<details>
<summary>点击展开示例</summary>

以下是示例命令:

```shell script
Expand Down Expand Up @@ -228,12 +239,28 @@ wxdump dbshow -h
# -fs , --filestorage_path
# (可选)文件夹FileStorage的路径(用于显示图片)

wxdump export -h
#usage: wxdump export [-h] -u -o -msg -micro -media [-fs]
#options:
# -h, --help show this help message and exit
# -u , --username 微信账号
# -o , --outpath 导出路径
# -msg , --msg_path 解密后的 MSG.db 的路径
# -micro , --micro_path
# 解密后的 MicroMsg.db 的路径
# -media , --media_path
# 解密后的 MediaMSG.db 的路径
# -fs , --filestorage_path
# (可选)文件夹FileStorage的路径(用于显示图片)

wxdump all -h
#usage: main.py all [-h]
#options:
# -h, --help show this help message and exit
```

</details>

### 2.2 python API

更多使用方法参考[tests](./tests)文件夹下的[test_*.py](./tests/)文件
Expand Down Expand Up @@ -302,6 +329,8 @@ else:

# 三、免责声明(非常重要!!!!!!!)

本项目仅供学习交流使用,请勿用于非法用途,否则后果自负。

本项目仅允许在授权情况下对数据库进行备份,严禁用于非法目的,否则自行承担所有相关责任。使用该工具则代表默认同意该条款;

请勿利用本项目的相关技术从事非法测试,如因此产生的一切不良后果与项目作者无关。
Expand Down
48 changes: 48 additions & 0 deletions pywxdump/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,49 @@ def before_request():
app.run(debug=False)


class MainExportChatRecords():
def init_parses(self, parser):
self.mode = "export"
# 添加 'decrypt' 子命令解析器
sb_decrypt = parser.add_parser(self.mode, help="聊天记录导出为html")
sb_decrypt.add_argument("-u", "--username", type=str, help="微信账号", required=True, metavar="")
sb_decrypt.add_argument("-o", "--outpath", type=str, help="导出路径", required=True, metavar="")
sb_decrypt.add_argument("-msg", "--msg_path", type=str, help="解密后的 MSG.db 的路径", required=True,
metavar="")
sb_decrypt.add_argument("-micro", "--micro_path", type=str, help="解密后的 MicroMsg.db 的路径", required=True,
metavar="")
sb_decrypt.add_argument("-media", "--media_path", type=str, help="解密后的 MediaMSG.db 的路径", required=True,
metavar="")
sb_decrypt.add_argument("-fs", "--filestorage_path", type=str,
help="(可选)文件夹FileStorage的路径(用于显示图片)", required=False,
metavar="")
return sb_decrypt

def run(self, args):
# 从命令行参数获取值
try:
from flask import Flask, request, jsonify, render_template, g
import logging
from .show_chat.main_window import app_show_chat, get_user_list, export
except Exception as e:
print(e)
print("[-] 请安装flask( pip install flask )")
return

if not os.path.exists(args.msg_path) or not os.path.exists(args.micro_path) or not os.path.exists(
args.media_path):
print(os.path.exists(args.msg_path), os.path.exists(args.micro_path), os.path.exists(args.media_path))
print("[-] 输入数据库路径不存在")
return

if not os.path.exists(args.outpath):
os.makedirs(args.outpath)
print(f"[+] 创建输出文件夹:{args.outpath}")

export(args.username, args.outpath, args.msg_path, args.micro_path, args.media_path, args.filestorage_path)
print(f"[+] 导出成功{args.outpath}")


class MainAll():
def init_parses(self, parser):
self.mode = "all"
Expand Down Expand Up @@ -294,6 +337,11 @@ def console_run():
sb_dbshow = main_show_chat_records.init_parses(subparsers)
modes[main_show_chat_records.mode] = main_show_chat_records

# 添加 'export' 子命令解析器
main_export_chat_records = MainExportChatRecords()
sb_export = main_export_chat_records.init_parses(subparsers)
modes[main_export_chat_records.mode] = main_export_chat_records

# 添加 'all' 子命令解析器
main_all = MainAll()
sb_all = main_all.init_parses(subparsers)
Expand Down
58 changes: 57 additions & 1 deletion pywxdump/show_chat/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import hashlib
from pywxdump.analyse import read_img_dat, decompress_CompressContent, read_audio, parse_xml_string

from flask import Flask, request, render_template, g, Blueprint


def get_md5(s):
m = hashlib.md5()
Expand Down Expand Up @@ -177,18 +179,49 @@ def load_chat_records(selected_talker, start_index, page_size, user_list, MSG_AL
return data


from flask import Flask, request, render_template, g, Blueprint
def export_html(user, outpath, MSG_ALL_db_path, MediaMSG_all_db_path, FileStorage_path, page_size=500):
name_save = user.get("remark", user.get("nickname", user.get("username", "")))
username = user.get("username", "")

chatCount = user.get("chat_count", 0)

for i in range(0, chatCount, page_size):
start_index = i
data = load_chat_records(username, start_index, page_size, user, MSG_ALL_db_path, MediaMSG_all_db_path,
FileStorage_path)
if len(data) == 0:
break
with open(f"{outpath}/{name_save}_{int(i / page_size)}.html", "w", encoding="utf-8") as f:
f.write(render_template("chat.html", msgs=data))
return True, f"导出成功{outpath}"


def export(username, outpath, MSG_ALL_db_path, MicroMsg_db_path, MediaMSG_all_db_path, FileStorage_path):
if not os.path.exists(outpath):
outpath = os.path.join(os.getcwd(), "export" + os.sep + username)
if not os.path.exists(outpath):
os.makedirs(outpath)

USER_LIST = get_user_list(MSG_ALL_db_path, MicroMsg_db_path)
user = list(filter(lambda x: x["username"] == username, USER_LIST))

if username and len(user) > 0:
user = user[0]
return export_html(user, outpath, MSG_ALL_db_path, MediaMSG_all_db_path, FileStorage_path)


app_show_chat = Blueprint('show_chat_main', __name__, template_folder='templates')
app_show_chat.debug = False


# 主页 - 显示用户列表
@app_show_chat.route('/')
def index():
g.USER_LIST = get_user_list(g.MSG_ALL_db_path, g.MicroMsg_db_path)
return render_template("index.html", users=g.USER_LIST)


# 获取聊天记录
@app_show_chat.route('/get_chat_data', methods=["GET", 'POST'])
def get_chat_data():
username = request.args.get("username", "")
Expand All @@ -208,3 +241,26 @@ def get_chat_data():
return render_template("chat.html", msgs=data)
else:
return "error"


# 聊天记录导出为html
@app_show_chat.route('/export_chat_data', methods=["GET", 'POST'])
def get_export():
username = request.args.get("username", "")

user = list(filter(lambda x: x["username"] == username, g.USER_LIST))

if username and len(user) > 0:
user = user[0]
n = f"{user.get('username', '')}_{user.get('nickname', '')}_{user.get('remark', '')}"
outpath = os.path.join(os.getcwd(), "export" + os.sep + n)
if not os.path.exists(outpath):
os.makedirs(outpath)

ret = export_html(user, outpath, g.MSG_ALL_db_path, g.MediaMSG_all_db_path, g.FileStorage_path, page_size=200)
if ret[0]:
return ret[1]
else:
return ret[1]
else:
return "error"
5 changes: 5 additions & 0 deletions pywxdump/show_chat/templates/chat.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
<meta charset="UTF-8">
<title>chat</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<style>
img {
max-width: 400px;
}
</style>

</head>
<body>
Expand Down
9 changes: 8 additions & 1 deletion pywxdump/show_chat/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@

</div>
<div class="col-3" style="display: flex; justify-content: flex-end;">
<button type="button" class="btn btn-primary">导出</button>
<button id="btn_export" type="button" class="btn btn-primary">导出</button>
</div>
</div>

Expand Down Expand Up @@ -184,6 +184,13 @@ <h2 style="text-align: center">欢迎使用<a href="https://github.com/xaoyaoo/P
request_function(requestUrl);
}
});

// 导出按钮点击事件
document.getElementById('btn_export').addEventListener('click', function () {
var requestUrl = '/export_chat_data?username=' + encodeURIComponent(globalUsername);
window.open(requestUrl);
});

</script>

</body>
Expand Down
27 changes: 15 additions & 12 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,20 @@
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()

version = "2.2.6"
version = "2.2.7"

install_requires = [
"psutil",
"pycryptodomex",
"pywin32",
"pymem",
"silk-python",
"pyaudio",
"requests",
"pillow",
"pyahocorasick"
]

setup(
name="pywxdump",
author="xaoyaoo",
Expand Down Expand Up @@ -33,17 +46,7 @@
"Operating System :: OS Independent",
],
python_requires='>=3.6, <4',
install_requires=[
"psutil",
"pycryptodomex",
"pywin32",
"pymem",
"silk-python",
"pyaudio",
"requests",
"pillow",
"pyahocorasick"
],
install_requires=install_requires,
entry_points={
'console_scripts': [
'wxdump = pywxdump.command:console_run',
Expand Down

0 comments on commit 21fe2bb

Please sign in to comment.