最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python一站式進行提取文檔內(nèi)容(Word、Excel、PDF 和PPT)

 更新時間:2025年09月23日 09:39:55   作者:阿幸軟件雜貨間  
這篇文章主要為大家詳細介紹了Python如何實現(xiàn)一站式提取文檔內(nèi)容,例如Word、Excel、PDF 和PPT,文中的示例代碼講解詳細,有需要的小伙伴可以了解下

代碼介紹

本文旨在系統(tǒng)介紹如何利用Python主流庫從四種常見格式文檔中提取原始文本

相關軟件安裝

第三方庫安裝

在cmd界面輸入:

pip install python-docx openpyxl pdfminer.six python-pptx

程序打包

可以用這個一鍵打包文檔代碼

完整代碼

import os
import sys
from docx import Document
import openpyxl
from pdfminer.high_level import extract_text
from pptx import Presentation
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QLabel, 
                            QFileDialog, QTextEdit, QVBoxLayout, QHBoxLayout, 
                            QWidget, QProgressBar, QMessageBox, QGroupBox,
                            QRadioButton, QButtonGroup)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject
from PyQt5.QtGui import QFont


class BatchExtractorThread(QThread):
    """批量提取線程(支持單文件/文件夾)"""
    progress_updated = pyqtSignal(int)
    batch_finished = pyqtSignal(str, int, int)  # 匯總信息, 成功數(shù), 失敗數(shù)
    log_message = pyqtSignal(str)

    def __init__(self, input_path, output_path, is_folder=False, parent=None):
        super().__init__(parent)  # 綁定父對象,避免線程殘留
        self.input_path = input_path  # 輸入路徑(文件/文件夾)
        self.output_path = output_path  # 輸出路徑(文件/文件夾)
        self.is_folder = is_folder  # 是否為文件夾批量處理
        self.supported_exts = ['.docx', '.xlsx', '.pdf', '.pptx']  # 支持的格式
        self.success_count = 0  # 成功提取數(shù)
        self.fail_count = 0  # 提取失敗數(shù)
        self.is_running = False  # 線程運行狀態(tài)標記

    def run(self):
        self.is_running = True
        try:
            self.progress_updated.emit(5)
            if self.is_folder:
                # 處理文件夾:遍歷所有支持的文件
                self.log_message.emit(f"開始批量處理文件夾: {self.input_path}")
                file_list = self.get_supported_files(self.input_path)
                total_files = len(file_list)
                
                if total_files == 0:
                    self.log_message.emit("文件夾中未找到支持格式的文檔")
                    self.batch_finished.emit("未找到可處理的文檔", 0, 0)
                    self.progress_updated.emit(100)
                    return
                
                self.log_message.emit(f"共發(fā)現(xiàn) {total_files} 個支持格式的文檔")
                
                # 逐個處理文件
                for idx, file_path in enumerate(file_list):
                    if not self.is_running:  # 檢查是否需要終止
                        self.log_message.emit("提取任務已被終止")
                        return
                    self.process_single_file(file_path, self.output_path)
                    # 更新整體進度
                    progress = 5 + int((idx + 1) / total_files * 90)
                    self.progress_updated.emit(min(100, progress))
                    
                summary = f"批量處理完成!共處理 {total_files} 個文件,成功 {self.success_count} 個,失敗 {self.fail_count} 個"
                self.batch_finished.emit(summary, self.success_count, self.fail_count)
            else:
                # 處理單個文件
                self.log_message.emit(f"開始處理單個文件: {self.input_path}")
                if self.is_running:  # 確保線程未被終止
                    self.process_single_file(self.input_path, self.output_path, is_single=True)
                summary = f"單文件處理完成!成功: {self.success_count} 個,失敗: {self.fail_count} 個"
                self.batch_finished.emit(summary, self.success_count, self.fail_count)
                self.progress_updated.emit(100)
                
        except Exception as e:
            self.log_message.emit(f"處理過程總錯誤: {str(e)}")
            self.batch_finished.emit(f"處理失敗: {str(e)}", 0, 1)
        finally:
            self.is_running = False  # 標記線程結束

    def get_supported_files(self, folder_path):
        """獲取文件夾內(nèi)所有支持格式的文件(遞歸遍歷子文件夾)"""
        supported_files = []
        for root, _, files in os.walk(folder_path):
            for file in files:
                file_ext = os.path.splitext(file)[1].lower()
                if file_ext in self.supported_exts:
                    supported_files.append(os.path.join(root, file))
        return supported_files

    def process_single_file(self, file_path, output_root, is_single=False):
        """處理單個文件的提取和保存"""
        file_name = os.path.basename(file_path)
        file_ext = os.path.splitext(file_path)[1].lower()
        
        # 確定單個文件的輸出路徑
        if is_single:
            # 單文件模式:直接使用用戶指定的輸出路徑
            save_path = output_root
        else:
            # 批量模式:保持原文件夾結構,輸出到指定根目錄
            relative_path = os.path.relpath(os.path.dirname(file_path), self.input_path)
            output_dir = os.path.join(output_root, relative_path)
            os.makedirs(output_dir, exist_ok=True)
            # 生成輸出文件名(原文件名+_提取結果.txt)
            base_name = os.path.splitext(file_name)[0]
            save_path = os.path.join(output_dir, f"{base_name}_提取結果.txt")

        try:
            self.log_message.emit(f"正在處理: {file_name}")
            # 根據(jù)文件類型提取內(nèi)容
            if file_ext == '.docx':
                content = self.doc_extract(file_path)
                file_type = "Word"
            elif file_ext == '.xlsx':
                content = self.excel_extract(file_path)
                file_type = "Excel"
            elif file_ext == '.pdf':
                content = self.pdf_extract(file_path)
                file_type = "PDF"
            elif file_ext == '.pptx':
                content = self.ppt_extract(file_path)
                file_type = "PowerPoint"
            else:
                self.log_message.emit(f"跳過不支持的文件: {file_name}")
                self.fail_count += 1
                return

            # 保存內(nèi)容
            if content:
                self.save_content(content, save_path)
                self.log_message.emit(f"? 成功: {file_name} -> 保存至 {os.path.basename(save_path)}")
                self.success_count += 1
            else:
                self.log_message.emit(f"??  無內(nèi)容: {file_name}(未生成輸出文件)")
                self.fail_count += 1

        except Exception as e:
            self.log_message.emit(f"? 失敗: {file_name} - {str(e)}")
            self.fail_count += 1

    def doc_extract(self, file_path) -> str:
        """提取 Word (.docx) 文檔內(nèi)容"""
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        doc = Document(file_path)
        content = [para.text for para in doc.paragraphs]
        return '\n'.join(content)

    def excel_extract(self, file_path) -> str:
        """提取 Excel (.xlsx) 文檔內(nèi)容"""
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        data = []
        wb = openpyxl.load_workbook(file_path)
        for sheet in wb.sheetnames:
            data.append(f"=== 工作表: {sheet} ===")
            ws = wb[sheet]
            for i in range(1, ws.max_row + 1):
                row_data = []
                for j in range(1, ws.max_column + 1):
                    cell_val = str(ws.cell(i, j).value) if ws.cell(i, j).value is not None else ""
                    row_data.append(cell_val)
                data.append("\t".join(row_data))
        return '\n'.join(data)

    def pdf_extract(self, file_path) -> str:
        """提取 PDF (.pdf) 文檔內(nèi)容"""
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        return extract_text(file_path)

    def ppt_extract(self, file_path) -> str:
        """提取 PowerPoint (.pptx) 文檔內(nèi)容"""
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        content = []
        ppt = Presentation(file_path)
        for slide_idx, slide in enumerate(ppt.slides, 1):
            content.append(f"=== 幻燈片 {slide_idx} ===")
            for shape in slide.shapes:
                if hasattr(shape, 'text') and shape.text:
                    content.append(shape.text)
        return '\n'.join(content)

    def save_content(self, content, save_path) -> None:
        """保存提取的內(nèi)容到指定路徑"""
        with open(save_path, 'w', encoding='utf-8') as f:
            f.write(content)

    def stop(self):
        """終止線程(安全退出)"""
        self.is_running = False


