当前位置:首页>python>Python+PyQt6 利用PaddleOCR3.4.0识别图片表格转 Word - 纯原生桌面应用开发指南

Python+PyQt6 利用PaddleOCR3.4.0识别图片表格转 Word - 纯原生桌面应用开发指南

  • 2026-02-09 13:40:04
Python+PyQt6 利用PaddleOCR3.4.0识别图片表格转 Word - 纯原生桌面应用开发指南

基于 PaddleOCR 表格识别技术的 PyQt6 原生桌面应用实现,无需 Web 引擎依赖

项目简介

本项目是一个基于 PyQt6 开发的桌面应用程序,用于将包含表格的图片自动识别并转换为 Word 文档。与 Flask Web 版本不同,本应用完全使用 PyQt6 原生组件实现,无需浏览器支持,提供更好的用户体验和离线使用能力。

为什么选择 PyQt6 原生实现?

特性
PyQt6 原生
Flask Web
离线使用
✅ 完全支持
⚠️ 需要服务器
系统资源
✅ 占用低
中等
用户体验
✅ 原生体验
依赖浏览器
文件操作
✅ 原生对话框
上传/下载
安装部署
需安装 Python 环境
需部署服务

功能特点

🎯 核心功能

1.图片上传

    • 拖拽上传:支持文件直接拖入窗口
    • 点击选择:传统文件选择对话框
    • 格式支持:JPG、PNG
    • 大小限制:最大 16MB

2.表格识别

    • 基于 PaddleOCR TableRecognitionPipelineV2
    • 自动检测有线/无线表格
    • 支持文档方向分类
    • CPU 推理,无需 GPU
3.双模式预览
    • 📊 表格视图:使用 QTableWidget 展示结构化数据

    • 🌐 HTML 视图:使用 QTextEdit 展示原始 HTML 源码

4.文档导出

    • 📄 Word 文档 (.docx)
    • 📄 JSON 原始数据 (.json)

🎨 UI 特性

  • 现代化界面:渐变标题栏、圆角按钮、阴影效果

  • 响应式布局:自适应窗口大小调整

  • 多页面切换:上传 → 预览 → 进度 → 结果

  • 进度反馈:实时进度条 + 状态文字


技术架构

技术栈

┌─────────────────────────────────────────┐
│           PyQt6 原生 GUI 层              │
│  QTableWidget | QTextEdit | QThread     │
├─────────────────────────────────────────┤
│           业务逻辑层                     │
│  TableRecognizer | ProcessingThread     │
├─────────────────────────────────────────┤
│           文档处理层                     │
│  python-docx | BeautifulSoup            │
├─────────────────────────────────────────┤
│           AI 推理层                      │
│  PaddleOCR | paddlepaddle               │
└─────────────────────────────────────────┘

核心组件


环境准备

系统要求

  • Python 3.8+
  • 操作系统:Windows / macOS / Linux
  • 内存:建议 4GB+
  • 磁盘空间:约 2GB(含模型文件)

安装依赖

# 创建虚拟环境 建议python3.10
python -m venv venv
source venv/bin/activate  # Linux/macOS
# 或: venv\Scripts\activate  # Windows


# 安装 PyQt6
pip install PyQt6


# 安装 PaddlePaddle (CPU 版本)
pip install paddlepaddle==3.2.0  -i https://www.paddlepaddle.org.cn/packages/stable/cpu/


# 安装 PaddleX (包含 OCR 模型)
pip install paddleocr==3.4.0
按系统而定
pip install "paddle['ocr']"


# 安装文档处理库
pip install beautifulsoup4 python-docx

模型准备

首次运行会自动下载模型到 ~/.paddlex/official_models/

所需模型清单:

  • PP-DocLayout-L - 文档布局分析

  • PP-LCNet_x1_0_doc_ori - 文档方向分类

  • PP-LCNet_x1_0_table_cls - 表格分类

  • SLANeXt_wired / SLANeXt_wireless - 表格结构识别

  • RT-DETR-L_wired/wireless_table_cell_det - 单元格检测

  • PP-OCRv4_server_det/rec_doc - 文字检测与识别


核心代码解析

1. Paddle 环境配置

import os


# 必须在导入 paddle 前设置
os.environ['FLAGS_use_mkldnn'] = 'False'
os.environ['FLAGS_enable_pir_api'] = 'False'
os.environ['PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK'] = 'True'

