Python Tkinter截图报错OSError: [Errno 22] Invalid argument求助
Python Tkinter截图应用OSError错误排查
问题描述
开发Python Tkinter应用时,需求为每秒捕获当前屏幕截图,同时从localhost API获取截图保存到本地指定文件夹。运行代码时触发以下错误:
OSError: [Errno 22] Invalid argument: 'http://localhost/test/1659071138.jpg'
原代码
from tkinter import * from tkinter import ttk import time import urllib.request #import requests import os #import mysql.connector import schedule import pyscreenshot as ImageGrab from functools import partial from PIL import ImageTk, Image import pyautogui as pg from datetime import datetime ws = Tk() ws.title('PythonGuides') ws.geometry('400x300') f = ('Times', 14) def validateLogin(): user = register_name.get() passw = register_pwd.get() return def screenshot(): random = int(time.time()) print("Taking screenshot...") #ss = pg.screenshot(filename,"w") #imgURL = "http://localhost/test/" + str(random) + ".jpg" #urllib.request.urlretrieve("GET",imgURL) #url = "http://localhost/test/" + str(random) + ".jpg" #req = requests.request("GET",url) filename = r"http://localhost/test/" + str(random) + ".jpg" imgURL = "http://localhost/test/image/mobile6.jpg" urllib.request.urlretrieve(imgURL, "D:/test/image/"+ str(random) + ".jpg") ss = pg.screenshot(filename) def main(): schedule.every().second.do(screenshot) while True: schedule.run_pending() time.sleep(5) # time.stop(5) if __name__ == '__main__': main() def hide_window( ): # hiding the tkinter window while taking the screenshot ws.withdraw() ws.after(1, screenshot) # Add a Label widget #Label(ws, text="Click the Button to Take the Screenshot", font=('Times New Roman', 18, 'bold')).pack(pady=10) # Create a Button to take the screenshots #button = Button(ws, text="Take Screenshot", font=('Aerial 11 bold'), background="#aa7bb1", foreground="white", command=hide_wsdow) #button.pack(pady=20) #second wsdow def open_win(): new= Toplevel(ws) new.title("Newsdow") #Create a Label in New window Label(new, font=('Helvetica 17 bold')).grid(row=0, column=1) button = Button(new, text="Take Screenshot", command=hide_window) button.grid(row=4, column=1) new.destroy print("username entered :", register_name.get()) print("password entered :", register_pwd.get()) #return right_frame = Frame( ws, bd=2, bg='#CCCCCC', relief=SOLID, padx=10, pady=10, ) #main window #Create a label #Label(win, text= "Click the below button to Open a New Window", font= ('Helvetica 17 bold')).pack(pady=30) #Create a button to open a New Window #username label and text entry box Label( right_frame, text="Enter Name", bg='#CCCCCC', font=f ).grid(row=0, column=0, sticky=W, pady=10) Label( right_frame, text="Enter Password", bg='#CCCCCC', font=f ).grid(row=5, column=0, sticky=W, pady=10) register_name = Entry( right_frame, font=f ) register_pwd = Entry( right_frame, font=f, show='*' ) validateLogin = partial(validateLogin, register_name, register_pwd) register_btn = Button( right_frame, width=15, text='Login', font=f, relief=SOLID, cursor='hand2', command=hide_window ) register_name.grid(row=0, column=1, pady=10, padx=20) register_pwd.grid(row=5, column=1, pady=10, padx=20) register_btn.grid(row=7, column=1, pady=10, padx=20) right_frame.pack( expand=YES) ws.mainloop()
错误原因分析
- 核心错误:
pg.screenshot(filename)中的filename被设置为URL(http://localhost/test/1659071138.jpg),但pyautogui.screenshot()的filename参数要求传入本地文件系统路径,不能是网络URL,这直接触发了OSError。 - 逻辑结构问题:
screenshot()函数内部嵌套了main()函数,并且if __name__ == '__main__'判断放在函数内部,导致代码执行逻辑混乱,无法正确启动定时任务。- 使用
schedule库的while True循环会阻塞Tkinter的主线程,导致GUI无响应。
- 其他小问题:
open_win()函数中new.destroy没有加括号,无法正确销毁窗口;定时任务设置为每秒执行但time.sleep(5),实际执行间隔会变成5秒,不符合需求。
修复方案
1. 修正截图保存路径
将pg.screenshot()的filename改为本地路径,比如D:/test/local_screenshot_ + str(random) + ".jpg"。
2. 重构定时任务逻辑
使用Tkinter的after()方法替代schedule库,避免阻塞主线程;移除嵌套的main()函数和错误的__name__判断。
3. 修复其他小问题
给new.destroy加上括号,确保窗口能正确销毁;调整定时执行间隔符合需求。
修复后的代码示例
from tkinter import * from tkinter import ttk import time import urllib.request import os import pyautogui as pg ws = Tk() ws.title('PythonGuides') ws.geometry('400x300') f = ('Times', 14) # 确保本地保存目录存在 LOCAL_SAVE_DIR = "D:/test/image/" API_SAVE_DIR = "D:/test/api_image/" os.makedirs(LOCAL_SAVE_DIR, exist_ok=True) os.makedirs(API_SAVE_DIR, exist_ok=True) def validateLogin(): user = register_name.get() passw = register_pwd.get() print(f"用户名: {user}, 密码: {passw}") def screenshot(): random = int(time.time()) print("正在执行截图操作...") # 1. 从API获取图片保存到本地 imgURL = "http://localhost/test/image/mobile6.jpg" api_save_path = os.path.join(API_SAVE_DIR, f"{random}.jpg") try: urllib.request.urlretrieve(imgURL, api_save_path) print(f"API图片已保存到: {api_save_path}") except Exception as e: print(f"获取API图片失败: {str(e)}") # 2. 捕获本地屏幕截图保存到本地 local_save_path = os.path.join(LOCAL_SAVE_DIR, f"local_{random}.jpg") try: pg.screenshot(local_save_path) print(f"本地截图已保存到: {local_save_path}") except Exception as e: print(f"本地截图失败: {str(e)}") # 3. 每秒重复执行(使用Tkinter after方法,不阻塞主线程) ws.after(1000, screenshot) def hide_window(): # 隐藏窗口后执行截图,然后恢复窗口 ws.withdraw() screenshot() # 如果需要截图后恢复窗口,取消下面注释 # ws.after(100, ws.deiconify) def open_win(): new = Toplevel(ws) new.title("新窗口") Label(new, font=('Helvetica 17 bold')).grid(row=0, column=1) Button(new, text="开始截图", command=hide_window).grid(row=4, column=1) # 点击按钮后不立即销毁窗口,让用户操作 # new.destroy() # 如需自动销毁,移到合适位置 # 登录界面布局 right_frame = Frame( ws, bd=2, bg='#CCCCCC', relief=SOLID, padx=10, pady=10 ) Label( right_frame, text="Enter Name", bg='#CCCCCC', font=f ).grid(row=0, column=0, sticky=W, pady=10) Label( right_frame, text="Enter Password", bg='#CCCCCC', font=f ).grid(row=5, column=0, sticky=W, pady=10) register_name = Entry(right_frame, font=f) register_pwd = Entry(right_frame, font=f, show='*') register_btn = Button( right_frame, width=15, text='Login', font=f, relief=SOLID, cursor='hand2', command=validateLogin ) register_name.grid(row=0, column=1, pady=10, padx=20) register_pwd.grid(row=5, column=1, pady=10, padx=20) register_btn.grid(row=7, column=1, pady=10, padx=20) right_frame.pack(expand=YES) ws.mainloop()
内容的提问来源于stack exchange,提问作者Nupur Koshti
相关产品推荐
相关产品推荐