class DocumentExtractorApp(QMainWindow):
    """文檔提取器主窗口(支持單文件/文件夾批量處理)"""
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.extractor_thread = None  # 線程對象初始化
        
    def init_ui(self):
        """初始化用戶界面(優(yōu)化布局間距)"""
        self.setWindowTitle("一站式提取Word、Excel、PDF 和PPT文檔內(nèi)容@阿幸")
        self.setGeometry(100, 100, 1000, 750)
        
        # 設置中文字體(優(yōu)化字體大小和間距)
        base_font = QFont()
        base_font.setFamily("SimHei")
        base_font.setPointSize(10)  # 基礎字體大小
        self.setFont(base_font)
        
        # 主布局(增加整體內(nèi)邊距)
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(15, 15, 15, 15)  # 主布局四周內(nèi)邊距
        main_layout.setSpacing(12)  # 布局內(nèi)組件間距
        
        # 1. 處理模式選擇(單文件/文件夾)- 核心優(yōu)化區(qū)域
        mode_group = QGroupBox("處理模式")
        mode_group.setFont(QFont("SimHei", 11, QFont.Bold))  # 分組標題加粗
        mode_layout = QHBoxLayout()
        # 增加模式布局內(nèi)邊距和間距,解決文字擁擠
        mode_layout.setContentsMargins(20, 15, 20, 15)  # 分組內(nèi)邊距
        mode_layout.setSpacing(30)  # 單選按鈕間距
        
        self.single_mode_radio = QRadioButton("單文件處理")
        self.folder_mode_radio = QRadioButton("文件夾批量處理")
        # 優(yōu)化單選按鈕字體和大小
        radio_font = QFont("SimHei", 10)
        self.single_mode_radio.setFont(radio_font)
        self.folder_mode_radio.setFont(radio_font)
        
        self.mode_btn_group = QButtonGroup(self)
        self.mode_btn_group.addButton(self.single_mode_radio, 0)
        self.mode_btn_group.addButton(self.folder_mode_radio, 1)
        self.single_mode_radio.setChecked(True)  # 默認單文件模式
        
        # 模式切換事件
        self.mode_btn_group.buttonClicked.connect(self.switch_mode)
        
        mode_layout.addWidget(self.single_mode_radio)
        mode_layout.addWidget(self.folder_mode_radio)
        mode_group.setLayout(mode_layout)
        main_layout.addWidget(mode_group)
        
        # 2. 路徑選擇區(qū)域
        path_group = QGroupBox("路徑設置")
        path_group.setFont(QFont("SimHei", 11, QFont.Bold))
        path_layout = QVBoxLayout()
        path_layout.setContentsMargins(15, 15, 15, 15)
        path_layout.setSpacing(10)
        
        # 輸入路徑選擇(文件/文件夾)
        input_layout = QHBoxLayout()
        input_layout.setSpacing(10)  # 標簽和按鈕間距
        self.input_label = QLabel("未選擇輸入(文件/文件夾)")
        self.input_label.setWordWrap(True)
        self.input_label.setStyleSheet("border: 1px solid #ccc; padding: 8px; min-height: 35px;")
        self.input_label.setFont(QFont("SimHei", 9))  # 標簽字體稍小,避免擁擠
        
        self.select_input_btn = QPushButton("選擇輸入路徑")
        self.select_input_btn.setFont(QFont("SimHei", 10))
        self.select_input_btn.setMinimumWidth(120)  # 固定按鈕寬度,避免變形
        self.select_input_btn.clicked.connect(self.select_input_path)
        
        input_layout.addWidget(self.input_label, 7)
        input_layout.addWidget(self.select_input_btn, 3)
        
        # 輸出路徑選擇(文件/文件夾)
        output_layout = QHBoxLayout()
        output_layout.setSpacing(10)
        self.output_label = QLabel("未選擇輸出(文件/文件夾)")
        self.output_label.setWordWrap(True)
        self.output_label.setStyleSheet("border: 1px solid #ccc; padding: 8px; min-height: 35px;")
        self.output_label.setFont(QFont("SimHei", 9))
        
        self.select_output_btn = QPushButton("選擇輸出路徑")
        self.select_output_btn.setFont(QFont("SimHei", 10))
        self.select_output_btn.setMinimumWidth(120)
        self.select_output_btn.clicked.connect(self.select_output_path)
        
        output_layout.addWidget(self.output_label, 7)
        output_layout.addWidget(self.select_output_btn, 3)
        
        # 添加到路徑布局
        path_layout.addLayout(input_layout)
        path_layout.addLayout(output_layout)
        path_group.setLayout(path_layout)
        main_layout.addWidget(path_group)
        
        # 3. 操作區(qū)域(新增終止按鈕)
        action_layout = QHBoxLayout()
        action_layout.setSpacing(15)  # 按鈕間距
        
        self.start_btn = QPushButton("開始提取")
        self.start_btn.setStyleSheet("font-size: 14px; padding: 10px; background-color: #4CAF50; color: white;")
        self.start_btn.setFont(QFont("SimHei", 10, QFont.Bold))
        self.start_btn.setMinimumWidth(150)
        self.start_btn.clicked.connect(self.start_extraction)
        self.start_btn.setEnabled(False)
        
        self.stop_btn = QPushButton("終止提取")
        self.stop_btn.setStyleSheet("font-size: 14px; padding: 10px; background-color: #f44336; color: white;")
        self.stop_btn.setFont(QFont("SimHei", 10, QFont.Bold))
        self.stop_btn.setMinimumWidth(150)
        self.stop_btn.clicked.connect(self.stop_extraction)
        self.stop_btn.setEnabled(False)  # 默認禁用
        
        self.clear_btn = QPushButton("清空日志")
        self.clear_btn.setStyleSheet("font-size: 14px; padding: 10px;")
        self.clear_btn.setFont(QFont("SimHei", 10))
        self.clear_btn.setMinimumWidth(150)
        self.clear_btn.clicked.connect(self.clear_logs)
        
        action_layout.addWidget(self.start_btn)
        action_layout.addWidget(self.stop_btn)
        action_layout.addWidget(self.clear_btn)
        main_layout.addLayout(action_layout)
        
        # 4. 進度條
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        self.progress_bar.setStyleSheet("margin-bottom: 10px; height: 25px;")
        main_layout.addWidget(self.progress_bar)
        
        # 5. 結果預覽區(qū)域
        result_group = QGroupBox("提取結果預覽(僅顯示最后一個文件的前2000字符)")
        result_group.setFont(QFont("SimHei", 11, QFont.Bold))
        result_layout = QVBoxLayout()
        result_layout.setContentsMargins(10, 10, 10, 10)
        
        self.result_text = QTextEdit()
        self.result_text.setReadOnly(True)
        self.result_text.setFont(QFont("SimHei", 9))
        result_layout.addWidget(self.result_text)
        
        result_group.setLayout(result_layout)
        main_layout.addWidget(result_group, 2)
        
        # 6. 日志區(qū)域
        log_group = QGroupBox("操作日志")
        log_group.setFont(QFont("SimHei", 11, QFont.Bold))
        log_layout = QVBoxLayout()
        log_layout.setContentsMargins(10, 10, 10, 10)
        
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setMaximumHeight(120)
        self.log_text.setFont(QFont("SimHei", 9))
        log_layout.addWidget(self.log_text)
        
        log_group.setLayout(log_layout)
        main_layout.addWidget(log_group)
        
        # 設置中心部件
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)
        
        # 初始化變量
        self.input_path = ""  # 輸入路徑(文件/文件夾)
        self.output_path = ""  # 輸出路徑(文件/文件夾)
        self.is_folder_mode = False  # 當前是否為文件夾模式

    def switch_mode(self):
        """切換處理模式(單文件/文件夾)"""
        # 切換模式前先檢查是否有正在運行的線程
        if self.extractor_thread and self.extractor_thread.isRunning():
            QMessageBox.warning(self, "警告", "正在進行提取操作,無法切換模式")
            # 恢復原選擇狀態(tài)
            if self.is_folder_mode:
                self.folder_mode_radio.setChecked(True)
            else:
                self.single_mode_radio.setChecked(True)
            return
        
        self.is_folder_mode = (self.mode_btn_group.checkedId() == 1)
        # 清空現(xiàn)有路徑并更新提示
        self.input_path = ""
        self.output_path = ""
        self.input_label.setText("未選擇輸入文件夾" if self.is_folder_mode else "未選擇輸入文件")
        self.output_label.setText("未選擇輸出文件夾" if self.is_folder_mode else "未選擇輸出文件")
        self.start_btn.setEnabled(False)
        self.log_message(f"已切換至{'文件夾批量處理' if self.is_folder_mode else '單文件處理'}模式")

    def select_input_path(self):
        """選擇輸入路徑(根據(jù)模式選擇文件或文件夾)"""
        # 選擇路徑前檢查線程狀態(tài)
        if self.extractor_thread and self.extractor_thread.isRunning():
            QMessageBox.warning(self, "警告", "正在進行提取操作,無法修改路徑")
            return
            
        if self.is_folder_mode:
            # 文件夾模式:選擇文件夾
            folder_path = QFileDialog.getExistingDirectory(
                self, "選擇輸入文件夾", "", QFileDialog.ShowDirsOnly
            )
            if folder_path:
                self.input_path = folder_path
                self.input_label.setText(f"輸入文件夾: {folder_path}")
                self.log_message(f"已選擇輸入文件夾: {folder_path}")
                # 自動建議輸出文件夾(原文件夾名+_提取結果)
                if not self.output_path:
                    folder_name = os.path.basename(folder_path)
                    self.output_path = os.path.join(os.path.dirname(folder_path), f"{folder_name}_提取結果")
                    self.output_label.setText(f"輸出文件夾: {self.output_path}")
        else:
            # 單文件模式:選擇文件
            file_path, _ = QFileDialog.getOpenFileName(
                self, "選擇文檔文件", "", 
                "支持的文件 (*.docx *.xlsx *.pdf *.pptx);;Word 文件 (*.docx);;Excel 文件 (*.xlsx);;PDF 文件 (*.pdf);;PPT 文件 (*.pptx);;所有文件 (*)"
            )
            if file_path:
                self.input_path = file_path
                self.input_label.setText(f"輸入文件: {os.path.basename(file_path)}")
                self.log_message(f"已選擇輸入文件: {file_path}")
                # 自動建議輸出文件
                if not self.output_path:
                    base_name = os.path.splitext(os.path.basename(file_path))[0]
                    self.output_path = os.path.join(os.path.dirname(file_path), f"{base_name}_提取結果.txt")
                    self.output_label.setText(f"輸出文件: {os.path.basename(self.output_path)}")
        
        self.check_btn_state()

    def select_output_path(self):
        """選擇輸出路徑(根據(jù)模式選擇文件或文件夾)"""
        # 選擇路徑前檢查線程狀態(tài)
        if self.extractor_thread and self.extractor_thread.isRunning():
            QMessageBox.warning(self, "警告", "正在進行提取操作,無法修改路徑")
            return
            
        if not self.input_path:
            QMessageBox.warning(self, "警告", f"請先選擇輸入{'文件夾' if self.is_folder_mode else '文件'}")
            return
        
        if self.is_folder_mode:
            # 文件夾模式:選擇輸出文件夾
            folder_path = QFileDialog.getExistingDirectory(
                self, "選擇輸出文件夾", os.path.dirname(self.input_path), QFileDialog.ShowDirsOnly
            )
            if folder_path:
                self.output_path = folder_path
                self.output_label.setText(f"輸出文件夾: {folder_path}")
                self.log_message(f"已選擇輸出文件夾: {folder_path}")
        else:
            # 單文件模式:選擇輸出文件
            default_name = os.path.splitext(os.path.basename(self.input_path))[0] + "_提取結果.txt"
            file_path, _ = QFileDialog.getSaveFileName(
                self, "保存提取結果", 
                os.path.join(os.path.dirname(self.input_path), default_name),
                "文本文件 (*.txt);;所有文件 (*)"
            )
            if file_path:
                self.output_path = file_path
                self.output_label.setText(f"輸出文件: {os.path.basename(file_path)}")
                self.log_message(f"已選擇輸出文件: {file_path}")
        
        self.check_btn_state()

    def check_btn_state(self):
        """檢查按鈕啟用狀態(tài)"""
        # 只有路徑都設置且無運行線程時,才能啟用開始按鈕
        can_start = bool(self.input_path) and bool(self.output_path)
        if self.extractor_thread and self.extractor_thread.isRunning():
            can_start = False
        self.start_btn.setEnabled(can_start)

    def log_message(self, message):
        """添加日志信息"""
        self.log_text.append(message)
        self.log_text.moveCursor(self.log_text.textCursor().End)

    def clear_logs(self):
        """清空日志和預覽"""
        # 提取中也允許清空日志
        self.log_text.clear()
        self.result_text.clear()
        self.log_message("已清空日志和結果預覽")

    def start_extraction(self):
        """開始提?。▎挝募?批量)"""
        # 再次檢查路徑有效性
        if not os.path.exists(self.input_path):
            QMessageBox.warning(self, "錯誤", f"輸入{'文件夾' if self.is_folder_mode else '文件'}不存在")
            return
            
        # 禁用相關按鈕,啟用終止按鈕
        self.select_input_btn.setEnabled(False)
        self.select_output_btn.setEnabled(False)
        self.start_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.result_text.clear()
        
        # 創(chuàng)建并啟動提取線程(綁定父對象,避免內(nèi)存泄漏)
        self.extractor_thread = BatchExtractorThread(
            input_path=self.input_path,
            output_path=self.output_path,
            is_folder=self.is_folder_mode,
            parent=self  # 關鍵:綁定到主窗口,確保線程隨窗口生命周期管理
        )
        self.extractor_thread.progress_updated.connect(self.update_progress)
        self.extractor_thread.batch_finished.connect(self.on_extraction_finished)
        self.extractor_thread.log_message.connect(self.log_message)
        
        # 單文件模式下綁定預覽功能
        if not self.is_folder_mode:
            self.extractor_thread.process_single_file = self.wrap_single_file_process(
                self.extractor_thread.process_single_file
            )
        
        self.extractor_thread.start()

    def stop_extraction(self):
        """終止提取操作"""
        if self.extractor_thread and self.extractor_thread.isRunning():
            reply = QMessageBox.question(
                self, "確認終止", 
                "確定要終止當前提取操作嗎?已處理的文件會保留,未處理的將停止。",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No
            )
            if reply == QMessageBox.Yes:
                self.extractor_thread.stop()  # 安全終止線程
                self.log_message("已終止提取操作")
                # 恢復按鈕狀態(tài)
                self.select_input_btn.setEnabled(True)
                self.select_output_btn.setEnabled(True)
                self.start_btn.setEnabled(True)
                self.stop_btn.setEnabled(False)
                self.progress_bar.setValue(0)
                self.progress_bar.setVisible(False)

    def wrap_single_file_process(self, original_func):
        """包裝單文件處理函數(shù),用于獲取預覽內(nèi)容"""
        def wrapper(file_path, output_root, is_single=False):
            # 先執(zhí)行原處理邏輯
            original_func(file_path, output_root, is_single)
            # 讀取保存的文件內(nèi)容用于預覽
            if os.path.exists(output_root):
                with open(output_root, 'r', encoding='utf-8') as f:
                    content = f.read()
                # 顯示前2000字符預覽
                preview = content[:2000]
                if len(content) > 2000:
                    preview += "\n\n... 內(nèi)容過長,僅顯示前2000字符 ..."
                self.result_text.setText(preview)
        return wrapper

    def update_progress(self, value):
        """更新進度條"""
        self.progress_bar.setValue(value)

    def on_extraction_finished(self, summary, success_count, fail_count):
        """提取完成回調(diào)(核心修復:保持軟件運行)"""
        # 關鍵修復:恢復所有操作按鈕狀態(tài),不終止程序
        self.select_input_btn.setEnabled(True)
        self.select_output_btn.setEnabled(True)
        self.start_btn.setEnabled(True)
        self.stop_btn.setEnabled(False)  # 提取完成后禁用終止按鈕
        self.progress_bar.setVisible(False)  # 隱藏進度條
        
        # 顯示匯總信息(使用information而非critical,避免誤操作)
        QMessageBox.information(self, "處理完成", summary)
        self.log_message(f"\n{summary}")
        
        # 清理線程對象(避免殘留)
        self.extractor_thread = None

    def closeEvent(self, event):
        """窗口關閉事件(安全處理線程)"""
        if self.extractor_thread and self.extractor_thread.isRunning():
            reply = QMessageBox.question(
                self, "確認關閉", 
                "正在進行提取操作,強制關閉可能導致文件損壞,確定要關閉嗎?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No
            )
            if reply == QMessageBox.Yes:
                self.extractor_thread.stop()
                self.extractor_thread.wait()  # 等待線程安全退出
                event.accept()
            else:
                event.ignore()
        else:
            event.accept()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    # 確保中文顯示正常
    app.setFont(QFont("SimHei", 10))
    window = DocumentExtractorApp()
    window.show()
    # 關鍵修復:正確的事件循環(huán)退出邏輯
    exit_code = app.exec_()
    # 程序退出前確保線程已終止
    if hasattr(window, 'extractor_thread') and window.extractor_thread and window.extractor_thread.isRunning():
        window.extractor_thread.stop()
        window.extractor_thread.wait()
    sys.exit(exit_code)