注意:这些环境变量用于禁用 MKL-DNN 加速和 PIR 新执行器,避免 Paddle 3.x 版本的兼容性问题。

2. 表格识别器(单例模式)

classTableRecognizer:
"""表格识别器 - 延迟初始化模型"""
    _instance = None
    _pipe = None

def__new__(cls):
if cls._instance isNone:
            cls._instance = super().__new__(cls)
return cls._instance

defget_pipe(self):
ifself._pipe isNone:
import paddle
            paddle.set_flags({'FLAGS_use_mkldnn'False})
            paddle.set_device('cpu')

from paddleocr import TableRecognitionPipelineV2
self._pipe = TableRecognitionPipelineV2(
                use_doc_orientation_classify=True,
                device='cpu',
            )
returnself._pipe

设计要点

  • 使用单例模式避免重复加载模型
  • 延迟初始化,首次使用时才加载
  • 约 1.3GB 模型文件,加载需要一定时间

3. 后台处理线程

classProcessingThread(QThread):
"""后台处理线程"""
    progress_signal = pyqtSignal(intstr)  # 进度, 消息
    complete_signal = pyqtSignal(boolstrstrstrstr)

defrun(self):
try:
# 1. 加载模型
self.progress_signal.emit(5"正在加载模型...")
            pipe = TableRecognizer().get_pipe()

# 2. 识别表格
self.progress_signal.emit(20"正在识别表格...")
            results = pipe.predict(self.image_path)

# 3. 生成 Word
self.progress_signal.emit(60"正在生成 Word 文档...")
# ... 处理逻辑

self.progress_signal.emit(100"处理完成!")
self.complete_signal.emit(True, html, word_path, json_path, "")
except Exception as e:
self.complete_signal.emit(False""""""str(e))

关键点

  • 继承 QThread 避免阻塞主界面

  • 使用 pyqtSignal 与主线程通信

  • 分阶段报告进度

4. 拖拽上传区域

classDropArea(QFrame):
"""自定义拖放区域"""
    file_dropped = pyqtSignal(str)

def__init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)  # 启用拖拽

defdragEnterEvent(self, event: QDragEnterEvent):
if event.mimeData().hasUrls():
            event.acceptProposedAction()

defdropEvent(self, event: QDropEvent):
        urls = event.mimeData().urls()
if urls:
            file_path = urls[0].toLocalFile()
self.file_dropped.emit(file_path)

5. HTML 表格转 Word

defappend_html_tables_to_word(doc, html):
"""将 HTML 表格添加到 Word 文档"""
    soup = BeautifulSoup(html, "html.parser")
    table_elements = soup.find_all("table")

for table in table_elements:
        rows = list(table.find_all("tr"))
# 计算行列数
        max_row = len(rows)
        max_col = max(len(row.find_all(["td""th"])) for row in rows)

# 创建 Word 表格
        word_table = doc.add_table(rows=max_row, cols=max_col)
        word_table.style = "Table Grid"

# 填充单元格
for r_idx, row inenumerate(rows):
            cells = row.find_all(["td""th"])
for c_idx, cell inenumerate(cells):
                word_cell = word_table.cell(r_idx, c_idx)
                word_cell.text = cell.get_text(strip=True)
# 设置样式...

完整代码

#!/usr/bin/env python3
"""
PyQt6 图片表格识别转 Word - 纯原生 PyQt6 版本


特点:
- 完全使用 PyQt6 原生组件,无 Web 引擎依赖
- 表格预览使用 QTableWidget 原生表格
- HTML 源码使用 QTextEdit 纯文本显示


用法:
  python app2_pyqt6_native.py
"""



import os
import sys
import json
import time
import uuid
from datetime import datetime
from pathlib import Path


# 设置 PaddlePaddle 环境变量(必须在导入 paddle 前设置)
os.environ['FLAGS_use_mkldnn'] = 'False'
os.environ['FLAGS_enable_pir_api'] = 'False'
os.environ['PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK'] = 'True'
os.environ['PADDLEX_HOME'] = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), 
'models'
)


from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QProgressBar, QTextEdit, QFileDialog,
    QMessageBox, QFrame, QTableWidget, QTableWidgetItem,
    QHeaderView, QStackedWidget
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import QFont, QDragEnterEvent, QDropEvent, QPixmap


