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
相关产品推荐
相关产品推荐

