当前位置:首页>python>《效率干货:python调用PaddleOCR-VL-1.5大模型api批量精准识别采购装箱单,彻底告别人工录入,实现摸鱼自由get√》

《效率干货:python调用PaddleOCR-VL-1.5大模型api批量精准识别采购装箱单,彻底告别人工录入,实现摸鱼自由get√》

  • 2026-08-26 05:48:55
《效率干货:python调用PaddleOCR-VL-1.5大模型api批量精准识别采购装箱单,彻底告别人工录入,实现摸鱼自由get√》

“带你横跨办公自动化的数据江海”

@摸鱼

闻道有先后,术业有专攻。各位大佬们大家好!~我是你们的老朋友摸鱼~,本人在十多年的日常工作中摸爬滚打攒了不少Python办公自动化的实用项目技巧,自创立"码海听潮"公众号以来,已经陆续分享近80篇原创干货文章啦!里面满满的办公实操干货,希望能与各位大佬共同探讨办公效率提升之道,实现不加班自由。

好叻,多了不说,少了不唠,咱直接上干货。

办公需求场景

从崩溃到优雅的进化

有一个神秘的图片文件夹, 里面有某外贸公司一天共计220张的全球采购装箱单图片,现在的需求是把这些图片上的Purchase Order No(采购单号)、Made in(产地) 、Qty Total(采购数量)的信息进行提取并保存为excel表方便汇总、要是这种类似的需求你的Big Boss安排你去完成,请问阁下该如何应对?

需求的图片文件夹和水印图片列表如下图:

  • 采购装箱单图片文件夹

  • 采购装箱单图片

办公痛点分析

