Python截屏实战:PyAutoGUI、Pillow与PyQt三种方案详解

📅 发布时间:2026/8/17 3:50:16
Python截屏实战:PyAutoGUI、Pillow与PyQt三种方案详解 1. 项目概述为什么需要Python截屏在日常开发、自动化测试、远程协助或者构建自己的效率工具时截屏是一个高频且基础的需求。你可能需要定时抓取某个应用的界面状态或者将自动化操作的结果保存为图片证据又或者想做一个自定义的截图工具。虽然系统自带的截图功能很方便但在程序化、批量化、无人值守的场景下它就无能为力了。Python作为一门“胶水语言”其魅力就在于能用简洁的代码调用各种底层库实现强大的功能。实现截屏也不例外。今天我们不谈那些复杂的商业软件就聚焦于用纯Python代码实现三种主流且实用的截屏方式。这三种方式各有侧重覆盖了从简单到复杂从跨平台到高性能的不同需求场景。无论你是想快速写个脚本抓个图还是想深入理解图形界面GUI的底层抓取原理这篇文章都能给你清晰的路径和可直接运行的代码。我们将要探讨的三种方式是基于pyautogui的“傻瓜式”全屏截图、基于PILPillow的灵活区域截图以及基于PyQt的高性能应用窗口截图。我会详细拆解每种方法的原理、适用场景、代码实现并分享我在实际使用中踩过的坑和总结的技巧。读完本文你不仅能获得三份完整的、可运行的代码更能理解在什么情况下该选择哪种工具真正做到知其然更知其所以然。2. 三种截屏方案的核心思路与选型考量在动手写代码之前我们先来理清思路。Python实现截屏本质上都是调用操作系统提供的图形接口来获取屏幕像素数据。不同的库是对不同层级接口的封装这就决定了它们在易用性、灵活性、性能和依赖复杂度上的差异。2.1 方案一PyAutoGUI - 极简全屏抓取核心思路PyAutoGUI是一个跨平台的GUI自动化库它的设计目标是模拟鼠标和键盘操作。截图功能对它而言更像是一个“赠品”。它通过调用操作系统最顶层的、面向用户的截图API在Windows上可能是PrtScn键的模拟在macOS/Linux上调用相应的命令行工具或库来获取整个屏幕的图像。为什么选它极致简单通常只需一行代码pyautogui.screenshot()就能得到全屏截图学习成本几乎为零。跨平台友好其设计初衷就是跨平台Windows, macOS, Linux省去了为不同系统分别适配的麻烦。适合快速原型和简单任务当你需要快速验证想法或者截屏只是自动化流程中一个微不足道的环节时它是首选。需要注意什么功能单一主要提供全屏截图虽然可以指定区域但其区域截图的底层可能还是全屏截图后裁剪效率并非最优。依赖与安装虽然它试图隐藏底层复杂性但在某些Linux发行版上可能需要额外安装scrot、maim等命令行截图工具作为后端安装过程可能遇到包构建错误正如热词中提到的error: failed to build ‘pyautogui‘。无法穿透遮挡它截取的是当前屏幕最顶层的合成画面。如果一个窗口被另一个窗口部分遮挡它无法单独抓取被遮挡窗口的内容。2.2 方案二PIL (Pillow) - 灵活的区域与屏幕操作核心思路PillowPIL Fork是Python事实上的图像处理标准库。它本身不直接提供截图功能但它可以与Python内置的GUI库tkinter结合或者跨平台地调用其他底层库如Windows的ctypes调用user32.dll macOS的Quartz Linux的Xlib来获取屏幕数据然后利用Pillow强大的图像处理能力进行处理。为什么选它无与伦比的灵活性你可以在获取屏幕图像后立即进行裁剪、缩放、滤镜、绘图、保存为各种格式等操作所有流程在一个库内完成。区域截图高效通过直接操作屏幕像素缓冲区可以实现真正高效、精准的矩形区域截图而不必先截全屏。深度控制你可以更接近底层对截图过程有更强的控制力例如获取特定显示器的数据。需要注意什么需要自己“组装”你需要编写更多的代码来整合截图功能和图像处理功能。不同操作系统的底层调用方式不同虽然有一些封装好的跨平台方法如PIL.ImageGrab.grab()在Windows/macOS上可用但在Linux上可能需要额外处理。略微陡峭的学习曲线需要理解一些图形编程的基本概念如坐标系、像素缓冲区RGB/RGBA。2.3 方案三PyQt/PySide - 专业级的窗口抓取核心思路PyQt/PySide是Qt框架的Python绑定是开发专业桌面应用的首选。Qt提供了完整的GUI组件和底层图形访问能力。通过QScreen和QWindow类我们可以直接访问屏幕和窗口的像素数据甚至包括那些最小化到任务栏或者被部分遮挡的窗口。为什么选它高性能与精准控制直接通过图形框架抓取性能通常优于前两种方式尤其是在频繁截图或高分辨率下。应用窗口级抓取这是它的杀手锏。你可以根据窗口标题、类名找到特定的应用程序窗口然后只抓取该窗口的内容即使它被其他窗口遮挡或者处于非活动状态。适合集成到GUI应用中如果你正在用PyQt开发一个带界面的截图工具或监控软件使用它来实现截图功能是天作之合无需引入外部依赖。需要注意什么重量级依赖PyQt本身是一个庞大的库如果你仅仅为了一个截图功能而引入它就像用大炮打蚊子会显著增加项目体积和启动时间。复杂度最高涉及Qt的事件循环QApplication、窗口句柄等概念对新手来说上手难度最大。平台细节虽然Qt是跨平台的但不同系统上窗口管理的细节如如何获取窗口句柄仍有差异代码可能不如前两种方案统一。选型总结速查表特性维度PyAutoGUIPIL (Pillow)PyQt上手速度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐代码简洁度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐功能灵活性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐跨平台一致性⭐⭐⭐⭐⭐⭐⭐⭐ (Linux需注意)⭐⭐⭐⭐额外依赖较少Linux可能需系统工具Pillow库完整的PyQt/PySide最佳场景快速脚本、全屏截图图像处理流程、灵活区域截图专业工具、窗口抓取、GUI应用集成3. 核心细节解析与实操要点确定了方案我们深入每个方案的核心看看在实现时有哪些必须注意的细节和可以提升效率的技巧。3.1 PyAutoGUI安装陷阱与“安全区”异常PyAutoGUI的安装看似简单pip install pyautogui但在某些环境下特别是纯净的Linux系统或特定的Python版本中你可能会遇到编译错误。这是因为它的部分功能依赖于需要编译的C扩展或者像前文热词提到的在构建轮子wheel时获取依赖失败。实操心得如果你在安装pyautogui时遇到Failed to build wheel之类的错误一个有效的解决方法是先确保你的系统安装了Python开发工具链。在Ubuntu/Debian上可以尝试sudo apt-get install python3-dev在CentOS/RHEL上则是sudo yum install python3-devel。如果问题依旧可以尝试使用pip install --no-binary :all: pyautogui强制从源码编译或者寻找预编译的wheel文件。另一个关键点是pyautogui的“故障安全”Fail-Safe机制。热词中提到了pyautogui.FailSafeException。这是一个贴心的设计当你将鼠标快速移动到屏幕的左上角坐标(0,0)时pyautogui会抛出这个异常并立即终止所有自动化操作防止脚本失控。但在截图时如果你的鼠标不小心划过左上角也可能意外触发它。注意事项在编写包含pyautogui操作的脚本时尤其是循环截图脚本建议在开头使用pyautogui.FAILSAFE False禁用故障安全。但请务必谨慎并确保你有其他方式如按特定键来终止失控的脚本。3.2 PIL (Pillow)坐标系、颜色模式与Linux适配使用Pillow截图核心是理解屏幕坐标系。在大多数系统中屏幕的原点(0,0)位于左上角X轴向右递增Y轴向下递增。当你调用ImageGrab.grab(bbox(left, top, right, bottom))时这个矩形区域是左闭右开、上闭下开的。也就是说像素(right, bottom)不会被包含在内。例如grab(bbox(0,0,100,100))会截取一个100x100像素的图片包含第0行到第99行第0列到第99列。截取到的图像对象其颜色模式通常是‘RGB‘。如果你需要处理透明度比如在某些特殊场景下可能需要转换为‘RGBA‘。保存图片时Pillow会根据文件扩展名自动选择编码器。‘PNG‘格式支持无损压缩和透明度是截图保存的首选。对于Linux用户PIL.ImageGrab.grab()可能无法直接使用因为它依赖的平台后端可能未安装。这时一个可靠的跨平台替代方案是使用pyscreenshot库它本身也是调用各种后端或者直接使用mss库后者性能更好。避坑技巧如果你在Linux上使用Pillow截图遇到问题可以尝试安装python3-pil.imagetkDebian/Ubuntu或使用mss库。一个简单的mss示例with mss.mss() as sct: sct.shot(output‘screenshot.png‘)。这比折腾ImageGrab的依赖要简单得多。3.3 PyQt事件循环、窗口查找与性能优化PyQt方案的核心在于QApplication实例。在任何一个PyQt GUI程序中都必须有一个QApplication实例来管理事件循环。即使我们只用来截图不显示窗口也需要创建它app QApplication(sys.argv)或app QApplication([])。对于纯后台截图脚本在完成所有操作后通常不需要调用app.exec_()启动事件循环但QApplication对象必须存在。查找特定窗口是PyQt的强项。QDesktopWidget或QGuiApplication.screens()可以获取屏幕信息。而要抓取特定应用窗口我们需要用到窗口句柄。在Windows上你可以使用win32gui库需额外安装pywin32根据窗口标题或类名找到句柄HWND然后将其转换为PyQt可识别的QWindow对象。这个过程稍显繁琐但一旦封装成函数就非常强大。性能提示频繁截图时避免在每次截图时都创建新的QApplication实例和查找窗口。应该初始化一次然后重复使用QScreen或QWindow对象。对于静态窗口的连续抓取直接抓取其QWindow的像素图QWindow.grab()效率极高。此外如果不需要保存为文件而是直接在内存中处理像素数据使用QImage.constBits()可以获取到底层数据指针与NumPy数组结合能实现最高效的图像处理。4. 实操过程与核心环节实现理论说得再多不如一行代码。接下来我将给出三种方式最核心、最完整的代码实现并附上详细的注释和运行说明。4.1 方案一实现PyAutoGUI 一键全屏与区域截图首先确保安装库pip install pyautoguiimport pyautogui import time def screenshot_with_pyautogui(modefull, regionNone, filenameNone): 使用PyAutoGUI进行截图。 参数: mode (str): 截图模式。‘full‘为全屏‘region‘为区域。 region (tuple): 当mode为‘region‘时有效指定区域(left, top, width, height)。 filename (str): 保存的文件名。如果为None则返回PIL Image对象。 返回: PIL.Image.Image 或 None: 如果filename为None则返回Image对象否则保存文件并返回None。 # 可选禁用故障安全机制防止鼠标移到左上角导致程序退出 # pyautogui.FAILSAFE False try: if mode full: # 全屏截图最简单的一行代码 screenshot pyautogui.screenshot() elif mode region and region: # 区域截图传入(left, top, width, height)四元组 # 注意这里的region是(左, 上, 宽, 高)与PIL的bbox(左,上,右,下)不同 screenshot pyautogui.screenshot(regionregion) else: print(参数错误请提供有效的模式和区域。) return None if filename: # 保存图片支持PNG, JPG等格式 screenshot.save(filename) print(f截图已保存至{filename}) return None else: # 返回PIL Image对象供后续处理 return screenshot except pyautogui.FailSafeException: print(故障安全机制被触发程序终止。) return None except Exception as e: print(f截图过程中发生错误{e}) return None # 使用示例 if __name__ __main__: # 示例1全屏截图并保存 screenshot_with_pyautogui(modefull, filenamefull_screen_pyautogui.png) # 等待2秒让你可以切换窗口 time.sleep(2) # 示例2截取屏幕左上角400x300的区域 # 假设你想截取从(100, 150)坐标开始宽400像素高300像素的区域 region_to_capture (100, 150, 400, 300) # (left, top, width, height) screenshot_with_pyautogui(moderegion, regionregion_to_capture, filenameregion_pyautogui.png) # 示例3获取截图对象并在内存中处理例如获取某个像素的颜色 img_obj screenshot_with_pyautogui(modefull) if img_obj: pixel_color img_obj.getpixel((500, 500)) # 获取坐标(500,500)处的RGB值 print(f屏幕(500,500)处的像素颜色为{pixel_color})代码解读与运行函数screenshot_with_pyautogui封装了两种模式。pyautogui.screenshot()不传参即全屏传region参数即区域截图。PyAutoGUI的区域参数是(left, top, width, height)这与后面PIL的(left, top, right, bottom)不同使用时需留意。函数提供了保存文件和返回PIL.Image对象两种方式灵活性更高。直接运行脚本它会先保存一张全屏截图2秒后再保存一张指定区域的截图最后打印出全屏截图某一点的像素颜色。4.2 方案二实现PIL (Pillow) 灵活抓取与处理首先确保安装库pip install Pillow对于Linux用户如果ImageGrab不可用可以考虑pip install pyscreenshot或pip install mss作为备选。from PIL import ImageGrab, Image import tkinter as tk from datetime import datetime import os def screenshot_with_pil(bboxNone, include_layered_windowsFalse, filenameNone): 使用PIL的ImageGrab进行截图功能更灵活。 参数: bbox (tuple): 可选。指定抓取区域的边界框 (left, top, right, bottom)。 如果为None则截取全屏。 include_layered_windows (bool): 仅Windows有效。是否包含分层窗口如透明窗口、UWP应用。 filename (str): 保存的文件名。如果为None则返回PIL Image对象。 返回: PIL.Image.Image 或 None: 如果filename为None则返回Image对象否则保存文件并返回None。 try: # 核心截图语句 # all_screensTrue 可以抓取所有显示器如果支持 if bbox: im ImageGrab.grab(bboxbbox, include_layered_windowsinclude_layered_windows) else: im ImageGrab.grab(all_screensTrue, include_layered_windowsinclude_layered_windows) if filename: # 确保目录存在 os.makedirs(os.path.dirname(os.path.abspath(filename)), exist_okTrue) im.save(filename) print(fPIL截图已保存至{filename}) return None else: return im except Exception as e: print(fPIL截图失败错误信息{e}) # 尝试备选方案对于非Windows/macOSImageGrab可能失效 # 这里可以添加调用pyscreenshot或mss的备用代码 return None def get_screen_resolution(): 使用tkinter获取主屏幕分辨率一种轻量级方法。 root tk.Tk() width root.winfo_screenwidth() height root.winfo_screenheight() root.destroy() # 立即销毁窗口避免内存占用 return width, height # 使用示例 if __name__ __main__: # 示例1全屏截图并保存包含分层窗口Windows screenshot_with_pil(filenamefull_screen_pil.png) # 示例2获取屏幕分辨率并截取右半屏 screen_width, screen_height get_screen_resolution() right_half_bbox (screen_width // 2, 0, screen_width, screen_height) screenshot_with_pil(bboxright_half_bbox, filenameright_half_pil.png) # 示例3截图后直接进行图像处理转换为灰度图并保存 img screenshot_with_pil(bbox(100, 100, 500, 400)) # 截取一个400x300的区域 if img: # 转换为灰度图 gray_img img.convert(L) timestamp datetime.now().strftime(%Y%m%d_%H%M%S) gray_img.save(fprocessed_gray_{timestamp}.png) print(已保存处理后的灰度截图。) # 示例4多显示器支持如果系统连接了多个显示器 # ImageGrab.grab(all_screensTrue) 会返回一个包含所有显示器拼接画面的图像。 # 你可以通过计算每个显示器的偏移量来裁剪出单个显示器的画面。 # 注意不同系统上多显示器的排列方式扩展/复制会影响结果。代码解读与运行ImageGrab.grab()是核心函数。bbox参数使用(左上右下)坐标系。include_layered_windows是Windows平台特有参数对于抓取一些现代应用如UWP应用、透明效果窗口的内容很有用。all_screensTrue尝试抓取所有显示器的画面拼接图这在多显示器环境下非常有用。我们使用tkinter来获取屏幕分辨率因为它通常是Python标准库的一部分无需额外安装。示例展示了截图后立即进行图像处理转灰度的流程体现了Pillow在“截图-处理”流水线中的优势。4.3 方案三实现PyQt5 精准窗口截图首先确保安装库pip install PyQt5如果需要抓取特定窗口在Windows上可能还需要pip install pywin32import sys from PyQt5.QtWidgets import QApplication from PyQt5.QtGui import QWindow, QScreen, QPixmap, QImage from PyQt5.QtCore import QRect, QBuffer, QIODevice import win32gui # 仅Windows用于查找窗口句柄 import win32con def screenshot_with_pyqt(modescreen, window_titleNone, save_pathpyqt_screenshot.png): 使用PyQt5进行截图。 参数: mode (str): ‘screen‘ 截取整个屏幕‘window‘ 截取特定窗口。 window_title (str): 当mode为‘window‘时指定目标窗口的标题部分匹配即可。 save_path (str): 截图保存路径。 # 必须创建QApplication实例即使没有GUI界面 app QApplication(sys.argv) # 或者 QApplication([]) screenshot_pixmap None try: if mode screen: # 获取主屏幕 screen QApplication.primaryScreen() if screen is not None: # 截取整个屏幕 screenshot_pixmap screen.grabWindow(0) # 参数0代表整个屏幕 else: print(无法获取屏幕对象。) return False elif mode window and window_title: # **Windows平台通过窗口标题查找窗口句柄** # 这是一个高级功能演示如何抓取特定应用窗口 def callback(hwnd, hwnds): if win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd): window_text win32gui.GetWindowText(hwnd) if window_title.lower() in window_text.lower(): hwnds.append(hwnd) return True hwnds [] win32gui.EnumWindows(callback, hwnds) if hwnds: target_hwnd hwnds[0] # 取第一个匹配的窗口 # 将Windows句柄转换为PyQt可识别的WId window QWindow.fromWinId(target_hwnd) if window: # 抓取该窗口 screenshot_pixmap window.screen().grabWindow(window.winId()) else: print(无法将窗口句柄转换为QWindow对象。) return False else: print(f未找到标题包含‘{window_title}‘的可见窗口。) return False else: print(参数错误。) return False # 保存截图 if screenshot_pixmap and not screenshot_pixmap.isNull(): success screenshot_pixmap.save(save_path) if success: print(fPyQt截图已保存至{save_path}) return True else: print(保存截图文件失败。) return False else: print(截图失败获取到的图像无效。) return False except Exception as e: print(fPyQt截图过程中发生错误{e}) return False finally: # 对于一次性截图脚本通常不需要启动事件循环但需要保持QApplication对象存在 # 这里我们不需要调用 app.exec_() pass # 使用示例 if __name__ __main__: # 示例1截取整个屏幕 screenshot_with_pyqt(modescreen, save_pathfull_screen_pyqt.png) # 示例2截取特定窗口例如记事本窗口 # 请先打开一个记事本Notepad并将其标题改为“测试.txt - 记事本”或类似。 # 下面的调用会查找窗口标题中包含“记事本”的窗口。 # 注意此功能仅适用于Windows且需要pywin32库。 try: import win32gui screenshot_with_pyqt(modewindow, window_title记事本, save_pathnotepad_window_pyqt.png) except ImportError: print(未安装pywin32跳过窗口截图示例。) # 示例3获取截图数据并进行处理不保存文件 app QApplication(sys.argv) screen QApplication.primaryScreen() pixmap screen.grabWindow(0) # 将QPixmap转换为QImage进而可以访问像素数据 image pixmap.toImage() # 例如转换为灰度图 gray_image image.convertToFormat(QImage.Format_Grayscale8) # 保存处理后的图像 gray_image.save(gray_screen_pyqt.png) print(已保存PyQt灰度截图。)代码解读与运行QApplication实例这是PyQt程序的起点必须创建。屏幕截图QScreen.grabWindow(0)是截取整个屏幕的标准方法。窗口截图这是高级功能。我们使用win32gui遍历所有窗口找到标题匹配的窗口句柄HWND。然后通过QWindow.fromWinId()将其转换为Qt的QWindow对象最后用grabWindow抓取。注意pywin32和窗口查找逻辑是Windows特有的macOS和Linux有对应的系统API如Quartz和X11实现起来更复杂。图像处理PyQt的QImage对象提供了丰富的图像处理功能可以与QPixmap相互转换。示例展示了转换为灰度图并保存。运行前请确保已安装PyQt5。窗口截图示例需要Windows系统和pywin32库并确保有标题包含“记事本”的窗口在前台运行。5. 常见问题与排查技巧实录在实际使用这些方法时你肯定会遇到各种各样的问题。下面是我总结的一些典型问题及其解决方案。5.1 通用问题Q1截图是全黑的或者内容不正确。可能原因A多显示器在有多台显示器的情况下截图库可能默认只抓取了主显示器或者抓取了错误的显示器区域。排查检查你的代码是否指定了正确的屏幕或区域。对于PIL尝试ImageGrab.grab(all_screensTrue)查看是否是所有显示器的拼接图。对于PyQt使用QApplication.screens()列表来获取特定屏幕。可能原因B权限或特殊窗口在一些系统上抓取某些具有特殊权限的窗口如安全登录界面、DRM保护的内容或最小化的窗口可能会失败或得到黑屏。排查尝试抓取普通的、前置的应用程序窗口如浏览器、文本编辑器。对于被遮挡的窗口PyQt方案可能有效但也不是百分百成功。可能原因CLinux桌面环境某些Linux桌面环境如Wayland显示服务器出于安全考虑限制了程序对屏幕内容的直接访问。传统的X11抓取方法在Wayland上可能失效。排查确认你的桌面环境。对于Wayland可能需要使用专门的API或工具如grimSway/Wayland原生截图工具并通过pip安装其Python绑定或调用子进程。Q2截图速度很慢导致程序卡顿。可能原因频繁调用截图函数每次调用都进行完整的屏幕像素拷贝和内存分配。优化降低分辨率/区域如果不需要全屏高清图指定一个较小的bbox区域。降低频率评估是否真的需要每秒多次截图。适当增加截图间隔。选择高性能库对于高频截图mss库通常比PIL.ImageGrab和pyautogui性能更好。PyQt方案在抓取特定窗口时也很快。内存复用如果可能复用图像缓冲区对象而不是每次创建新的。5.2 各方案特有问题PyAutoGUI 专属问题pyautogui.FailSafeException: PyAutoGUI fail-safe triggered原因鼠标移动到了屏幕左上角坐标(0,0)。解决在脚本开头设置pyautogui.FAILSAFE False来禁用此功能但请务必谨慎并确保有其他终止脚本的方法如监听特定按键。安装错误error: failed to build ‘pyautogui‘原因缺少编译依赖或环境问题。解决升级pip和setuptoolspython -m pip install --upgrade pip setuptools wheel安装系统开发工具如前文所述。尝试从预编译的wheel安装去 PyPI 上查找对应你系统和Python版本的.whl文件用pip install 文件名.whl安装。终极方案换用其他截图方法如PILmss。PIL (Pillow) 专属问题ImportError: cannot import name ‘_imaging‘ from ‘PIL‘或ImageGrab在Linux上报错原因Pillow安装不完整或平台不支持ImageGrab。解决重新安装Pillowpip uninstall Pillow然后pip install Pillow。对于Linux的ImageGrab问题直接使用mss库替代pip install mss然后使用with mss.mss() as sct: sct.shot()。截图区域坐标计算错误原因混淆了(left, top, width, height)和(left, top, right, bottom)两种坐标系。牢记PIL的bbox参数是右开下开的(左上右下)。right left width,bottom top height。PyQt 专属问题This application failed to start because no Qt platform plugin could be initialized.原因常见于打包后的程序或某些缺少GUI环境的系统如无头服务器。解决在创建QApplication前设置环境变量。对于无头环境可以尝试使用os.environ[‘QT_QPA_PLATFORM‘] ‘offscreen‘。但这需要Qt编译时包含offscreen插件。窗口截图找不到目标窗口原因窗口标题不匹配、窗口已最小化、或使用了错误的查找方式。排查使用win32gui.EnumWindows打印所有可见窗口的标题确认目标窗口的确切标题。确保窗口是可见的IsWindowVisible返回True。考虑使用窗口类名GetClassName进行更精确的匹配因为标题可能动态变化。5.3 进阶技巧与场景延伸场景一定时循环截图制作延时摄影或监控。import time import pyautogui # 或 from PIL import ImageGrab interval 5 # 截图间隔单位秒 duration 60 # 总持续时间单位秒 output_dir ‘timelapse‘ import os os.makedirs(output_dir, exist_okTrue) start_time time.time() frame_count 0 while time.time() - start_time duration: timestamp time.strftime(“%Y%m%d_%H%M%S”) filename os.path.join(output_dir, f”frame_{timestamp}_{frame_count:04d}.png”) # 使用pyautogui或PIL截图 # pyautogui.screenshot(filename) # 或 ImageGrab.grab().save(filename) print(f”已保存: {filename}”) frame_count 1 time.sleep(interval)技巧使用高压缩比的JPEG格式可以显著减少文件体积和磁盘I/O压力但会损失画质。根据监控需求权衡。场景二比较两次截图的差异可用于自动化测试。from PIL import ImageGrab, ImageChops, Image import math def screenshot_and_compare(previous_imgNone, bboxNone, threshold10): 截图并与前一张图比较返回差异度和新图像 current_img ImageGrab.grab(bboxbbox) if bbox else ImageGrab.grab() if previous_img is None: return 0.0, current_img # 第一次截图无差异 # 计算差异 diff ImageChops.difference(previous_img, current_img) # 将差异图像转换为灰度并计算统计值粗略代表差异程度 diff_stat diff.convert(‘L‘).point(lambda x: 255 if x threshold else 0) hist diff_stat.histogram() changed_pixels sum(hist[1:]) # 统计非纯黑0的像素数 total_pixels diff_stat.size[0] * diff_stat.size[1] change_ratio changed_pixels / total_pixels if total_pixels 0 else 0 return change_ratio, current_img # 使用示例 prev_img None for i in range(3): ratio, prev_img screenshot_and_compare(prev_img, bbox(0,0,800,600)) print(f”第{i1}次截图与上次差异度{ratio:.2%}”) time.sleep(1)技巧ImageChops.difference能精确计算像素差异。通过设置threshold可以忽略微小的颜色波动如抗锯齿造成的差异。这种方法在UI自动化测试中检查界面是否发生变化非常有用。场景三将截图直接嵌入到GUI应用中实时显示。这通常结合PyQt或tkinter实现。核心思路是在一个定时器QTimer或循环中不断截图然后将截图数据QPixmap或PIL.Image转换为可以在GUI控件如QLabel上显示的格式并更新。这可以实现简单的屏幕共享预览或监控面板功能。由于涉及GUI事件循环代码稍复杂但原理与上述截图代码一脉相承。