軟件使用

可以選擇單文件也可以選擇文件夾

點擊開始提取

以上就是Python一站式進行提取文檔內(nèi)容(Word、Excel、PDF 和PPT)的詳細內(nèi)容,更多關于Python提取文檔內(nèi)容的資料請關注腳本之家其它相關文章!

相關文章

  • Python利用pywin32實現(xiàn)自動操作電腦

    Python利用pywin32實現(xiàn)自動操作電腦

    在windows系統(tǒng)上,重復性的操作可以用Python腳本來完成,其中常用的模塊是win32gui、win32con、win32api,要使用這三個模塊需要先安裝pywin32。本文就為大家介紹了如何利用這些模塊實現(xiàn)自動操作電腦,感興趣的可以了解一下
    2022-11-11
  • python中單雙下劃線的區(qū)別對比分析

    python中單雙下劃線的區(qū)別對比分析

    Python中存在一些特殊的方法,有些方法以雙下劃線 “__” 開頭和結尾,它們是Python的魔法函數(shù),比如__init__()和__str__等等,不用要這種方式命名自己的變量或者函數(shù),這篇文章主要介紹了python里面單雙下劃線的區(qū)別,需要的朋友可以參考下
    2023-04-04
  • python中for語句簡單遍歷數(shù)據(jù)的方法

    python中for語句簡單遍歷數(shù)據(jù)的方法

    這篇文章主要介紹了python中for語句簡單遍歷數(shù)據(jù)的方法,以一個簡單實例形式分析了Python中for語句遍歷數(shù)據(jù)的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-05-05
  • python?selenium參數(shù)詳解和實現(xiàn)案例

    python?selenium參數(shù)詳解和實現(xiàn)案例

    這篇文章主要介紹了python?selenium參數(shù)詳解和實現(xiàn)案例,無頭模式添加,可以讓selenium模擬登錄,進入到后臺運行,本文以登錄打開公司內(nèi)網(wǎng)下載數(shù)據(jù)為例,給大家詳細講解,需要的朋友可以參考下
    2022-10-10
  • Numpy數(shù)組轉置的兩種實現(xiàn)方法

    Numpy數(shù)組轉置的兩種實現(xiàn)方法

    下面小編就為大家分享一篇Numpy數(shù)組轉置的兩種實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • 解決pyinstaller打包運行程序時出現(xiàn)缺少plotly庫問題

    解決pyinstaller打包運行程序時出現(xiàn)缺少plotly庫問題

    這篇文章主要介紹了解決pyinstaller打包運行程序時出現(xiàn)缺少plotly庫問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-06-06
  • 使用python快速生成nodejs項目文件結構

    使用python快速生成nodejs項目文件結構

    這篇文章主要介紹了如何使用Python快速生成nodejs項目文件結構,主要是為了解決AI Studio生成的Node.js程序的存放文件夾并快速生成問題的工具軟件,有需要的可以了解下
    2026-01-01
  • Pytorch抽取網(wǎng)絡層的Feature Map(Vgg)實例

    Pytorch抽取網(wǎng)絡層的Feature Map(Vgg)實例

    今天小編就為大家分享一篇Pytorch抽取網(wǎng)絡層的Feature Map(Vgg)實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Django設置Postgresql的操作

    Django設置Postgresql的操作

    這篇文章主要介紹了Django設置Postgresql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • 使用go和python遞歸刪除.ds store文件的方法

    使用go和python遞歸刪除.ds store文件的方法

    使用python和go遞歸刪除.DS_Store文件,.DS_Store (英文全稱 Desktop Services Store)是一種由蘋果公司的Mac OS X操作系統(tǒng)所創(chuàng)造的隱藏文件,目的在于存貯文件夾的自定義屬性
    2014-01-01

最新評論

旌德县| 那坡县| 昌宁县| 元朗区| 文水县| 通化市| 筠连县| 东辽县| 道真| 武义县| 车致| 会东县| 略阳县| 满洲里市| 南岸区| 昌宁县| 密云县| 普陀区| 乡宁县| 昆山市| 杨浦区| 小金县| 云安县| 东阿县| 炉霍县| 棋牌| 曲周县| 通渭县| 永济市| 商河县| 德州市| 中山市| 庆城县| 通州区| 扎兰屯市| 钟山县| 泾阳县| 东乌珠穆沁旗| 石台县| 永定县| 阳原县|