from bs4 import BeautifulSoup
from docx import Document
from docx.shared import Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn


# 目录配置
UPLOAD_FOLDER = 'uploads'
OUTPUT_FOLDER = 'output'
JSON_FOLDER = 'output/json'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)
os.makedirs(JSON_FOLDER, exist_ok=True)


FONT_NAME = "微软雅黑"
FONT_SIZE = 11



classTableRecognizer:
"""表格识别器 - 单例模式延迟初始化"""
    _instance = None
    _pipe = None

def__new__(cls):
if cls._instance isNone:
            cls._instance = super().__new__(cls)
return cls._instance

defget_pipe(self):
ifself._pipe isNone:
import paddle
            paddle.set_flags({'FLAGS_use_mkldnn'False})
            paddle.set_device('cpu')

from paddleocr import TableRecognitionPipelineV2
print("[系统] 正在初始化表格识别模型...")
self._pipe = TableRecognitionPipelineV2(
                use_doc_orientation_classify=True,
                device='cpu',
            )
print("[系统] 模型初始化完成")
returnself._pipe



classProcessingThread(QThread):
"""后台处理线程"""
    progress_signal = pyqtSignal(intstr)
    complete_signal = pyqtSignal(boolstrstrstrstr)

def__init__(self, image_path, output_filename):
super().__init__()
self.image_path = image_path
self.output_filename = output_filename
self.json_filename = output_filename.replace('.docx''.json')
self.json_path = os.path.join(JSON_FOLDER, self.json_filename)
self.word_path = os.path.join(OUTPUT_FOLDER, self.output_filename)

defrun(self):
try:
self.progress_signal.emit(5"正在加载模型...")
            pipe = TableRecognizer().get_pipe()

self.progress_signal.emit(20"正在识别表格...")
            results = pipe.predict(self.image_path)

            result_data = None
            html_content = ""

for res in results:
ifhasattr(res, 'json'):
                    result_data = res.json
