mirror of
https://github.com/LC044/WeChatMsg
synced 2024-11-14 05:21:41 +08:00
支持导出csv格式聊天记录
This commit is contained in:
parent
f1d0ff2f83
commit
0c00298728
@ -4,9 +4,14 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="match语法说明">
|
||||
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="增加群二维码">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/readme.md" beforeDir="false" afterPath="$PROJECT_DIR$/readme.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/DataBase/data.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/data.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/DataBase/output.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/output.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/Ui/contact/contact.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/Ui/contact/contact.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/Ui/contact/contactUi.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/Ui/contact/contactUi.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/Ui/contact/contactUi.ui" beforeDir="false" afterPath="$PROJECT_DIR$/app/Ui/contact/contactUi.ui" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@ -30,6 +35,19 @@
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
<option name="SWAP_SIDES_IN_COMPARE_BRANCHES" value="true" />
|
||||
</component>
|
||||
<component name="GitHubPullRequestSearchHistory">{
|
||||
"lastFilter": {
|
||||
"state": "OPEN"
|
||||
}
|
||||
}</component>
|
||||
<component name="GithubPullRequestsUISettings">
|
||||
<option name="selectedUrlAndAccountId">
|
||||
<UrlAndAccount>
|
||||
<option name="accountId" value="17f6adba-af7f-4dcb-aeb1-4ed3d744f378" />
|
||||
<option name="url" value="https://github.com/LC044/WeChatMsg.git" />
|
||||
</UrlAndAccount>
|
||||
</option>
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
@ -48,7 +66,7 @@
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"last_opened_file_path": "D:/Program Files/Python310/Scripts/pyuic5.exe",
|
||||
"settings.editor.selected.configurable": "project.propVCSSupport.CommitDialog"
|
||||
"settings.editor.selected.configurable": "reference.settings.ide.settings.new.ui"
|
||||
}
|
||||
}</component>
|
||||
<component name="RecentsManager">
|
||||
@ -56,7 +74,7 @@
|
||||
<recent name="D:\Project\PythonProject\WeChatMsg\app\Ui" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Python.main">
|
||||
<component name="RunManager" selected="Python.output">
|
||||
<configuration name="data (1)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="WeChatMsg" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
@ -99,7 +117,7 @@
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="mainwindow" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<configuration name="output" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="WeChatMsg" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
@ -107,11 +125,11 @@
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/TEST" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/DataBase" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/TEST/mainwindow.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/DataBase/output.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
@ -165,10 +183,10 @@
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Python.main" />
|
||||
<item itemvalue="Python.output" />
|
||||
<item itemvalue="Python.report" />
|
||||
<item itemvalue="Python.data (1)" />
|
||||
<item itemvalue="Python.test" />
|
||||
<item itemvalue="Python.mainwindow" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
@ -387,7 +405,21 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1692427491271</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="30" />
|
||||
<task id="LOCAL-00030" summary="update readme">
|
||||
<created>1698248435600</created>
|
||||
<option name="number" value="00030" />
|
||||
<option name="presentableId" value="LOCAL-00030" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1698248435600</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00031" summary="增加群二维码">
|
||||
<created>1698248457797</created>
|
||||
<option name="number" value="00031" />
|
||||
<option name="presentableId" value="LOCAL-00031" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1698248457797</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="32" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="UnknownFeatures">
|
||||
@ -437,12 +469,26 @@
|
||||
<MESSAGE value="readme" />
|
||||
<MESSAGE value="mainwindows文件修正" />
|
||||
<MESSAGE value="match语法说明" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="match语法说明" />
|
||||
<MESSAGE value="update readme" />
|
||||
<MESSAGE value="增加群二维码" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="增加群二维码" />
|
||||
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
|
||||
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/app/DataBase/output.py</url>
|
||||
<line>41</line>
|
||||
<option name="timeStamp" value="3" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/app/DataBase/output.py</url>
|
||||
<line>410</line>
|
||||
<option name="timeStamp" value="7" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
<default-breakpoints>
|
||||
<breakpoint type="python-exception">
|
||||
<properties notifyOnTerminate="true" exception="BaseException">
|
||||
|
@ -250,7 +250,7 @@ def get_all_message(wxid):
|
||||
sql = '''
|
||||
select * from message
|
||||
where talker = ?
|
||||
order by msgId
|
||||
order by createTime
|
||||
'''
|
||||
cursor.execute(sql, [wxid])
|
||||
return cursor.fetchall()
|
||||
|
@ -3,6 +3,8 @@ import re
|
||||
import time
|
||||
|
||||
import docx
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import xmltodict
|
||||
from PyQt5.QtCore import *
|
||||
from docx import shared
|
||||
@ -13,6 +15,9 @@ from docxcompose.composer import Composer
|
||||
from . import data
|
||||
|
||||
|
||||
# import data
|
||||
|
||||
|
||||
def IS_5_min(last_m, now_m):
|
||||
"""
|
||||
#! 判断两次聊天时间是不是大于五分钟
|
||||
@ -43,8 +48,11 @@ class Output(QThread):
|
||||
rangeSignal = pyqtSignal(int)
|
||||
okSignal = pyqtSignal(int)
|
||||
i = 1
|
||||
CSV = 0
|
||||
DOCX = 1
|
||||
HTML = 2
|
||||
|
||||
def __init__(self, Me, ta_u, parent=None):
|
||||
def __init__(self, Me, ta_u, parent=None, type_=DOCX):
|
||||
super().__init__(parent)
|
||||
self.Me = Me
|
||||
self.sec = 2 # 默认1000秒
|
||||
@ -52,6 +60,8 @@ class Output(QThread):
|
||||
self.my_avatar = self.Me.my_avatar
|
||||
self.ta_avatar = data.get_avator(ta_u)
|
||||
self.msg_id = 0
|
||||
self.output_type = type_
|
||||
self.total_num = 0
|
||||
|
||||
def merge_docx(self, conRemark, n):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{conRemark}"
|
||||
@ -87,26 +97,46 @@ class Output(QThread):
|
||||
self.okSignal.emit(1)
|
||||
self.progressSignal.emit(self.i)
|
||||
|
||||
def to_csv(self, conRemark, path):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{conRemark}"
|
||||
messages = data.get_all_message(self.ta_username)
|
||||
# print(messages)
|
||||
self.Child0 = ChildThread(self.Me, self.ta_username, messages, conRemark, 0, type_=ChildThread.CSV)
|
||||
self.Child0.progressSignal.connect(self.progress)
|
||||
self.Child0.start()
|
||||
print("成功导出CSV文件:", origin_docx_path)
|
||||
|
||||
def run(self):
|
||||
self.Child = {}
|
||||
if 1:
|
||||
conRemark = data.get_conRemark(self.ta_username)
|
||||
data.mkdir(f"{os.path.abspath('.')}/data/聊天记录/{conRemark}")
|
||||
conRemark = data.get_conRemark(self.ta_username)
|
||||
data.mkdir(f"{os.path.abspath('.')}/data/聊天记录/{conRemark}")
|
||||
if self.output_type == self.DOCX:
|
||||
self.Child = {}
|
||||
if 1:
|
||||
messages = data.get_all_message(self.ta_username)
|
||||
self.total_num = len(messages)
|
||||
self.rangeSignal.emit(self.total_num)
|
||||
l = len(messages)
|
||||
self.n = 10
|
||||
for i in range(self.n):
|
||||
q = i * (l // self.n)
|
||||
p = (i + 1) * (l // self.n)
|
||||
if i == self.n - 1:
|
||||
p = l
|
||||
len_data = messages[q:p]
|
||||
# self.to_docx(len_data, i, conRemark)
|
||||
self.Child[i] = ChildThread(self.Me, self.ta_username, len_data, conRemark, i)
|
||||
self.Child[i].progressSignal.connect(self.progress)
|
||||
self.Child[i].start()
|
||||
elif self.output_type == self.CSV:
|
||||
# print("线程导出csv")
|
||||
# self.to_csv(self.ta_username, "path")
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.ta_username}"
|
||||
messages = data.get_all_message(self.ta_username)
|
||||
self.total_num = len(messages)
|
||||
self.rangeSignal.emit(self.total_num)
|
||||
l = len(messages)
|
||||
self.n = 10
|
||||
for i in range(self.n):
|
||||
q = i * (l // self.n)
|
||||
p = (i + 1) * (l // self.n)
|
||||
if i == self.n - 1:
|
||||
p = l
|
||||
len_data = messages[q:p]
|
||||
# self.to_docx(len_data, i, conRemark)
|
||||
self.Child[i] = ChildThread(self.Me, self.ta_username, len_data, conRemark, i)
|
||||
self.Child[i].progressSignal.connect(self.progress)
|
||||
self.Child[i].start()
|
||||
# print(messages)
|
||||
self.Child0 = ChildThread(self.Me, self.ta_username, messages, conRemark, 0, type_=ChildThread.CSV)
|
||||
self.Child0.progressSignal.connect(self.progress)
|
||||
self.Child0.run()
|
||||
self.okSignal.emit(1)
|
||||
|
||||
|
||||
class ChildThread(QThread):
|
||||
@ -116,8 +146,11 @@ class ChildThread(QThread):
|
||||
progressSignal = pyqtSignal(int)
|
||||
rangeSignal = pyqtSignal(int)
|
||||
i = 1
|
||||
CSV = 0
|
||||
DOCX = 1
|
||||
HTML = 2
|
||||
|
||||
def __init__(self, Me, ta_u, message, conRemark, num, parent=None):
|
||||
def __init__(self, Me, ta_u, message, conRemark, num, parent=None, type_=DOCX):
|
||||
super().__init__(parent)
|
||||
self.Me = Me
|
||||
self.sec = 2 # 默认1000秒
|
||||
@ -128,6 +161,7 @@ class ChildThread(QThread):
|
||||
self.conRemark = conRemark
|
||||
self.message = message
|
||||
self.msg_id = 0
|
||||
self.output_type = type_
|
||||
|
||||
def create_table(self, doc, isSend):
|
||||
'''
|
||||
@ -374,11 +408,41 @@ class ChildThread(QThread):
|
||||
print(filename)
|
||||
doc.save(filename)
|
||||
|
||||
def to_csv(self, messages, i, conRemark):
|
||||
'''创建联系人目录'''
|
||||
# print('123', messages)
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{conRemark}/{conRemark}.csv"
|
||||
last_timestamp = 1601968667000
|
||||
columns = ["用户名", "消息内容", "发送时间", "发送状态", "消息类型", "isSend", "msgId"]
|
||||
df = pd.DataFrame()
|
||||
df["用户名"] = np.array(list(map(lambda x: x[7], messages)))
|
||||
df["消息内容"] = np.array(list(map(lambda x: x[8], messages)))
|
||||
df["发送时间"] = np.array(list(map(lambda x: time_format(x[6]), messages)))
|
||||
df["发送状态"] = np.array(list(map(lambda x: x[3], messages)))
|
||||
df["消息类型"] = np.array(list(map(lambda x: x[2], messages)))
|
||||
df["isSend"] = np.array(list(map(lambda x: x[4], messages)))
|
||||
df["msgId"] = np.array(list(map(lambda x: x[0], messages)))
|
||||
df.to_csv(filename)
|
||||
# df.to_csv('data.csv')
|
||||
print(df)
|
||||
self.progressSignal.emit(self.num)
|
||||
|
||||
def to_html(self, messages, i, conRemark):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
self.to_docx(self.message, self.num, self.conRemark)
|
||||
if self.output_type == self.DOCX:
|
||||
# print("导出docx")
|
||||
self.to_docx(self.message, self.num, self.conRemark)
|
||||
elif self.output_type == self.CSV:
|
||||
print("导出csv001")
|
||||
# print('00', self.message[0])
|
||||
self.to_csv(self.message, self.num, self.conRemark)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
me = data.Me('wxid_27hqbq7vx5hf22')
|
||||
t = Output(Me=me, ta_u='wxid_q3ozn70pweud22')
|
||||
# wxid_0o18ef858vnu22
|
||||
# wxid_fdkbu92el15h22
|
||||
me = data.Me('wxid_fdkbu92el15h22')
|
||||
t = Output(Me=me, ta_u='wxid_0o18ef858vnu22', type_=Output.CSV)
|
||||
t.run()
|
||||
|
@ -69,7 +69,7 @@ class ContactController(QWidget, Ui_Dialog):
|
||||
def initui(self):
|
||||
# 槽函数连接
|
||||
self.btn_back.clicked.connect(self.back)
|
||||
self.btn_output.clicked.connect(self.output)
|
||||
# self.btn_output.clicked.connect(self.output)
|
||||
self.btn_analysis.clicked.connect(self.analysis)
|
||||
self.btn_emotion.clicked.connect(self.emotionale_Analysis)
|
||||
self.btn_report.clicked.connect(self.annual_report)
|
||||
@ -86,6 +86,19 @@ class ContactController(QWidget, Ui_Dialog):
|
||||
self.userinfo.progressBar.setVisible(False)
|
||||
self.stackedWidget.addWidget(self.frame)
|
||||
# self.lay0.addWidget(self.frame)
|
||||
menu = QMenu(self)
|
||||
self.toDocxAct = QAction(QIcon('app/data/icons/word.svg'), '导出Docx', self)
|
||||
self.toCSVAct = QAction(QIcon('app/data/icons/csv.svg'), '导出CSV', self)
|
||||
self.toHtmlAct = QAction(QIcon('app/data/icons/html.svg'), '导出HTML', self)
|
||||
self.toolButton_output.setPopupMode(QToolButton.MenuButtonPopup)
|
||||
menu.addAction(self.toDocxAct)
|
||||
menu.addAction(self.toCSVAct)
|
||||
menu.addAction(self.toHtmlAct)
|
||||
self.toolButton_output.setMenu(menu)
|
||||
# self.toolButton_output.addSeparator()
|
||||
self.toHtmlAct.triggered.connect(self.output)
|
||||
self.toDocxAct.triggered.connect(self.output)
|
||||
self.toCSVAct.triggered.connect(self.output)
|
||||
|
||||
def showContact(self):
|
||||
"""
|
||||
@ -160,11 +173,27 @@ class ContactController(QWidget, Ui_Dialog):
|
||||
:return:
|
||||
"""
|
||||
self.setViewVisible(self.now_talkerId)
|
||||
self.outputThread = output.Output(self.Me, self.now_talkerId)
|
||||
self.outputThread.progressSignal.connect(self.output_progress)
|
||||
self.outputThread.rangeSignal.connect(self.set_progressBar_range)
|
||||
self.outputThread.okSignal.connect(self.hide_progress_bar)
|
||||
self.outputThread.start()
|
||||
|
||||
if self.sender() == self.toDocxAct:
|
||||
self.outputThread = output.Output(self.Me, self.now_talkerId)
|
||||
self.outputThread.progressSignal.connect(self.output_progress)
|
||||
self.outputThread.rangeSignal.connect(self.set_progressBar_range)
|
||||
self.outputThread.okSignal.connect(self.hide_progress_bar)
|
||||
self.outputThread.start()
|
||||
elif self.sender() == self.toCSVAct:
|
||||
print('开始导出csv')
|
||||
self.outputThread = output.Output(self.Me, self.now_talkerId, type_=output.Output.CSV)
|
||||
self.outputThread.progressSignal.connect(self.output_progress)
|
||||
self.outputThread.rangeSignal.connect(self.set_progressBar_range)
|
||||
self.outputThread.okSignal.connect(self.hide_progress_bar)
|
||||
self.outputThread.start()
|
||||
print('导出csv')
|
||||
elif self.sender() == self.toHtmlAct:
|
||||
print('功能暂未实现')
|
||||
QMessageBox.warning(self,
|
||||
"别急别急",
|
||||
"马上就实现该功能"
|
||||
)
|
||||
|
||||
def hide_progress_bar(self, int):
|
||||
reply = QMessageBox(self)
|
||||
|
@ -83,9 +83,9 @@ class Ui_Dialog(object):
|
||||
self.btn_report = QtWidgets.QPushButton(self.frame)
|
||||
self.btn_report.setObjectName("btn_report")
|
||||
self.horizontalLayout_3.addWidget(self.btn_report)
|
||||
self.btn_output = QtWidgets.QPushButton(self.frame)
|
||||
self.btn_output.setObjectName("btn_output")
|
||||
self.horizontalLayout_3.addWidget(self.btn_output)
|
||||
self.toolButton_output = QtWidgets.QToolButton(self.frame)
|
||||
self.toolButton_output.setObjectName("toolButton_output")
|
||||
self.horizontalLayout_3.addWidget(self.toolButton_output)
|
||||
self.btn_back = QtWidgets.QPushButton(self.frame)
|
||||
self.btn_back.setObjectName("btn_back")
|
||||
self.horizontalLayout_3.addWidget(self.btn_back)
|
||||
@ -112,5 +112,5 @@ class Ui_Dialog(object):
|
||||
self.btn_analysis.setText(_translate("Dialog", "统计信息"))
|
||||
self.btn_emotion.setText(_translate("Dialog", "情感分析"))
|
||||
self.btn_report.setText(_translate("Dialog", "生成年度报告"))
|
||||
self.btn_output.setText(_translate("Dialog", "导出聊天记录"))
|
||||
self.toolButton_output.setText(_translate("Dialog", "导出聊天记录"))
|
||||
self.btn_back.setText(_translate("Dialog", "退出"))
|
||||
|
@ -204,7 +204,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_output">
|
||||
<widget class="QToolButton" name="toolButton_output">
|
||||
<property name="text">
|
||||
<string>导出聊天记录</string>
|
||||
</property>
|
||||
|
Loading…
Reference in New Issue
Block a user