Python健身应用:点击单选按钮后图片爬取延迟优化求助
Python健身程序性能优化建议
针对你点击单选按钮后图片爬取及显示延迟的问题,以下是具体的优化方案:
1. 异步处理网络与IO操作,避免UI阻塞
当前所有网络请求、图片下载处理都在UI主线程执行,直接导致界面卡顿。需将耗时操作放到后台线程,仅在主线程更新UI:
import threading def display(insert, tab): def fetch_and_show(): url = f'https://uk.images.search.yahoo.com/search/images;_ylt=AwrIfln4XytkPt4DqAAM34lQ;_ylu=Y29sbwNpcjIEcG9zAzEEdnRpZAMEc2VjA3BpdnM-?p={insert}+gym+diagram+instructions&fr2=piv-web&type=E210GB91082G0&fr=mcafee' try: page = requests.get(url) soup = BeautifulSoup(page.content, 'html.parser') holder = soup.find('img') if not holder or 'data-src' not in holder.attrs: root.after(0, lambda: tk.Label(tab, text="未找到图片").grid(row=1, column=0)) return img_url = holder['data-src'] # 直接从内存加载图片,跳过本地文件IO img_response = requests.get(img_url, stream=True) img_response.raw.decode_content = True img = Image.open(img_response.raw) img = img.resize((250, 250)) tk_img = ImageTk.PhotoImage(img) # 回到主线程更新UI root.after(0, lambda: update_image(tab, tk_img, holder.get('alt', 'Something'))) except Exception as e: root.after(0, lambda: tk.Label(tab, text=f"加载失败: {str(e)}").grid(row=1, column=0)) def update_image(tab, tk_img, alt_text): lbl = tk.Label(tab, image=tk_img) lbl.image = tk_img # 保留引用防止被GC回收 lbl.grid(row=1, column=0) tk.Label(tab, text=f'图片: {alt_text}').grid(row=0, column=0) # 启动后台线程执行爬取与处理 threading.Thread(target=fetch_and_show, daemon=True).start()
2. 实现图片缓存,避免重复爬取
对已获取过的锻炼图片进行缓存,下次直接复用,减少重复网络请求:
# 全局缓存字典,键为锻炼名称,值为ImageTk.PhotoImage对象 image_cache = {} def display(insert, tab): if insert in image_cache: # 直接使用缓存的图片 tk_img = image_cache[insert] root.after(0, lambda: update_image(tab, tk_img, insert)) return # 后续爬取逻辑同上面的异步代码,爬取成功后存入缓存 def fetch_and_show(): # ... 爬取逻辑 ... image_cache[insert] = tk_img # 存入缓存
3. 优化API请求方式,复用连接
初始化阶段多次调用API时,使用requests.Session()复用TCP连接,减少握手开销:
# 初始化会话对象 session = requests.Session() session.headers.update({'X-Api-Key': 'EYubhelGF0jRmCC4ZtZKZg==pWcZsqUXcpnwlFW7'}) def m(option, muscle): url = f"https://api.api-ninjas.com/v1/exercises?{option}={muscle}" response = session.get(url) return response.json()
4. 避免不必要的文件IO操作
原代码中用urllib.request.urlretrieve保存图片到本地再打开,改为直接从网络流加载图片,跳过磁盘读写:
# 替换原有的urllib下载逻辑 img_response = requests.get(img_url, stream=True) img_response.raw.decode_content = True # 处理gzip压缩 img = Image.open(img_response.raw)
5. 修复单选按钮的延迟绑定问题
当前单选按钮的command绑定存在延迟绑定,可能导致点击时获取错误的值,改为显式传递值:
# 修改前 Radio = tk.Radiobutton(inside_frame, text="", variable=gym, value=program.workouts[j].exercises[i].name, command=lambda: clicked(gym.get())) # 修改后 Radio = tk.Radiobutton(inside_frame, text=program.workouts[j].exercises[i].name, variable=gym, value=program.workouts[j].exercises[i].name, command=lambda val=program.workouts[j].exercises[i].name: clicked(val))
6. 减少全局变量依赖
代码中大量使用global关键字,导致状态管理混乱且容易引发问题,改为用类封装数据:
# 示例:用类管理锻炼数据 class WorkoutManager: def __init__(self): self.session = requests.Session() self.session.headers.update({'X-Api-Key': 'EYubhelGF0jRmCC4ZtZKZg==pWcZsqUXcpnwlFW7'}) self.exercises = {} self.image_cache = {} self.load_exercises() def load_exercises(self): # 原有的API请求、数据初始化逻辑移到这里 pass # 初始化管理器 workout_manager = WorkoutManager()
7. 预加载常用资源
在程序启动时,预加载高频使用的锻炼图片或缓存API数据到本地文件,启动时直接读取:
# 示例:缓存API数据到本地 import json def save_exercises_to_file(data, filename="exercises_cache.json"): with open(filename, 'w') as f: json.dump(data, f) def load_exercises_from_file(filename="exercises_cache.json"): if os.path.exists(filename): with open(filename, 'r') as f: return json.load(f) return None # 初始化时先尝试加载缓存 cached_data = load_exercises_from_file() if cached_data: # 使用缓存数据初始化 pass else: # 请求API并保存缓存 data = ... # API请求逻辑 save_exercises_to_file(data)
内容的提问来源于stack exchange,提问作者Armaan Khaitan
相关产品推荐
相关产品推荐