01

 痛点1:重复劳动多,效率极低

    • 机械重复: 220张图,每张都要打开、定位、扫视、打字、保存、关闭。这种高密度的机械操作通常在30张之后大脑就开始自动疲劳

    02

     痛点2:极易出错

      • 数着数着容易忘记哪张图录了、哪张图没录,需要停下来做标记

      03

      痛点3:非标格式的解析障碍

      • 字段位置不固定: 虽然是“装箱单”,但不同国家供应商的格式天差地别。有的PO号在右上角,有的在标题栏,有的藏在备注里。

      由此可见若操作成百上千张装箱单图片的话整个操作流程繁琐且耗时,高频次的鼠标点击和键盘输入使操作者手指疲劳,堪称"键盘敲冒烟"式的体力劳动,加上人工疲劳操作极易导致遗漏文件夹。于是乎这时候,按以往的 “解题套路”,Python 的专属 BGM 该响起来了 ——go~ go~ go~,救苦救难的大救星这不就来了!!

      @摸鱼

      问题拆解思路

      1.遍历装箱单图片文件夹→

      2.调用Paddleocr-Vl-1.5大模型api精准提取指定字段信息→

      3.保存提取的信息写入excel表格

      下面,我就用python代码让excel见识一下,什么叫"传统文化遇上赛博效率"(仅展示部分代码,非完整代码,需完整代码看文章末尾说明~)

      import sysimport osimport jsonfrom PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,                             QHBoxLayout, QPushButton, QLabel, QLineEdit,                             QTextEdit, QFileDialog, QMessageBox, QGroupBox,                            QGridLayout, QCheckBox)from PyQt6.QtCore import Qtfrom PyQt6.QtGui import QTextCursorclass Config:    """配置管理类"""    CONFIG_FILE = "config.json"    @classmethod    def load(cls):        """加载配置"""        default_config = {            "api_url": "",            "token": "",            "recursive": True,            "output_file": "采购装箱单提取结果.xlsx"        }        try:            if os.path.exists(cls.CONFIG_FILE):                with open(cls.CONFIG_FILE, 'r', encoding='utf-8') as f:                    config = json.load(f)                    for key in default_config:                        if key not in config:                            config[key] = default_config[key]                    return config        except Exception as e:            print(f"加载配置文件失败: {e}")        return default_config    @classmethod    def save(cls, api_url, token, recursive, output_file):        """保存配置"""        try:            config = {                "api_url": api_url,                "token": token,                "recursive": recursive,                "output_file": output_file            }            with open(cls.CONFIG_FILE, 'w', encoding='utf-8') as f:                json.dump(config, f, ensure_ascii=False, indent=2)            return True        except Exception as e:            print(f"保存配置文件失败: {e}")            return Falseclass MainWindow(QMainWindow):    """主窗口"""    def __init__(self):        super().__init__()        self.config = Config.load()        self.init_ui()    def init_ui(self):        """初始化UI"""        self.setWindowTitle("采购装箱单信息提取工具(欢迎关注微信公众号:码海听潮)")        self.setMinimumSize(800, 650)        self.setStyleSheet("""            QMainWindow {                background-color: #f5f7fa;            }            QGroupBox {                font-weight: bold;                border: 2px solid #e1e9f0;                border-radius: 8px;                margin-top: 10px;                padding-top: 10px;                background-color: white;            }            QGroupBox::title {                subcontrol-origin: margin;                left: 10px;                padding: 0 10px 0 10px;                color: #2c3e50;            }            QPushButton {                background-color: #3498db;                color: white;                border: none;                padding: 8px 16px;                border-radius: 5px;                font-weight: bold;                min-width: 100px;            }            QPushButton:hover {                background-color: #2980b9;            }            QPushButton:pressed {                background-color: #1c6ea4;            }            QPushButton:disabled {                background-color: #bdc3c7;            }            QLineEdit {                padding: 8px;                border: 2px solid #e1e9f0;                border-radius: 5px;                background-color: white;                selection-background-color: #3498db;            }            QLineEdit:focus {                border-color: #3498db;            }            QTextEdit {                border: 2px solid #e1e9f0;                border-radius: 5px;                background-color: white;                font-family: Consolas, Monaco, monospace;                font-size: 12px;            }            QCheckBox {                spacing: 8px;            }            QCheckBox::indicator {                width: 18px;                height: 18px;                border: 2px solid #e1e9f0;                border-radius: 3px;                background-color: white;            }            QCheckBox::indicator:checked {                background-color: #3498db;                border-color: #3498db;            }            QLabel {                color: #2c3e50;            }        """)        central_widget = QWidget()        self.setCentralWidget(central_widget)        main_layout = QVBoxLayout(central_widget)        main_layout.setSpacing(15)        main_layout.setContentsMargins(20, 20, 20, 20)        config_group = QGroupBox("配置参数")        config_layout = QGridLayout(config_group)        config_layout.setVerticalSpacing(12)        config_layout.setHorizontalSpacing(10)        config_layout.addWidget(QLabel("输入目录:"), 0, 0)        self.input_dir_edit = QLineEdit()        self.input_dir_edit.setPlaceholderText("请选择包含图片/PDF文件的目录")        config_layout.addWidget(self.input_dir_edit, 0, 1)        self.browse_input_btn = QPushButton("浏览...")        self.browse_input_btn.clicked.connect(self.browse_input_dir)        self.browse_input_btn.setFixedWidth(80)        config_layout.addWidget(self.browse_input_btn, 0, 2)        config_layout.addWidget(QLabel("输出Excel:"), 1, 0)        self.output_file_edit = QLineEdit()        self.output_file_edit.setText(self.config.get("output_file", "采购单提取结果.xlsx"))        config_layout.addWidget(self.output_file_edit, 1, 1)        self.browse_output_btn = QPushButton("浏览...")        self.browse_output_btn.clicked.connect(self.browse_output_file)        self.browse_output_btn.setFixedWidth(80)        config_layout.addWidget(self.browse_output_btn, 1, 2)        config_layout.addWidget(QLabel("API地址:"), 2, 0)        self.api_url_edit = QLineEdit()        self.api_url_edit.setText(self.config.get("api_url", "https://38.com/layout-parsing"))        config_layout.addWidget(self.api_url_edit, 2, 1, 1, 2)        config_layout.addWidget(QLabel("Token:"), 3, 0)        self.token_edit = QLineEdit()        self.token_edit.setText(self.config.get("token", "db65aec850709aa083c4"))        self.token_edit.setEchoMode(QLineEdit.EchoMode.Password)        config_layout.addWidget(self.token_edit, 3, 1, 1, 2)        self.recursive_checkbox = QCheckBox("递归查找子目录")        self.recursive_checkbox.setChecked(self.config.get("recursive", True))        config_layout.addWidget(self.recursive_checkbox, 4, 1)        main_layout.addWidget(config_group)        button_layout = QHBoxLayout()        button_layout.setSpacing(15)        self.start_btn = QPushButton("开始处理")        self.start_btn.setMinimumHeight(40)        self.start_btn.clicked.connect(self.start_processing)        button_layout.addWidget(self.start_btn)        self.clear_btn = QPushButton("清空日志")        self.clear_btn.setMinimumHeight(40)        self.clear_btn.clicked.connect(self.clear_log)        button_layout.addWidget(self.clear_btn)        self.save_config_btn = QPushButton("保存配置")        self.save_config_btn.setMinimumHeight(40)        self.save_config_btn.clicked.connect(self.save_configuration)        self.save_config_btn.setStyleSheet("background-color: #2ecc71;")        button_layout.addWidget(self.save_config_btn)        main_layout.addLayout(button_layout)        log_group = QGroupBox("处理日志")        log_layout = QVBoxLayout(log_group)        self.log_text = QTextEdit()        self.log_text.setReadOnly(True)        self.log_text.setMinimumHeight(350)        log_layout.addWidget(self.log_text)        main_layout.addWidget(log_group)        self.status_label = QLabel("就绪")        self.status_label.setStyleSheet("color: #27ae60; font-weight: bold; padding: 5px;")        main_layout.addWidget(self.status_label)    def browse_input_dir(self):        """浏览输入目录"""        directory = QFileDialog.getExistingDirectory(            self,             "选择输入目录",            "",            QFileDialog.Option.ShowDirsOnly        )        if directory:            self.input_dir_edit.setText(directory.replace('/', '\\'))    def browse_output_file(self):        """浏览输出文件"""        file_path, _ = QFileDialog.getSaveFileName(            self,            "保存Excel文件",            self.output_file_edit.text() or "采购单提取结果.xlsx",            "Excel文件 (*.xlsx)"        )        if file_path:            self.output_file_edit.setText(file_path)    def save_configuration(self):        """保存配置到文件"""        api_url = self.api_url_edit.text().strip()        token = self.token_edit.text().strip()        recursive = self.recursive_checkbox.isChecked()        output_file = self.output_file_edit.text().strip()        if Config.save(api_url, token, recursive, output_file):            self.append_log("✓ 配置已保存")            QMessageBox.information(self, "保存成功", "配置已成功保存!")        else:            QMessageBox.warning(self, "保存失败", "配置保存失败!")    def start_processing(self):        """开始处理"""        input_dir = self.input_dir_edit.text().strip()        if not input_dir:            QMessageBox.warning(self, "警告", "请选择输入目录!")            return        if not os.path.exists(input_dir):            QMessageBox.warning(self, "警告", "输入目录不存在!")            return        output_file = self.output_file_edit.text().strip()        if not output_file:            output_file = "采购单提取结果.xlsx"            self.output_file_edit.setText(output_file)        api_url = self.api_url_edit.text().strip()        if not api_url:            QMessageBox.warning(self, "警告", "请输入API地址!")            return        token = self.token_edit.text().strip()        if not token:            QMessageBox.warning(self, "警告", "请输入Token!")            return        self.save_configuration()        self.status_label.setText("正在处理中...")        self.status_label.setStyleSheet("color: #e67e22; font-weight: bold; padding: 5px;")        self.append_log("开始批量处理...")        self.append_log("=" * 50)        QMessageBox.information(            self,            "提示",            "处理功能已启动,请查看日志输出。\n\n(注意:实际处理功能需要集成API调用等业务逻辑)"        )    def append_log(self, message):        """追加日志"""        self.log_text.append(message)        cursor = self.log_text.textCursor()        cursor.movePosition(QTextCursor.MoveOperation.End)        self.log_text.setTextCursor(cursor)    def clear_log(self):        """清空日志"""        self.log_text.clear()def main():    """主函数"""    app = QApplication(sys.argv)    window = MainWindow()    window.show()    sys.exit(app.exec())if __name__ == "__main__":    main()

      最终将所有的装箱单图片按照指定字段精准提取了信息,完美实现了之前既定的需求...

      通过上面Python自动化脚本,仅用几分钟的时间就完成原需手动操作数小时甚至数天的工作任务。从最初准备手动人工机械操作的麻木到用python实现高效自动化的畅快,工作效率获得指数级提升,终于实现了不加班熬夜的自由!

      大佬们也可以举一反三,参照上面的代码思路根据自己工作中的实际情况来具体问题具体分析,实现自己定制化的需求。

      结语

      当Python遇见办公,牛马打工人终于笑出了猪叫声

      【职场人必看】每天早上一睁眼,想到又要面对:

      1.📊 堆积如山的Excel表格

      2.📑 机械重复的复制粘贴

      3.✍️ 永远改不完的各类文档

      4.诸如此类的更多........

      是不是连Ctrl+Alt+Delete的心都有了?

      别慌!别急,摸鱼这位“职场外挂”已经带着Python代码来拯救你了!

      友情提示:考虑到没有python环境的朋友需要打包好的成品exe,摸鱼早已贴心打包好,本篇文章代码打包的exe截图如下:

      另外,《码海听潮》公众号所有文章码和exe程序已打包好上传绿联nas私有云,有需要的大佬扫一扫上面博主的个人微信二维码,需要的大佬需支付9.9元永久拥有公众号资源(写原创干货费时费力,属实不易),邀请您进入社区群获取下载链接!!,群内提供python办公自动化交流问题,解决问题,且码海听潮微信公众号文章发布会第一时间会更新到群里,非诚勿扰哈!

      码海听潮官方社区群如下:

      赶紧微信扫一扫下方二维码添加摸鱼君微信

      最新文章

      随机文章