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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 09:07:36