支持导出csv格式聊天记录

This commit is contained in:
shuaikangzhou 2023-10-26 22:45:44 +08:00
parent f1d0ff2f83
commit 0c00298728
6 changed files with 184 additions and 45 deletions

View File

@ -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">{
&quot;lastFilter&quot;: {
&quot;state&quot;: &quot;OPEN&quot;
}
}</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 @@
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/Program Files/Python310/Scripts/pyuic5.exe&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;project.propVCSSupport.CommitDialog&quot;
&quot;settings.editor.selected.configurable&quot;: &quot;reference.settings.ide.settings.new.ui&quot;
}
}</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">

View File

@ -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()

View File

@ -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()

View File

@ -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)

View File

@ -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", "退出"))

View File

@ -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>