You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本如何实现启动时自动安装tesseract-OCR exe程序

Tesseract-OCR自动检测安装实现方案

核心逻辑

  • 程序启动时优先执行环境检测,判断Tesseract-OCR是否已安装
  • 适配Windows/macOS/Linux三大系统,未检测到安装时自动调用对应系统的官方安装通道执行安装
  • 移除原代码中硬编码的Tesseract执行路径,改为动态获取,适配不同用户的安装目录
  • 安装过程弹出提示告知用户,避免误关程序

实现说明

无需额外安装第三方Python包,仅通过Python内置的subprocess、sys、platform模块即可实现检测和自动安装逻辑,修改后的完整代码如下:

import os
import sys
import platform
import subprocess
import tkinter
from tkinter import *
from tkinter import filedialog as fd
import PyPDF2
from pyttsx3 import *
from PyPDF2 import *
from docx import Document
import pytesseract
import cv2
import pyttsx3
from pygame import mixer
from tkinter import messagebox as md

# -------------------------- 新增Tesseract检测安装逻辑 开始 --------------------------
def check_and_install_tesseract():
    # 先检测是否已安装
    try:
        subprocess.run(["tesseract", "--version"], check=True, capture_output=True, text=True)
        # 能正常执行则直接配置路径
        pytesseract.pytesseract.tesseract_cmd = "tesseract"
        return True
    except (subprocess.CalledProcessError, FileNotFoundError):
        # 未检测到安装则走安装流程
        pass

    md.showinfo("环境检测", "未检测到Tesseract-OCR组件,即将自动安装,请稍候不要关闭程序...")
    system = platform.system()
    try:
        if system == "Windows":
            # Windows调用系统自带winget安装,适配Win10 1709及以上版本
            subprocess.run(["winget", "install", "--id", "UB-Mannheim.TesseractOCR", "--silent", "--accept-package-agreements", "--accept-source-agreements"], check=True)
            # 遍历常规安装路径匹配执行文件
            possible_paths = [
                r"C:\Program Files\Tesseract-OCR\tesseract.exe",
                r"C:\Program Files (x86)\Tesseract-OCR\tesseract.exe"
            ]
            for path in possible_paths:
                if os.path.exists(path):
                    pytesseract.pytesseract.tesseract_cmd = path
                    return True
        elif system == "Darwin":
            # macOS通过Homebrew安装
            subprocess.run(["brew", "install", "tesseract"], check=True)
            pytesseract.pytesseract.tesseract_cmd = "tesseract"
            return True
        elif system == "Linux":
            # 适配Debian/Ubuntu发行版,其他发行版可自行修改安装命令
            subprocess.run(["sudo", "apt", "update"], check=True)
            subprocess.run(["sudo", "apt", "install", "-y", "tesseract-ocr"], check=True)
            pytesseract.pytesseract.tesseract_cmd = "tesseract"
            return True
    except Exception as e:
        md.showerror("安装失败", f"Tesseract-OCR自动安装失败,请手动安装后重试。错误信息:{str(e)}")
        sys.exit(1)

    md.showerror("安装失败", "未匹配到当前系统的自动安装方案,请手动安装Tesseract-OCR后重试")
    sys.exit(1)

# 程序启动优先执行检测安装
check_and_install_tesseract()
# -------------------------- 新增Tesseract检测安装逻辑 结束 --------------------------

# Setting Up the tkinter window
win = Tk()
win.geometry('550x750')
win.config(background='#d4fffe')
win.title('AudioBook')
icon=PhotoImage(file='audiobook.png')
win.iconphoto(False,icon)
# Set Up Complete

vari=StringVar()

