Windows桌面壁纸自动化管理Python脚本实现定时切换、多屏适配与一键部署前言桌面壁纸管理看似简单但在实际使用中会遇到几个痛点手动换壁纸太麻烦想根据时间段自动切换不同风格多显示器场景下每块屏幕想设不同壁纸系统自带功能不够用换了电脑或重装系统后壁纸收藏全部丢失动态壁纸和静态壁纸想按场景自动切换比如工作时静态、休息时动态本文以小鸟壁纸birdwallpaper.ijinshan.com作为壁纸来源结合 Python 脚本实现一套轻量级的桌面壁纸自动化管理方案。核心思路是用小鸟壁纸的海量壁纸库解决内容来源问题用 Python 脚本解决自动化调度问题。小鸟壁纸的缓存目录会保存所有用户下载或浏览过的壁纸文件包括图片和视频格式。这个缓存目录就是我们脚本的数据源——不需要单独爬取壁纸只需要扫描这个目录就能拿到全部可用素材。相比自己写爬虫去壁纸网站采集这种方式省去了反爬、格式解析、去重等一系列工程问题直接拿到了已经分类整理好的壁纸库。一、整体架构设计这套系统时遵循了数据源与调度逻辑解耦的原则。小鸟壁纸负责壁纸的获取、分类和更新Python脚本只负责读取缓存目录中的文件然后按规则调度切换。小鸟壁纸客户端壁纸源 │ ▼ 本地壁纸缓存目录自动下载的壁纸文件 │ ▼ Python 调度引擎 ├── 壁纸索引模块 → 扫描缓存目录建立壁纸元数据库 ├── 定时切换模块 → 按规则匹配壁纸并调用系统API设置 ├── 多屏管理模块 → 为每块屏幕独立分配壁纸 └── 配置备份模块 → 导出/导入壁纸配置这种架构的好处是小鸟壁纸和Python脚本各自独立运行、互不依赖。小鸟壁纸更新了壁纸库Python脚本下次扫描时自动感知。脚本挂了也不影响小鸟壁纸正常使用。解耦带来的另一个好处是扩展性——未来如果换用其他壁纸源只需要修改索引器的扫描路径其他模块完全不用动。二、环境准备2.1 安装小鸟壁纸从小鸟壁纸官网birdwallpaper.ijinshan.com下载并安装。装好后软件会自动将下载过的壁纸缓存到本地目录。这个缓存机制是脚本能工作的前提——小鸟壁纸不会把壁纸存在数据库或加密文件中而是直接以原始格式jpg/png/mp4等保存在文件系统里这让外部脚本可以直接读取。默认缓存路径通常在C:\Users\用户名\AppData\Local\BirdWallpaper\Cache如果安装时改了路径可以通过软件设置→存储管理中查看实际位置。这个路径在后续所有脚本中都会用到是唯一需要根据自己电脑修改的配置项。2.2 Python 环境需要 Python 3.8。依赖方面尽量精简除了Pillow用于读取图片尺寸信息外其他功能全部使用标准库实现。ctypes用于调用 Windows API 设置壁纸os/json/hashlib用于文件扫描和索引管理schedule用于定时任务调度。pipinstallPillow schedule多屏独立设置需要pywin32可选只在多屏场景下需要pipinstallpywin32三、模块一壁纸索引器第一个要解决的问题是缓存目录里有几百上千张壁纸杂乱地分布在不同的子文件夹里怎么快速按条件筛选索引器的设计思路是增量扫描元数据提取。首次运行时遍历整个缓存目录为每张壁纸提取关键信息尺寸、长宽比、文件类型、文件大小存入一个 JSON 索引文件。后续运行时只扫描新增的文件通过 MD5 哈希去重。选择 MD5 而不是直接比较文件名是因为同一个小鸟壁纸ID的壁纸可能会在不同时间点下载到不同子目录。用文件内容的哈希作为唯一标识可以精准识别同一张壁纸避免索引中出现重复条目。extract_meta方法中只对图片类型调用 Pillow 读取尺寸信息视频文件跳过这一步因为视频的解码开销太大且调度规则通常不会按视频分辨率筛选。这是一个刻意的性能取舍。importosimportjsonimporthashlibfromdatetimeimportdatetimefromPILimportImageclassWallpaperIndexer:def__init__(self,cache_dir):self.cache_dircache_dir self.index_filewallpaper_index.jsonself.indexself._load_index()def_load_index(self):ifos.path.exists(self.index_file):withopen(self.index_file,r,encodingutf-8)asf:returnjson.load(f)return{}defscan(self):扫描缓存目录增量更新索引forroot,dirs,filesinos.walk(self.cache_dir):forfinfiles:iff.lower().endswith((.jpg,.jpeg,.png,.bmp,.mp4,.webm)):full_pathos.path.join(root,f)file_hashself._hash_file(full_path)iffile_hashnotinself.index:self.index[file_hash]self._extract_meta(full_path,f)self._save()def_hash_file(self,path):hasherhashlib.md5()withopen(path,rb)asf:hasher.update(f.read(65536))# 只读前64KB做快速哈希returnhasher.hexdigest()def_extract_meta(self,path,filename):meta{path:path,filename:filename,size_bytes:os.path.getsize(path),added:datetime.now().isoformat(),type:videoiffilename.lower().endswith((.mp4,.webm))elseimage,}ifmeta[type]image:try:withImage.open(path)asimg:meta[width]img.width meta[height]img.height meta[aspect_ratio]round(img.width/img.height,2)exceptException:meta[width]meta[height]0meta[aspect_ratio]0returnmetadef_save(self):withopen(self.index_file,w,encodingutf-8)asf:json.dump(self.index,f,indent2,ensure_asciiFalse)defquery(self,min_width0,aspect_ratioNone,file_typeNone):按条件筛选壁纸results[]forh,metainself.index.items():ifmin_widthandmeta.get(width,0)min_width:continueifaspect_ratioandabs(meta.get(aspect_ratio,0)-aspect_ratio)0.1:continueiffile_typeandmeta[type]!file_type:continueresults.append(meta)returnresultsif__name____main__:indexerWallpaperIndexer(C:/Users/YourName/AppData/Local/BirdWallpaper/Cache)indexer.scan()print(f索引完成共{len(indexer.index)}张壁纸)索引文件wallpaper_index.json的结构大致如下可以直接用文本编辑器打开查看和手动编辑{a1b2c3d4...:{path:C:/Users/.../Cache/wallpaper_001.jpg,filename:wallpaper_001.jpg,width:3840,height:2160,aspect_ratio:1.78,type:image,size_bytes:2456789,added:2026-06-12T10:30:00}}四、模块二壁纸设置引擎有了壁纸索引下一步是把壁纸真正设置到桌面上。Windows 提供了两条设置壁纸的路径。路径一SystemParametersInfo(SPI_SETDESKWALLPAPER)。这是最经典的 Windows API从 Windows 95 一直延续到 Windows 11。优点是兼容性极好缺点是只能设置单张壁纸给所有屏幕共用不支持多屏独立设置。路径二IDesktopWallpaperCOM接口。从 Windows 8 开始引入支持为每块显示器独立设置壁纸。但需要通过 COM 调用对 Python 来说需要pywin32桥接代码也复杂不少。本引擎同时实现了两条路径set_single走路径一适合单屏或对所有屏幕统一设置的场景set_per_monitor走路径二需要多屏独立设置时使用。如果set_per_monitor调用失败比如系统是 Windows 7 或未安装 pywin32会自动回退到set_single保证核心功能不中断。importctypesimportosimportrandomclassWallpaperSetter:SPI_SETDESKWALLPAPER0x0014SPIF_UPDATEINIFILE0x01SPIF_SENDCHANGE0x02staticmethoddefset_single(image_path):设置单张壁纸所有屏幕统一ifnotos.path.exists(image_path):raiseFileNotFoundError(f壁纸文件不存在:{image_path})ctypes.windll.user32.SystemParametersInfoW(WallpaperSetter.SPI_SETDESKWALLPAPER,0,image_path,WallpaperSetter.SPIF_UPDATEINIFILE|WallpaperSetter.SPIF_SENDCHANGE)staticmethoddefset_per_monitor(wallpapers:dict): 为每块屏幕独立设置壁纸 wallpapers: { monitor_index: image_path } 需要 Windows 8 支持 try:importpythoncom pythoncom.CoInitialize()fromwin32com.clientimportDispatch desktopDispatch(Shell.Application)wallpaper_objdesktop.GetType().InvokeMember(DesktopWallpaper,0x200,None,desktop,None)formonitor_idinwallpapers:ifmonitor_idwallpaper_obj.GetType().InvokeMember(GetMonitorDevicePathCount,0x200,None,wallpaper_obj,None):monitor_pathwallpaper_obj.GetType().InvokeMember(GetMonitorDevicePathAt,0x200,None,wallpaper_obj,[monitor_id])image_pathwallpapers[monitor_id]ifos.path.exists(image_path):wallpaper_obj.GetType().InvokeMember(SetWallpaper,0x200,None,wallpaper_obj,[monitor_path,image_path])exceptImportError:print(多屏独立设置需要 pywin32: pip install pywin32)exceptExceptionase:print(f多屏设置失败:{e}回退到单屏模式)first_wallpaperlist(wallpapers.values())[0]WallpaperSetter.set_single(first_wallpaper)staticmethoddefset_random(wallpaper_list,per_monitorFalse):随机选择壁纸设置ifnotwallpaper_list:returnifper_monitor:wallpapers{0:random.choice(wallpaper_list)}WallpaperSetter.set_per_monitor(wallpapers)else:WallpaperSetter.set_single(random.choice(wallpaper_list))五、模块三定时调度器索引器和设置器就绪后调度器负责把它们串起来。设计调度规则时考虑了一个场景工作时间希望壁纸简洁、不分散注意力休息时间可以切换到动态视频壁纸或更炫的视觉效果。所以规则按时间段划分了四个区间每个区间可以独立配置筛选条件。_load_rules方法返回的字典就是规则配置。每个时段可以指定最低分辨率min_width防止低清壁纸被选中可以指定文件类型file_type工作时间只选静态图晚间允许视频壁纸还可以指定长宽比aspect_ratio适配不同比例的屏幕。调度器使用schedule库做定时触发默认每30分钟检查一次当前时段并执行对应的壁纸切换。这个间隔可以按需调整——太频繁会产生不必要的磁盘IO太稀疏调度精度不够。30分钟是一个折中值。importtimeimportschedulefromdatetimeimportdatetimeclassWallpaperScheduler:def__init__(self,indexer,setter):self.indexerindexer self.settersetter self.rulesself._load_rules()def_load_rules(self):加载调度规则可按需自定义return{morning:{min_width:1920,aspect_ratio:None,file_type:image,},afternoon:{min_width:2560,aspect_ratio:None,file_type:image,},evening:{min_width:1920,aspect_ratio:None,file_type:None,# 图片或视频均可},night:{min_width:0,aspect_ratio:None,file_type:image,},}def_get_current_period(self):hourdatetime.now().hourif6hour12:returnmorningelif12hour18:returnafternoonelif18hour24:returneveningelse:returnnightdefexecute_rule(self):periodself._get_current_period()rule_filterself.rules[period]wallpapersself.indexer.query(**rule_filter)ifwallpapers:paths[w[path]forwinwallpapers]self.setter.set_random(paths)print(f[{datetime.now().strftime(%H:%M)}] 已切换到{period}时段壁纸候选{len(paths)}张)else:print(f[{datetime.now().strftime(%H:%M)}]{period}时段无匹配壁纸)defstart(self,interval_minutes30):print(f壁纸调度器已启动每{interval_minutes}分钟切换一次)self.execute_rule()# 立即执行一次schedule.every(interval_minutes).minutes.do(self.execute_rule)whileTrue:schedule.run_pending()time.sleep(10)六、模块四配置备份与恢复壁纸自动化跑起来之后索引文件和调度规则就是你积累的成果。换了电脑或者重装系统这些数据全丢会很心疼。备份模块把索引文件和配置目录打包成带时间戳的 ZIP 压缩包。恢复时直接解压覆盖到原目录索引器下次扫描时自动识别已有文件新下载的壁纸会增量补充进来。之所以用 ZIP 而不是直接复制文件夹是因为小鸟壁纸的缓存目录可能有几百 MB 甚至几 GB 的图片文件——这些不需要备份只要重新从小鸟壁纸下载就行。我们只需要备份索引元数据几 KB和配置信息ZIP 压缩后通常不到 1MB。importosimportzipfilefromdatetimeimportdatetimeclassConfigBackup:def__init__(self,cache_dir,backup_dir./wallpaper_backups):self.cache_dircache_dir self.backup_dirbackup_dir os.makedirs(backup_dir,exist_okTrue)defexport_config(self):导出壁纸索引 配置文件到压缩包timestampdatetime.now().strftime(%Y%m%d_%H%M%S)backup_fileos.path.join(self.backup_dir,fwallpaper_backup_{timestamp}.zip)withzipfile.ZipFile(backup_file,w,zipfile.ZIP_DEFLATED)aszf:index_filewallpaper_index.jsonifos.path.exists(index_file):zf.write(index_file)config_diros.path.join(os.path.dirname(self.cache_dir),Config)ifos.path.exists(config_dir):forroot,dirs,filesinos.walk(config_dir):forfinfiles:fullos.path.join(root,f)arcos.path.relpath(full,os.path.dirname(config_dir))zf.write(full,arc)print(f配置已导出到:{backup_file})returnbackup_filedefimport_config(self,backup_file):从压缩包恢复配置withzipfile.ZipFile(backup_file,r)aszf:zf.extractall(os.path.dirname(self.cache_dir))print(f配置已从{backup_file}恢复)七、主程序入口四个模块全部就绪后用一个main函数把它们串起来。启动流程分四步检查缓存目录是否存在不存在说明小鸟壁纸还没装或者还没下载过壁纸、扫描索引、备份当前配置、启动调度循环。如果缓存目录不存在脚本会给出明确的提示而不是直接报错退出。这是一个对用户的友好处理——很多工具脚本的报错信息太技术化普通用户看不懂。importosimportsysdefmain():CACHE_DIRos.path.expandvars(r%LOCALAPPDATA%\BirdWallpaper\Cache)ifnotos.path.exists(CACHE_DIR):print(f缓存目录不存在:{CACHE_DIR})print(请先安装并运行小鸟壁纸下载至少一张壁纸后再启动本脚本)print(下载地址birdwallpaper.ijinshan.com)sys.exit(1)indexerWallpaperIndexer(CACHE_DIR)setterWallpaperSetter()schedulerWallpaperScheduler(indexer,setter)backupConfigBackup(CACHE_DIR)print(正在扫描壁纸缓存目录...)indexer.scan()print(f共发现{len(indexer.index)}张壁纸)backup.export_config()scheduler.start(interval_minutes30)if__name____main__:main()八、扩展方向以上是一套基础框架代码量不大但覆盖了壁纸管理的核心流程。以下是一些可以自行扩展的方向接入天气API。获取当前城市的天气数据晴/阴/雨/雪根据天气匹配不同氛围的壁纸。比如雨天自动切换到暗色调壁纸晴天切换到明亮色调。需要注册一个免费的天气API如和风天气在调度器中增加一个天气查询步骤即可。GPU负载感知。通过nvidia-smi或pyadl库获取GPU实时负载当检测到GPU占用超过阈值比如80%时自动将动态视频壁纸切换为静态图片释放渲染资源。这在打游戏时需要——视频壁纸的持续解码和渲染会抢占GPU资源。跨设备同步。把wallpaper_index.json和备份 ZIP 存到 OneDrive 或坚果云的同步目录下。多台电脑共享同一份索引每台机器只需要单独维护自己的小鸟壁纸缓存目录即可。GUI管理面板。用 PyQt5 或 Tkinter 给这套脚本包一个可视化管理界面实时预览当前壁纸、手动切换、编辑调度规则、查看索引统计。适合不想手动改代码和配置文件的使用场景。九、常见问题Q运行脚本后壁纸没变化检查缓存目录路径是否正确。小鸟壁纸的缓存目录可以在软件设置中查看。如果路径不对修改主程序中的CACHE_DIR变量。另外确认一下缓存目录里确实有壁纸文件——如果小鸟壁纸刚安装还没有使用过缓存目录可能是空的。Q多屏设置不生效set_per_monitor方法依赖 Windows 8 以上系统且需要安装pywin32pip install pywin32。不满足这两个条件时脚本会自动回退到单屏统一设置模式。Q小鸟壁纸本身有自动换壁纸功能为什么还要写脚本自带的时间切换功能只能在小鸟壁纸设定的分类范围内轮换不支持按场景制定规则。脚本的价值在于可以通过外部条件驱动——比如根据时间段切换不同的分辨率要求、根据GPU状态自动暂停动态壁纸、接入天气API做氛围匹配。这些都不是自带功能能做到的。Q脚本会影响小鸟壁纸正常使用吗不会。脚本只读取缓存目录中的文件不修改小鸟壁纸本身的任何配置或数据。两者完全独立运行。小鸟壁纸下载地址birdwallpaper.ijinshan.com
Windows桌面壁纸自动化管理:Python脚本实现定时切换、多屏适配与一键部署
Windows桌面壁纸自动化管理Python脚本实现定时切换、多屏适配与一键部署前言桌面壁纸管理看似简单但在实际使用中会遇到几个痛点手动换壁纸太麻烦想根据时间段自动切换不同风格多显示器场景下每块屏幕想设不同壁纸系统自带功能不够用换了电脑或重装系统后壁纸收藏全部丢失动态壁纸和静态壁纸想按场景自动切换比如工作时静态、休息时动态本文以小鸟壁纸birdwallpaper.ijinshan.com作为壁纸来源结合 Python 脚本实现一套轻量级的桌面壁纸自动化管理方案。核心思路是用小鸟壁纸的海量壁纸库解决内容来源问题用 Python 脚本解决自动化调度问题。小鸟壁纸的缓存目录会保存所有用户下载或浏览过的壁纸文件包括图片和视频格式。这个缓存目录就是我们脚本的数据源——不需要单独爬取壁纸只需要扫描这个目录就能拿到全部可用素材。相比自己写爬虫去壁纸网站采集这种方式省去了反爬、格式解析、去重等一系列工程问题直接拿到了已经分类整理好的壁纸库。一、整体架构设计这套系统时遵循了数据源与调度逻辑解耦的原则。小鸟壁纸负责壁纸的获取、分类和更新Python脚本只负责读取缓存目录中的文件然后按规则调度切换。小鸟壁纸客户端壁纸源 │ ▼ 本地壁纸缓存目录自动下载的壁纸文件 │ ▼ Python 调度引擎 ├── 壁纸索引模块 → 扫描缓存目录建立壁纸元数据库 ├── 定时切换模块 → 按规则匹配壁纸并调用系统API设置 ├── 多屏管理模块 → 为每块屏幕独立分配壁纸 └── 配置备份模块 → 导出/导入壁纸配置这种架构的好处是小鸟壁纸和Python脚本各自独立运行、互不依赖。小鸟壁纸更新了壁纸库Python脚本下次扫描时自动感知。脚本挂了也不影响小鸟壁纸正常使用。解耦带来的另一个好处是扩展性——未来如果换用其他壁纸源只需要修改索引器的扫描路径其他模块完全不用动。二、环境准备2.1 安装小鸟壁纸从小鸟壁纸官网birdwallpaper.ijinshan.com下载并安装。装好后软件会自动将下载过的壁纸缓存到本地目录。这个缓存机制是脚本能工作的前提——小鸟壁纸不会把壁纸存在数据库或加密文件中而是直接以原始格式jpg/png/mp4等保存在文件系统里这让外部脚本可以直接读取。默认缓存路径通常在C:\Users\用户名\AppData\Local\BirdWallpaper\Cache如果安装时改了路径可以通过软件设置→存储管理中查看实际位置。这个路径在后续所有脚本中都会用到是唯一需要根据自己电脑修改的配置项。2.2 Python 环境需要 Python 3.8。依赖方面尽量精简除了Pillow用于读取图片尺寸信息外其他功能全部使用标准库实现。ctypes用于调用 Windows API 设置壁纸os/json/hashlib用于文件扫描和索引管理schedule用于定时任务调度。pipinstallPillow schedule多屏独立设置需要pywin32可选只在多屏场景下需要pipinstallpywin32三、模块一壁纸索引器第一个要解决的问题是缓存目录里有几百上千张壁纸杂乱地分布在不同的子文件夹里怎么快速按条件筛选索引器的设计思路是增量扫描元数据提取。首次运行时遍历整个缓存目录为每张壁纸提取关键信息尺寸、长宽比、文件类型、文件大小存入一个 JSON 索引文件。后续运行时只扫描新增的文件通过 MD5 哈希去重。选择 MD5 而不是直接比较文件名是因为同一个小鸟壁纸ID的壁纸可能会在不同时间点下载到不同子目录。用文件内容的哈希作为唯一标识可以精准识别同一张壁纸避免索引中出现重复条目。extract_meta方法中只对图片类型调用 Pillow 读取尺寸信息视频文件跳过这一步因为视频的解码开销太大且调度规则通常不会按视频分辨率筛选。这是一个刻意的性能取舍。importosimportjsonimporthashlibfromdatetimeimportdatetimefromPILimportImageclassWallpaperIndexer:def__init__(self,cache_dir):self.cache_dircache_dir self.index_filewallpaper_index.jsonself.indexself._load_index()def_load_index(self):ifos.path.exists(self.index_file):withopen(self.index_file,r,encodingutf-8)asf:returnjson.load(f)return{}defscan(self):扫描缓存目录增量更新索引forroot,dirs,filesinos.walk(self.cache_dir):forfinfiles:iff.lower().endswith((.jpg,.jpeg,.png,.bmp,.mp4,.webm)):full_pathos.path.join(root,f)file_hashself._hash_file(full_path)iffile_hashnotinself.index:self.index[file_hash]self._extract_meta(full_path,f)self._save()def_hash_file(self,path):hasherhashlib.md5()withopen(path,rb)asf:hasher.update(f.read(65536))# 只读前64KB做快速哈希returnhasher.hexdigest()def_extract_meta(self,path,filename):meta{path:path,filename:filename,size_bytes:os.path.getsize(path),added:datetime.now().isoformat(),type:videoiffilename.lower().endswith((.mp4,.webm))elseimage,}ifmeta[type]image:try:withImage.open(path)asimg:meta[width]img.width meta[height]img.height meta[aspect_ratio]round(img.width/img.height,2)exceptException:meta[width]meta[height]0meta[aspect_ratio]0returnmetadef_save(self):withopen(self.index_file,w,encodingutf-8)asf:json.dump(self.index,f,indent2,ensure_asciiFalse)defquery(self,min_width0,aspect_ratioNone,file_typeNone):按条件筛选壁纸results[]forh,metainself.index.items():ifmin_widthandmeta.get(width,0)min_width:continueifaspect_ratioandabs(meta.get(aspect_ratio,0)-aspect_ratio)0.1:continueiffile_typeandmeta[type]!file_type:continueresults.append(meta)returnresultsif__name____main__:indexerWallpaperIndexer(C:/Users/YourName/AppData/Local/BirdWallpaper/Cache)indexer.scan()print(f索引完成共{len(indexer.index)}张壁纸)索引文件wallpaper_index.json的结构大致如下可以直接用文本编辑器打开查看和手动编辑{a1b2c3d4...:{path:C:/Users/.../Cache/wallpaper_001.jpg,filename:wallpaper_001.jpg,width:3840,height:2160,aspect_ratio:1.78,type:image,size_bytes:2456789,added:2026-06-12T10:30:00}}四、模块二壁纸设置引擎有了壁纸索引下一步是把壁纸真正设置到桌面上。Windows 提供了两条设置壁纸的路径。路径一SystemParametersInfo(SPI_SETDESKWALLPAPER)。这是最经典的 Windows API从 Windows 95 一直延续到 Windows 11。优点是兼容性极好缺点是只能设置单张壁纸给所有屏幕共用不支持多屏独立设置。路径二IDesktopWallpaperCOM接口。从 Windows 8 开始引入支持为每块显示器独立设置壁纸。但需要通过 COM 调用对 Python 来说需要pywin32桥接代码也复杂不少。本引擎同时实现了两条路径set_single走路径一适合单屏或对所有屏幕统一设置的场景set_per_monitor走路径二需要多屏独立设置时使用。如果set_per_monitor调用失败比如系统是 Windows 7 或未安装 pywin32会自动回退到set_single保证核心功能不中断。importctypesimportosimportrandomclassWallpaperSetter:SPI_SETDESKWALLPAPER0x0014SPIF_UPDATEINIFILE0x01SPIF_SENDCHANGE0x02staticmethoddefset_single(image_path):设置单张壁纸所有屏幕统一ifnotos.path.exists(image_path):raiseFileNotFoundError(f壁纸文件不存在:{image_path})ctypes.windll.user32.SystemParametersInfoW(WallpaperSetter.SPI_SETDESKWALLPAPER,0,image_path,WallpaperSetter.SPIF_UPDATEINIFILE|WallpaperSetter.SPIF_SENDCHANGE)staticmethoddefset_per_monitor(wallpapers:dict): 为每块屏幕独立设置壁纸 wallpapers: { monitor_index: image_path } 需要 Windows 8 支持 try:importpythoncom pythoncom.CoInitialize()fromwin32com.clientimportDispatch desktopDispatch(Shell.Application)wallpaper_objdesktop.GetType().InvokeMember(DesktopWallpaper,0x200,None,desktop,None)formonitor_idinwallpapers:ifmonitor_idwallpaper_obj.GetType().InvokeMember(GetMonitorDevicePathCount,0x200,None,wallpaper_obj,None):monitor_pathwallpaper_obj.GetType().InvokeMember(GetMonitorDevicePathAt,0x200,None,wallpaper_obj,[monitor_id])image_pathwallpapers[monitor_id]ifos.path.exists(image_path):wallpaper_obj.GetType().InvokeMember(SetWallpaper,0x200,None,wallpaper_obj,[monitor_path,image_path])exceptImportError:print(多屏独立设置需要 pywin32: pip install pywin32)exceptExceptionase:print(f多屏设置失败:{e}回退到单屏模式)first_wallpaperlist(wallpapers.values())[0]WallpaperSetter.set_single(first_wallpaper)staticmethoddefset_random(wallpaper_list,per_monitorFalse):随机选择壁纸设置ifnotwallpaper_list:returnifper_monitor:wallpapers{0:random.choice(wallpaper_list)}WallpaperSetter.set_per_monitor(wallpapers)else:WallpaperSetter.set_single(random.choice(wallpaper_list))五、模块三定时调度器索引器和设置器就绪后调度器负责把它们串起来。设计调度规则时考虑了一个场景工作时间希望壁纸简洁、不分散注意力休息时间可以切换到动态视频壁纸或更炫的视觉效果。所以规则按时间段划分了四个区间每个区间可以独立配置筛选条件。_load_rules方法返回的字典就是规则配置。每个时段可以指定最低分辨率min_width防止低清壁纸被选中可以指定文件类型file_type工作时间只选静态图晚间允许视频壁纸还可以指定长宽比aspect_ratio适配不同比例的屏幕。调度器使用schedule库做定时触发默认每30分钟检查一次当前时段并执行对应的壁纸切换。这个间隔可以按需调整——太频繁会产生不必要的磁盘IO太稀疏调度精度不够。30分钟是一个折中值。importtimeimportschedulefromdatetimeimportdatetimeclassWallpaperScheduler:def__init__(self,indexer,setter):self.indexerindexer self.settersetter self.rulesself._load_rules()def_load_rules(self):加载调度规则可按需自定义return{morning:{min_width:1920,aspect_ratio:None,file_type:image,},afternoon:{min_width:2560,aspect_ratio:None,file_type:image,},evening:{min_width:1920,aspect_ratio:None,file_type:None,# 图片或视频均可},night:{min_width:0,aspect_ratio:None,file_type:image,},}def_get_current_period(self):hourdatetime.now().hourif6hour12:returnmorningelif12hour18:returnafternoonelif18hour24:returneveningelse:returnnightdefexecute_rule(self):periodself._get_current_period()rule_filterself.rules[period]wallpapersself.indexer.query(**rule_filter)ifwallpapers:paths[w[path]forwinwallpapers]self.setter.set_random(paths)print(f[{datetime.now().strftime(%H:%M)}] 已切换到{period}时段壁纸候选{len(paths)}张)else:print(f[{datetime.now().strftime(%H:%M)}]{period}时段无匹配壁纸)defstart(self,interval_minutes30):print(f壁纸调度器已启动每{interval_minutes}分钟切换一次)self.execute_rule()# 立即执行一次schedule.every(interval_minutes).minutes.do(self.execute_rule)whileTrue:schedule.run_pending()time.sleep(10)六、模块四配置备份与恢复壁纸自动化跑起来之后索引文件和调度规则就是你积累的成果。换了电脑或者重装系统这些数据全丢会很心疼。备份模块把索引文件和配置目录打包成带时间戳的 ZIP 压缩包。恢复时直接解压覆盖到原目录索引器下次扫描时自动识别已有文件新下载的壁纸会增量补充进来。之所以用 ZIP 而不是直接复制文件夹是因为小鸟壁纸的缓存目录可能有几百 MB 甚至几 GB 的图片文件——这些不需要备份只要重新从小鸟壁纸下载就行。我们只需要备份索引元数据几 KB和配置信息ZIP 压缩后通常不到 1MB。importosimportzipfilefromdatetimeimportdatetimeclassConfigBackup:def__init__(self,cache_dir,backup_dir./wallpaper_backups):self.cache_dircache_dir self.backup_dirbackup_dir os.makedirs(backup_dir,exist_okTrue)defexport_config(self):导出壁纸索引 配置文件到压缩包timestampdatetime.now().strftime(%Y%m%d_%H%M%S)backup_fileos.path.join(self.backup_dir,fwallpaper_backup_{timestamp}.zip)withzipfile.ZipFile(backup_file,w,zipfile.ZIP_DEFLATED)aszf:index_filewallpaper_index.jsonifos.path.exists(index_file):zf.write(index_file)config_diros.path.join(os.path.dirname(self.cache_dir),Config)ifos.path.exists(config_dir):forroot,dirs,filesinos.walk(config_dir):forfinfiles:fullos.path.join(root,f)arcos.path.relpath(full,os.path.dirname(config_dir))zf.write(full,arc)print(f配置已导出到:{backup_file})returnbackup_filedefimport_config(self,backup_file):从压缩包恢复配置withzipfile.ZipFile(backup_file,r)aszf:zf.extractall(os.path.dirname(self.cache_dir))print(f配置已从{backup_file}恢复)七、主程序入口四个模块全部就绪后用一个main函数把它们串起来。启动流程分四步检查缓存目录是否存在不存在说明小鸟壁纸还没装或者还没下载过壁纸、扫描索引、备份当前配置、启动调度循环。如果缓存目录不存在脚本会给出明确的提示而不是直接报错退出。这是一个对用户的友好处理——很多工具脚本的报错信息太技术化普通用户看不懂。importosimportsysdefmain():CACHE_DIRos.path.expandvars(r%LOCALAPPDATA%\BirdWallpaper\Cache)ifnotos.path.exists(CACHE_DIR):print(f缓存目录不存在:{CACHE_DIR})print(请先安装并运行小鸟壁纸下载至少一张壁纸后再启动本脚本)print(下载地址birdwallpaper.ijinshan.com)sys.exit(1)indexerWallpaperIndexer(CACHE_DIR)setterWallpaperSetter()schedulerWallpaperScheduler(indexer,setter)backupConfigBackup(CACHE_DIR)print(正在扫描壁纸缓存目录...)indexer.scan()print(f共发现{len(indexer.index)}张壁纸)backup.export_config()scheduler.start(interval_minutes30)if__name____main__:main()八、扩展方向以上是一套基础框架代码量不大但覆盖了壁纸管理的核心流程。以下是一些可以自行扩展的方向接入天气API。获取当前城市的天气数据晴/阴/雨/雪根据天气匹配不同氛围的壁纸。比如雨天自动切换到暗色调壁纸晴天切换到明亮色调。需要注册一个免费的天气API如和风天气在调度器中增加一个天气查询步骤即可。GPU负载感知。通过nvidia-smi或pyadl库获取GPU实时负载当检测到GPU占用超过阈值比如80%时自动将动态视频壁纸切换为静态图片释放渲染资源。这在打游戏时需要——视频壁纸的持续解码和渲染会抢占GPU资源。跨设备同步。把wallpaper_index.json和备份 ZIP 存到 OneDrive 或坚果云的同步目录下。多台电脑共享同一份索引每台机器只需要单独维护自己的小鸟壁纸缓存目录即可。GUI管理面板。用 PyQt5 或 Tkinter 给这套脚本包一个可视化管理界面实时预览当前壁纸、手动切换、编辑调度规则、查看索引统计。适合不想手动改代码和配置文件的使用场景。九、常见问题Q运行脚本后壁纸没变化检查缓存目录路径是否正确。小鸟壁纸的缓存目录可以在软件设置中查看。如果路径不对修改主程序中的CACHE_DIR变量。另外确认一下缓存目录里确实有壁纸文件——如果小鸟壁纸刚安装还没有使用过缓存目录可能是空的。Q多屏设置不生效set_per_monitor方法依赖 Windows 8 以上系统且需要安装pywin32pip install pywin32。不满足这两个条件时脚本会自动回退到单屏统一设置模式。Q小鸟壁纸本身有自动换壁纸功能为什么还要写脚本自带的时间切换功能只能在小鸟壁纸设定的分类范围内轮换不支持按场景制定规则。脚本的价值在于可以通过外部条件驱动——比如根据时间段切换不同的分辨率要求、根据GPU状态自动暂停动态壁纸、接入天气API做氛围匹配。这些都不是自带功能能做到的。Q脚本会影响小鸟壁纸正常使用吗不会。脚本只读取缓存目录中的文件不修改小鸟壁纸本身的任何配置或数据。两者完全独立运行。小鸟壁纸下载地址birdwallpaper.ijinshan.com