ifhasattr(res, 'html'):
                    html_data = res.html
                    html_content = html_data ifisinstance(html_data, strelsestr(html_data)

if result_data:
withopen(self.json_path, 'w', encoding='utf-8'as f:
                        json.dump(result_data, f, ensure_ascii=False, indent=2)
break

ifnot result_data andnot html_content:
self.complete_signal.emit(False"""""""未识别到表格内容")
return

self.progress_signal.emit(60"正在生成 Word 文档...")

            doc = Document()
            doc.styles["Normal"].font.name = FONT_NAME
            doc.styles["Normal"]._element.rPr.rFonts.set(qn("w:eastAsia"), FONT_NAME)

# 提取表格并写入
            soup = BeautifulSoup(html_content, "html.parser")
for table in soup.find_all("table"):
                rows = list(table.find_all("tr"))
ifnot rows:
continue
                max_col = max(len(row.find_all(["td""th"])) for row in rows)
                word_table = doc.add_table(rows=len(rows), cols=max_col)
                word_table.style = "Table Grid"

for r_idx, row inenumerate(rows):
                    cells = row.find_all(["td""th"])
for c_idx, cell inenumerate(cells):
                        word_table.cell(r_idx, c_idx).text = cell.get_text(strip=True)
                doc.add_paragraph()

            doc.save(self.word_path)

self.progress_signal.emit(100"处理完成!")
self.complete_signal.emit(True, html_content, self.word_path, self.json_path, "")

except Exception as e:
import traceback
            traceback.print_exc()
self.complete_signal.emit(False""""""str(e))



classDropArea(QFrame):
"""拖放上传区域"""
    file_dropped = pyqtSignal(str)

def__init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.setMinimumHeight(200)
self.setFrameShape(QFrame.Shape.StyledPanel)
self.setStyleSheet("""
            DropArea {
                border: 3px dashed 
#cccccc;
                border-radius: 12px;
                background-color: #fafafa;
            }
            DropArea[dragOver="true"] {
                border-color: #667eea;
                background-color: #e8eeff;
            }
        """)

        layout = QVBoxLayout(self)
        layout.setAlignment(Qt.AlignmentFlag.AlignCenter)

self.icon_label = QLabel("📁")
self.icon_label.setStyleSheet("font-size: 48px;")
self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

self.text_label = QLabel("点击或拖拽上传图片")
self.text_label.setStyleSheet("font-size: 18px; color: #555;")
self.text_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

self.hint_label = QLabel("支持 JPG、PNG 格式,最大 16MB")
self.hint_label.setStyleSheet("font-size: 12px; color: #999;")
self.hint_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        layout.addWidget(self.icon_label)
        layout.addWidget(self.text_label)
        layout.addWidget(self.hint_label)

defmousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
            file_path, _ = QFileDialog.getOpenFileName(
self"选择图片""""图片文件 (*.jpg *.jpeg *.png)"
            )
if file_path:
self.file_dropped.emit(file_path)

defdragEnterEvent(self, event: QDragEnterEvent):
if event.mimeData().hasUrls():
self.setProperty("dragOver"True)
self.style().unpolish(self)
self.style().polish(self)
            event.acceptProposedAction()

defdragLeaveEvent(self, event):
self.setProperty("dragOver"False)
self.style().unpolish(self)
self.style().polish(self)

defdropEvent(self, event: QDropEvent):
self.setProperty("dragOver"False)
self.style().unpolish(self)
self.style().polish(self)

        urls = event.mimeData().urls()
if urls:
            file_path = urls[0].toLocalFile()
if file_path.lower().endswith(('.jpg''.jpeg''.png')):
self.file_dropped.emit(file_path)



classMainWindow(QMainWindow):
"""主窗口"""

def__init__(self):
super().__init__()
self.setWindowTitle("📊 图片表格转 Word")
self.setMinimumSize(900700)

self.current_image_path = None
self.current_word_path = None
self.current_json_path = None
self.processing_thread = None

self.init_ui()
self.apply_styles()

definit_ui(self):
        central_widget = QWidget()
self.setCentralWidget(central_widget)

        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(0000)

# 标题栏
        header = QWidget()
        header.setFixedHeight(120)
        header.setStyleSheet("""
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #667eea, stop:1 #764ba2);
        """
)
        header_layout = QVBoxLayout(header)

        title = QLabel("📊 图片表格转 Word")
        title.setStyleSheet("font-size: 28px; font-weight: bold; color: white;")
        title.setAlignment(Qt.AlignmentFlag.AlignCenter)

        subtitle = QLabel("上传包含表格的图片,自动识别并转换为 Word 文档")
        subtitle.setStyleSheet("font-size: 14px; color: rgba(255,255,255,0.9);")
        subtitle.setAlignment(Qt.AlignmentFlag.AlignCenter)

        header_layout.addWidget(title)
        header_layout.addWidget(subtitle)
        main_layout.addWidget(header)

# 内容区域
        content = QWidget()
        content.setStyleSheet("background-color: white; border-radius: 16px; margin: 20px;")
        content_layout = QVBoxLayout(content)

# 页面切换
self.preview_stack = QStackedWidget()

# 上传页面
self.upload_page = QWidget()
        upload_layout = QVBoxLayout(self.upload_page)
self.drop_area = DropArea()
self.drop_area.file_dropped.connect(self.handle_file)
        upload_layout.addStretch()
        upload_layout.addWidget(self.drop_area)
        upload_layout.addStretch()

# 预览页面
self.preview_page = QWidget()
        preview_layout = QVBoxLayout(self.preview_page)
self.preview_label = QLabel()
self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.preview_label.setMinimumSize(400300)
self.preview_label.setScaledContents(True)
        preview_layout.addWidget(self.preview_label)

        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        remove_btn = QPushButton("移除图片")
        remove_btn.clicked.connect(self.reset_upload)
        process_btn = QPushButton("开始识别")
        process_btn.clicked.connect(self.start_processing)
        btn_layout.addWidget(remove_btn)
        btn_layout.addWidget(process_btn)
        btn_layout.addStretch()
        preview_layout.addLayout(btn_layout)

# 进度页面
self.progress_page = QWidget()
        progress_layout = QVBoxLayout(self.progress_page)
self.progress_bar = QProgressBar()
self.progress_text = QLabel("准备中...")
self.progress_text.setAlignment(Qt.AlignmentFlag.AlignCenter)
        progress_layout.addStretch()
        progress_layout.addWidget(self.progress_bar)
        progress_layout.addWidget(self.progress_text)
        progress_layout.addStretch()

# 结果页面
self.result_page = QWidget()
        result_layout = QVBoxLayout(self.result_page)

        success_label = QLabel("✅ 处理完成")
        success_label.setStyleSheet("font-size: 24px; color: #27ae60;")
        success_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        result_layout.addWidget(success_label)

# 切换按钮
        switch_layout = QHBoxLayout()
self.table_btn = QPushButton("📊 表格视图")
self.table_btn.setCheckable(True)
self.table_btn.setChecked(True)
self.table_btn.clicked.connect(lambdaself.switch_view("table"))

self.html_btn = QPushButton("🌐 HTML视图")
self.html_btn.setCheckable(True)
self.html_btn.clicked.connect(lambdaself.switch_view("html"))

        switch_layout.addWidget(self.table_btn)
        switch_layout.addWidget(self.html_btn)
        result_layout.addLayout(switch_layout)

# 预览区域
self.result_stack = QStackedWidget()

self.table_widget = QTableWidget()
self.table_widget.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)

self.html_text = QTextEdit()
self.html_text.setReadOnly(True)

self.result_stack.addWidget(self.table_widget)
self.result_stack.addWidget(self.html_text)
        result_layout.addWidget(self.result_stack)

# 下载按钮
        download_layout = QHBoxLayout()
        word_btn = QPushButton("📥 下载 Word")
        word_btn.clicked.connect(self.download_word)
        json_btn = QPushButton("📄 下载 JSON")
        json_btn.clicked.connect(self.download_json)
        download_layout.addWidget(word_btn)
        download_layout.addWidget(json_btn)
        result_layout.addLayout(download_layout)

        reset_btn = QPushButton("🔄 处理新图片")
        reset_btn.clicked.connect(self.reset_all)
        result_layout.addWidget(reset_btn, alignment=Qt.AlignmentFlag.AlignCenter)

# 添加所有页面
self.preview_stack.addWidget(self.upload_page)
self.preview_stack.addWidget(self.preview_page)
self.preview_stack.addWidget(self.progress_page)
self.preview_stack.addWidget(self.result_page)

        content_layout.addWidget(self.preview_stack)
        main_layout.addWidget(content)

defapply_styles(self):
self.setStyleSheet("""
            QPushButton {
                padding: 10px 20px;
                border-radius: 20px;
                font-weight: bold;
            }
            QPushButton:checked {
                background-color: #667eea;
                color: white;
            }
            QTableWidget {
                border: 1px solid #ddd;
                gridline-color: #ddd;
            }
            QTableWidget::item {
                padding: 8px;
                color: #333;
            }
            QProgressBar {
                border-radius: 5px;
                height: 20px;
            }
        """
)

defhandle_file(self, file_path):
self.current_image_path = file_path
        pixmap = QPixmap(file_path)
        scaled = pixmap.scaled(400300, Qt.AspectRatioMode.KeepAspectRatio)
self.preview_label.setPixmap(scaled)
self.preview_stack.setCurrentIndex(1)

defstart_processing(self):
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        output_filename = f"table_{timestamp}.docx"

self.preview_stack.setCurrentIndex(2)

self.processing_thread = ProcessingThread(
self.current_image_path, 
            output_filename
        )
self.processing_thread.progress_signal.connect(self.update_progress)
self.processing_thread.complete_signal.connect(self.processing_complete)
self.processing_thread.start()

defupdate_progress(self, progress, message):
self.progress_bar.setValue(progress)
self.progress_text.setText(message)

defprocessing_complete(self, success, html, word_path, json_path, error):
if success:
self.current_word_path = word_path
self.current_json_path = json_path
self.parse_html(html)
self.html_text.setPlainText(html)
self.preview_stack.setCurrentIndex(3)
else:
            QMessageBox.critical(self"错误", error)
self.preview_stack.setCurrentIndex(0)

defparse_html(self, html):
        soup = BeautifulSoup(html, "html.parser")
        table = soup.find("table")
ifnot table:
return

        rows = table.find_all("tr")
self.table_widget.setRowCount(len(rows))
        max_cols = max(len(row.find_all(["td""th"])) for row in rows)
self.table_widget.setColumnCount(max_cols)

for r_idx, row inenumerate(rows):
            cells = row.find_all(["td""th"])
for c_idx, cell inenumerate(cells):
                item = QTableWidgetItem(cell.get_text(strip=True))
                item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.table_widget.setItem(r_idx, c_idx, item)

defswitch_view(self, mode):
if mode == "table":
self.result_stack.setCurrentIndex(0)
self.table_btn.setChecked(True)
self.html_btn.setChecked(False)
else:
self.result_stack.setCurrentIndex(1)
self.table_btn.setChecked(False)
self.html_btn.setChecked(True)

defdownload_word(self):
        save_path, _ = QFileDialog.getSaveFileName(
self"保存 Word""table_result.docx""Word 文件 (*.docx)"
        )
if save_path:
import shutil
            shutil.copy(self.current_word_path, save_path)

defdownload_json(self):
        save_path, _ = QFileDialog.getSaveFileName(
self"保存 JSON""table_result.json""JSON 文件 (*.json)"
        )
if save_path:
import shutil
            shutil.copy(self.current_json_path, save_path)

defreset_upload(self):
self.current_image_path = None
self.preview_label.clear()
self.preview_stack.setCurrentIndex(0)

defreset_all(self):
self.current_image_path = None
self.current_word_path = None
self.current_json_path = None
self.preview_label.clear()
self.table_widget.clear()
self.html_text.clear()
self.progress_bar.setValue(0)
self.preview_stack.setCurrentIndex(0)



defmain():
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())



if __name__ == '__main__':
    main()

使用说明

启动应用

# 激活环境
source venv/bin/activate


# 运行应用
python app2_pyqt6_native.py

操作流程

1.上传图片

    • 拖拽图片到虚线框区域
    • 或点击区域选择文件
2.预览确认
    • 查看图片预览
    • 点击"开始识别"
3.等待处理
    • 观察进度条
    • 模型首次加载约需 10-30 秒
4.查看结果
    • 切换"表格视图"查看结构化数据
    • 切换"HTML 视图"查看原始代码
5.导出文档
    • 下载 Word 文档
    • 或下载 JSON 数据

常见问题

Q1: 启动时提示缺少模型?

首次使用会自动下载模型到 ~/.paddlex/official_models/,确保网络畅通。或者手动复制模型到项目目录。

Q2: 识别速度慢?

  • 首次加载模型较慢,后续使用会快很多
  • CPU 推理速度取决于硬件性能
  • 大图片会先缩放再处理

Q3: 表格识别不准确?

  • 确保图片清晰度足够
  • 表格边框应尽量完整
  • 复杂表格可能需要手动调整

Q4: 如何打包为可执行文件?

使用 PyInstaller:

pip install pyinstaller
...
方法省略了

请参考我的另一篇文章

https://mp.weixin.qq.com/s/QgrilA66q5VCOqzL0hBfUQ

注意:打包时需要包含模型文件和依赖库。


总结

本文介绍了如何使用 PyQt6 原生组件开发一个图片表格识别桌面应用。关键技术点包括:

  1. PaddleOCR 集成 - 处理 onednn 兼容性,延迟加载模型

  2. QThread 多线程 - 避免 UI 卡顿,实时进度反馈

  3. 自定义组件 - DropArea 实现拖拽上传

  4. 多页面切换 - QStackedWidget 管理不同状态页面

  5. 文档生成 - python-docx 生成标准 Word 文档

完整代码已提供,可以直接运行使用。

创作不易,如果对你有帮助,欢迎点赞、收藏、关注支持一下,也欢迎分享给有需要的朋友。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-09 15:33:36 HTTP/2.0 GET : https://f.mffb.com.cn/a/474516.html
  2. 运行时间 : 0.210672s [ 吞吐率:4.75req/s ] 内存消耗:4,686.85kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=3264b5943fc3e40bd0af77e056a49a39
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000523s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000665s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.003146s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.009958s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000559s ]
  6. SELECT * FROM `set` [ RunTime:0.000202s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000554s ]
  8. SELECT * FROM `article` WHERE `id` = 474516 LIMIT 1 [ RunTime:0.004082s ]
  9. UPDATE `article` SET `lasttime` = 1770622416 WHERE `id` = 474516 [ RunTime:0.006820s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.002183s ]
  11. SELECT * FROM `article` WHERE `id` < 474516 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.004863s ]
  12. SELECT * FROM `article` WHERE `id` > 474516 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.009163s ]
  13. SELECT * FROM `article` WHERE `id` < 474516 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.005766s ]
  14. SELECT * FROM `article` WHERE `id` < 474516 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.047744s ]
  15. SELECT * FROM `article` WHERE `id` < 474516 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.044746s ]
0.212300s