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

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()

错误原因分析

  1. 核心错误:pg.screenshot(filename)中的filename被设置为URL(http://localhost/test/1659071138.jpg),但pyautogui.screenshot()的filename参数要求传入本地文件系统路径,不能是网络URL,这直接触发了OSError。
  2. 逻辑结构问题:
    • screenshot()函数内部嵌套了main()函数,并且if __name__ == '__main__'判断放在函数内部,导致代码执行逻辑混乱,无法正确启动定时任务。
    • 使用schedule库的while True循环会阻塞Tkinter的主线程,导致GUI无响应。
  3. 其他小问题: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 13:24:21