import pandas as pd
# from pandasql import sqldf # 用 SQL 语句操作 panda 模块
from pandasql import * # 用 SQL 语句操作 panda 模块
import os # 处理文件模块
import shutil # 删除非空文件夹模块
import time
from PySide2.QtWidgets import QApplication, QMessageBox, QFileDialog, QMainWindow
from PySide2.QtUiTools import QUiLoader
from PySide2.QtGui import QIcon
from threading import Thread, Lock
from PySide2.QtCore import Signal, QObject
# 多线程处理
# 信号库
class SignalStore(QObject):
# 定义一种信号
progress_update = Signal(int,str)
# 子线程让主线程弹窗
msg = Signal(str)
# 导入显示框添加内容信号
# 实例花
so = SignalStore()
def getTime():
a = time.strftime('%H:%M:%S', time.localtime(time.time()))
# return time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
return a
# 数据处理
class DataHandle:
def __init__(self):
self.ui = QUiLoader().load('static/web.ui')
# 连接信号到处理的 slot 函数
so.progress_update.connect(self.setProgress)
so.msg.connect(self.son_msg)
# 0. 按钮事件
self.ui.pushButton.clicked.connect(self.changeFileExcel) # 选择文件事件
self.ui.pushButton_2.clicked.connect(self.to_begin) # 开始提取事件
self.fieldName = '' # 筛选字段名的内容
self.content = '' # 筛选字段的内容
self.num = 0 # 计数,提取到有内容的文件数量
self.statistical = 0 # 所有文件条数汇总
# 1. 选择文件夹路径,获取到文件夹下所有文件的绝对路径
self.filePath = '' # 选择的文件夹路径
self.fileList = [] # 文件夹路径下所有文件的绝对路径集合
self.fileName = [] # 文件名称集合
self.excelPath = '' # 当前文件的 excel 路径
# 2. 开始依次读取 excel 文件,并进行处理
self.i = 0
self.bankLock = Lock()
self.excel = '' # 读取导入的表数据
# 选择文件点击事件
def changeFileExcel(self):
self.fileName = []
self.fileList= []
self.filePath = QFileDialog.getExistingDirectory(QMainWindow(), "选择文件夹")
print('文件夹路径', self.filePath)
# 准备一个空列表,用来存储遍历数据
'''
root :代表目录的路径
dirs :一个list,包含了dirpath下所有子目录文件夹的名字
files :一个list,包含了所有非目录文件的名字
'''
for root, dirs, files in os.walk(self.filePath):
# fileName.append()
# 循环遍历列表:files【所有文件】,仅得到不包含路径的文件名
for fileObj in files:
# 空列表写入遍历的文件名称,兵勇目录路径拼接文件名称
path = os.path.join(root, fileObj).replace('\\', '/')
self.fileName.append(fileObj)
self.fileList.append(path)
print('文件名集合', self.fileName)
print('文件路径集合', self.fileList)
self.ui.textBrowser.setText(self.filePath)
# 处理进度条的 slot 函数
def setProgress(self, value,text):
self.ui.progressBar_2.setValue(value)
self.ui.textBrowser_2.append(text)
if value == len(self.fileList):
self.end_time = time.time()
messageBox = QMessageBox()
messageBox.setWindowTitle('提取结果')
messageBox.setText(f'提取筛选内容成功,共<span style="color:red;font-weight:bold;">{self.num}</span>个文件,'
f'<span style="color:red;font-weight:bold;">{self.statistical}</span>条内容')
messageBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
buttonY = messageBox.button(QMessageBox.Yes)
buttonY.setText('打开提取结果文件夹')
buttonN = messageBox.button(QMessageBox.No)
buttonN.setText('退出')
messageBox.exec_()
if messageBox.clickedButton() == buttonY:
# print('你选择了yes')
start_directory = r'提取结果' # 打开文件夹提取结果
os.startfile(start_directory)
# if choice == QMessageBox.No:
# # print('你选择了no')
# pass
# QMessageBox.information(
# self.ui,
# '成功',
# f'提取筛选内容成功,共<span style="color:red;font-weight:bold;">{self.num}</span>个文件')
# 开始提取事件
def to_begin(self):
self.ui.pushButton_2.setEnabled(False)
self.fieldName = self.ui.lineEdit.text()
self.content = self.ui.lineEdit_2.text()
print(self.fieldName)
print(self.content)
try:
ml = os.getcwd() + '\\提取结果' # 获取当前目录
judge = os.path.exists(ml) # 判断疑点数据文件夹是否存在,存在就删除重新创建
if judge:
shutil.rmtree(ml)
os.mkdir(os.getcwd() + '\\提取结果') # 创建疑点数据文件夹
self.i = 0
except PermissionError as e:
e = str(e)
self.msg('错误', e)
return
self.ui.progressBar_2.setRange(0, len(self.fileList))
self.ui.progressBar_2.setValue(0)
self.ui.textBrowser_2.append(f'开始提取数据{getTime()}')
self.num = 0
self.statistical = 0
for i,item in enumerate(self.fileList):
sql = f"""select * from tables where `{self.fieldName}` like '%{self.content}%'"""
self.i = self.i + 1
dataQuery_son = Thread(target=self.dataQuery, args=(item,self.fileName[i], sql))
dataQuery_son.setDaemon(True) # 设置成守护线程,主程序退出,线程也结束
dataQuery_son.start()
dataQuery_son.join()
so.progress_update.emit(self.i, f'提取文件:{self.fileName[i]} 完成')
self.ui.pushButton_2.setEnabled(True)
# 对数据表 self.excel 进行查询处理
def dataQuery(self,item, excelName, q):
self.bankLock.acquire()
try:
self.excelPath = item
print('文件路径', self.excelPath)
tableArr = self.excelPath.split(".")
print("文件类型", tableArr[-1])
if tableArr[-1] == "csv":
try:
print('读取的csv')
ex = pd.read_csv(self.excelPath, encoding='ANSI', keep_default_na=False, low_memory=False, sep=',')
# labels = list(ex.columns.values)
# print('表头',labels)
except BaseException as e:
e = str(e)
so.msg.emit(f'错误,读取 csv 出现问题:{e}')
self.toin = 1 # 让导入计时停止
# self.ui.pushButton_3.setEnabled(True)
return
else:
ex = pd.read_excel(self.excelPath, keep_default_na=False)
print('读取的excel')
# 将 excel 读成表格形式, excel 就是要操作的数据表
excel = pd.DataFrame(ex)
a = list(excel.keys())
# a = sorted(a, key=lambda i: len(i)) # 将表头按字符串长度进行排序
self.tableTitle = a
print("导入的表头", a)
print('table数据', excel)
global tables
tables = excel
pysqldf = lambda sql: sqldf(sql, globals()) # 为了避免每次都要传入dataframes,可以定义一个lambda
sql = q
# try:
df = pysqldf(sql) # 执行 sql
print(f'表名{excelName}\n'
f'列数:{df.shape[1]}\n'
f'行数:{df.shape[0]}')
self.statistical += df.shape[0]
# 如果查出来没有数据,则代表没有该项错误,不需要生成 excel 表
if df.shape[0] > 0:
# self.errorNum += 1 # 增加一种错误类型计数
thePath = os.getcwd() + '\\提取结果' # 获取存取路径
# writer = pd.ExcelWriter(thePath + f'\\{excelName}.csv') # 创建错误数据 excel
name = excelName.split('.')[0]
writer = thePath + f'\\{name}.csv' # 创建错误数据 excel
# 将容易变成科学计数法的列保存为字符串
for item in self.tableTitle:
# df[item] = '="' + df[item].apply(str) + '"'
df[item] = df[item].apply(str) + '\t'
df.to_csv(writer, float_format='{:f}'.format, columns=self.tableTitle, index=False, sep=',',
encoding='ANSI')
self.num += 1
except BaseException as e:
print('错误', e)
e = '存在异常:' + str(e)
# so.progress_update.emit(self.i,e)
print("存在异常", e) # 打印所有异常
# self.bankLock.release()
# return
self.bankLock.release()
# over
# 子线程让主线程弹窗,表头有误
def son_msg(self, str):
arr = str.split(',')
print("arr", len(arr), arr[1])
QMessageBox.critical(
self.ui,
arr[0],
arr[1]
)
# 弹框
def msg(self, info, text):
QMessageBox.critical(
self.ui,
info,
text
)
if __name__ == '__main__':
# thread = Thread(target=DataHandle)
# thread.start()
app = QApplication([])
# 加载 icon
app.setWindowIcon(QIcon("static/logo.ico"))
handle = DataHandle()
handle.ui.show()
app.exec_()