# Creating functionality
def select_file():
    global file
    if vari.get() == 'Word Document':
        file=fd.askopenfilename(initialdir='/',filetypes=[('Word FILE','*.docx')])
    elif vari.get()== 'Pdf Document':
        file=fd.askopenfilename(initialdir='/',filetypes=[('PDF FILE','*.pdf')])
    elif vari.get() == 'Image(Indiviual)' :
        file=fd.askopenfilename(initialdir='/',filetypes=[('JPG','*jpg'),('PNG','*png')])
    elif vari.get()=='Text Document':
        file=fd.askopenfilename(initialdir='/',filetypes=[('Text File','*.txt')])
    
    button2.config(state=NORMAL,fg='MidnightBlue')

def check(*args):
    if vari.get():
        button.config(state=NORMAL,fg='MidnightBlue')
    else:
        button.config(state=DISABLED)


def ocr():
    global word,pdfs,image1,txt,text_word,text_img,text_txt,pdf_txt
    word=FALSE
    pdfs=FALSE
    image1=FALSE
    txt=FALSE
    if file:
        if file.endswith('.docx'):
            word=TRUE
        elif file.endswith('.pdf'):
            pdfs=TRUE
        elif file.endswith('.PNG') or file.endswith('.jpg') or file.endswith('.png'):
            image1=TRUE
        elif file.endswith('.txt'):
            txt=TRUE

    if word:
        text_word1=[]
        doc=Document(file)
        for par in doc.paragraphs:
            text_word1.append(par.text)

        text_word=''.join(text_word1)
        box.delete('1.0',END)
        box.insert(tkinter.END,text_word)

    elif pdfs:
        try:
            pdf_reader=PyPDF2.PdfFileReader(file)
            for pages in range(pdf_reader.numPages):
                page=pdf_reader.getPage(pages)
                pdf_txt=page.extractText()
                box.delete('1.0',END)
                box.insert(tkinter.END,pdf_txt)
        except:
            box.delete('1.0',END)
            box.insert(tkinter.END,"Text Can't Be Recognised In PDF File Try Image Option")

    elif image1:
        try:
            # 移除原硬编码路径,已在启动时全局配置
            img=cv2.imread(file)
            imgf=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
            text_img=pytesseract.image_to_string(imgf)
            box.delete('1.0',END)
            box.insert(tkinter.END,text_img)
        except:
            box.delete('1.0',END)
            box.insert(tkinter.END,"Text Can't be Reconginsed in Image")
    elif txt:
        txt1=open(file,'r',encoding='utf-8', errors='ignore')
        text_txt=txt1.read()
        box.delete('1.0',END)
        box.insert(tkinter.END,text_txt)

    button3.config(state=NORMAL,fg='MidnightBlue')

def play():
    direc=os.getcwd()
    new_dir=direc.replace('\\','/')
    mixer.init()
    engine=pyttsx3.init()
    engine.setProperty('rate',165)
    if word:
        if os.path.isfile(new_dir+'/'+'my.wav'):
            engine.save_to_file(text_word,new_dir+'/'+'my2.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my.wav')
        elif os.path.isfile(new_dir+'/'+'my2.wav') :
            engine.save_to_file(text_word,new_dir+'/'+'my.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my2.wav')
        else:
            engine.save_to_file(text_word,new_dir+'/'+'my.wav')
            engine.runAndWait()
    elif pdfs:
        if os.path.isfile(new_dir+'/'+'my.wav'):
            engine.save_to_file(pdf_txt,new_dir+'/'+'my2.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my.wav')
        elif os.path.isfile(new_dir+'/'+'my2.wav'):
            engine.save_to_file(pdf_txt,new_dir+'/'+'my.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my2.wav')
        else:
            engine.save_to_file(pdf_txt,new_dir+'/'+'my.wav')
            engine.runAndWait()
    elif image1:
        if os.path.isfile(new_dir+'/'+'my.wav'):

            engine.save_to_file(text_img,new_dir+'/'+'my2.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my.wav')
        elif os.path.isfile(new_dir+'/'+'my2.wav'):
            engine.save_to_file(text_img,new_dir+'/'+'my.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my2.wav')
        else:
            engine.save_to_file(text_img,new_dir+'/'+'my.wav')
            engine.runAndWait()

    elif txt:
        if os.path.isfile(new_dir+'/'+'my.wav'):

            engine.save_to_file(text_txt,new_dir+'/'+'my2.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my.wav')
        elif os.path.isfile(new_dir+'/'+'my2.wav'):
            engine.save_to_file(text_txt,new_dir+'/'+'my.wav')
            engine.runAndWait()
            mixer.music.unload()
            os.remove(new_dir+'/'+'my2.wav')
        else:
            engine.save_to_file(text_txt,new_dir+'/'+'my.wav')
            engine.runAndWait()

    if os.path.isfile(new_dir+'/'+'my.wav'):
        mixer.music.load(new_dir+'/'+'my.wav')
        mixer.music.play()
    else:
        mixer.music.load(new_dir+'/'+'my2.wav')
        mixer.music.play()

    button4.config(state=NORMAL,fg='MidnightBlue')
    button5.config(state=NORMAL,fg='MidnightBlue')
    button6.config(state=NORMAL,fg='MidnightBlue')
    
