使用icrawler爬取谷歌图片填充Tkinter按钮仅显示最后一张问题求助
问题原因
你猜测的Python垃圾回收相关问题是正确的。Tkinter的PhotoImage对象不会被绑定的按钮组件自动持有引用,当create_grid函数执行结束后,局部作用域内的img_1对象会被GC清理,仅最后一次赋值的图片对象可能因残留引用保留,因此仅显示最后一张图。
具体修复方案
只需在代码中手动保留所有图片对象的引用即可,同时修复你现有代码中「新爬取的图片不会被加载」的逻辑问题,修改点如下:
- 新增列表存储图片引用,避免被GC回收
- 每次爬取完成后重新读取本地图片文件夹,重置计数与布局参数
- 移除阻塞主循环的
time.sleep,icrawler的crawl方法本身是同步的,执行完成后自动进入下一步,不需要额外等待
修复后的完整代码
from tkinter import * from PIL import ImageTk,Image from icrawler.builtin import GoogleImageCrawler import os fileLocation = "C:\\Python projects\\tkinter\\images\\" root = Tk() root.title("Product image search") # 若favicon.ico不存在可注释下一行避免启动报错 root.iconbitmap("favicon.ico") e = Entry(root, borderwidth=5) e.grid(row=0, column=0, columnspan=5) button_list = [] # 新增列表专门存储图片引用,避免被垃圾回收 image_refs = [] def create_grid(): global button_list, image_refs # 先清空之前生成的按钮和图片引用,避免多次搜索叠加布局 for btn in button_list: btn.destroy() button_list.clear() image_refs.clear() # 重新读取当前图片文件夹的最新文件 fileList = os.listdir(fileLocation) length = len(fileList) i = 0 rows = 0 cols = 1 while i < length: img_path = f"{fileLocation}{fileList[i]}" # 跳过非图片文件避免启动报错 try: img_raw= Image.open(img_path) except: i += 1 continue img_resize = img_raw.resize((200, 200), Image.ANTIALIAS) img_1 = ImageTk.PhotoImage(img_resize) img_btn = Button(image=img_1) img_btn.grid(row= rows, column= cols) button_list.append(img_btn) # 手动保存图片引用到全局列表 image_refs.append(img_1) rows += 1 if rows == 5: rows = 0 cols += 1 i += 1 def crawlerAction(): google_crawler = GoogleImageCrawler( parser_threads=2, downloader_threads=4, storage={'root_dir': 'images'}) google_crawler.crawl(keyword=e.get(), max_num=20) create_grid() search_btn = Button(text="検査", command=crawlerAction) search_btn.grid(row=0, column=3) root.mainloop()
额外说明
如果你坚持要把create_grid的逻辑放到函数外部,只要把图片对象存到全局的列表里,同样可以解决显示问题,核心逻辑就是不要让PhotoImage对象的引用计数降到0被GC回收即可。
内容的提问来源于stack exchange,提问作者pepelord
相关产品推荐
相关产品推荐