def pause():
    mixer.music.pause()

def unpause():
    mixer.music.unpause()

def stop():
    mixer.music.stop()
    

# Creating widgets
labl1=Label(win,text='Welcome To AudioBook',bg='#d4fffe',font=('Consolas',13,'bold')).place(x=190,y=20)
labl=Label(win,text='Select File Type To Listen Text',bg='#d4fffe',font=('Consolas',13,'bold')).place(x=140,y=60)

drop=OptionMenu(win,vari,'Select File Type ','Word Document','Pdf Document','Image(Indiviual)','Text Document',command=check)

button=Button(win,text='Select File',command=select_file,state=DISABLED,width=15,height=2,bg='LightSkyBlue')

button2=Button(win,text='Extract Text',command=ocr,state=DISABLED,width=15,height=2,bg='LightSkyBlue')

button3=Button(win,text='Listen Text',command=play,state=DISABLED,width=15,height=2,bg='LightSkyBlue')

button4=Button(win,text='Pause',command=pause,state=DISABLED,width=15,height=2,bg='LightSkyBlue')

button5=Button(win,text='Resume',command=unpause,state=DISABLED,width=15,height=2,bg='LightSkyBlue')

button6=Button(win,text='Stop Listening',command=stop,state=DISABLED,width=15,height=2,bg='LightSkyBlue')


box=Text(win,width=60,height=15,font=('consolas',11,'italic'))
#placement

drop.place(x=205,y=120)
button.place(x=208,y=170)
box.place(x=35,y=240)
button2.place(x=110,y=530)
button3.place(x=310,y=530)
button4.place(x=110,y=600)
button5.place(x=310,y=600)
button6.place(x=208,y=670)
#designing

drop.config(width=15,bg='LightSkyBlue',highlightbackground='LightSkyBlue')
button2.config(font=('Consolas',11,'italic'),activebackground='cornsilk')
button.config(font=('Consolas',11,'italic'),activebackground='cornsilk')
button3.config(font=('Consolas',11,'italic'),activebackground='cornsilk')
button4.config(font=('Consolas',11,'italic'),activebackground='cornsilk')
button5.config(font=('Consolas',11,'italic'),activebackground='cornsilk')
button6.config(font=('Consolas',11,'italic'),activebackground='cornsilk')
drop["menu"]["background"] = 'lightskyblue'
drop["menu"]["foreground"] = 'navy'
drop["menu"]["font"] = ('Consolas',11,'italic')
drop['height']= 1

win.mainloop()

额外优化内容

  • 修复原代码仅支持大写.PNG后缀图片的问题,新增兼容小写.png格式
  • 优化txt文件读取逻辑,添加编码兼容配置,避免中文内容乱码
  • 自动安装失败会弹出明确错误提示,引导用户手动安装

内容的提问来源于stack exchange,提问作者Kushagra Pandey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:45:03