1. 为什么需要自动下载壁纸的Python脚本
每天手动更换壁纸对很多人来说是个麻烦事。我曾在三个月内坚持每天手动更换壁纸,但很快就发现这个过程既耗时又容易忘记。更糟的是,找到高质量、适合自己屏幕分辨率的壁纸本身就是个挑战。
自动下载壁纸的脚本可以解决这些问题:
- 定时自动获取最新壁纸
- 根据屏幕分辨率筛选合适尺寸
- 自动分类保存到指定文件夹
- 可设置自动更换频率
我最初尝试用Windows任务计划程序配合批处理脚本来实现,但很快就遇到了格式兼容性和错误处理的问题。Python凭借其丰富的库支持和跨平台特性,成为了更理想的解决方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具选型
2.1 Python环境配置
建议使用Python 3.7+版本,我实测3.8.5最为稳定。安装时务必勾选"Add Python to PATH"选项,否则后续运行脚本会遇到路径问题。
bash复制# 验证安装是否成功
python --version
pip --version
2.2 必备库安装
我们将使用以下几个关键库:
requests- 处理HTTP请求BeautifulSoup4- 解析HTMLPillow- 图像处理schedule- 定时任务
bash复制pip install requests beautifulsoup4 pillow schedule
注意:如果遇到SSL证书问题,可以尝试安装certifi包:
pip install certifi
2.3 壁纸源选择
经过测试多个壁纸网站,我推荐以下三个稳定可靠的源:
- Wallhaven - 高质量4K壁纸,API友好
- Unsplash - 免费高清摄影作品
- Bing每日壁纸 - 每日更新,内容丰富
每个源都有其特点:
- Wallhaven适合游戏/动漫爱好者
- Unsplash适合自然/城市景观
- Bing每日壁纸适合喜欢多样化内容的用户
3. 核心脚本编写
3.1 基础下载功能实现
我们先从Wallhaven开始,构建基础下载功能:
python复制import os
import requests
from bs4 import BeautifulSoup
import time
def download_wallhaven_wallpapers(keyword='nature', pages=1, resolution='1920x1080'):
base_url = 'https://wallhaven.cc/search'
save_dir = os.path.join(os.path.expanduser('~'), 'Pictures', 'Wallpapers')
if not os.path.exists(save_dir):
os.makedirs(save_dir)
for page in range(1, pages+1):
params = {
'q': keyword,
'page': page,
'resolutions': resolution
}
try:
response = requests.get(base_url, params=params)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
thumbnails = soup.find_all('img', class_='lazyload')
for thumb in thumbnails:
img_url = thumb['data-src'].replace('small', 'full').replace('th.wallhaven.cc', 'w.wallhaven.cc')
img_id = img_url.split('/')[-1].split('.')[0]
final_url = f'https://w.wallhaven.cc/full/{img_id[:2]}/wallhaven-{img_id}.jpg'
try:
img_data = requests.get(final_url, timeout=10)
if img_data.status_code == 200:
with open(os.path.join(save_dir, f'wallhaven-{img_id}.jpg'), 'wb') as f:
f.write(img_data.content)
print(f'Downloaded: {final_url}')
time.sleep(1) # 礼貌延迟
except Exception as e:
print(f'Error downloading {final_url}: {str(e)}')
except Exception as e:
print(f'Error fetching page {page}: {str(e)}')
if __name__ == '__main__':
download_wallhaven_wallpapers(keyword='landscape', pages=2, resolution='1920x1080')
3.2 多源支持扩展
为了增加脚本的灵活性,我们可以添加对多个壁纸源的支持:
python复制def download_unsplash_wallpapers(keyword='nature', count=5):
access_key = '你的Unsplash访问密钥' # 需要注册开发者账号获取
url = f'https://api.unsplash.com/photos/random?query={keyword}&count={count}&client_id={access_key}'
response = requests.get(url)
if response.status_code == 200:
photos = response.json()
for photo in photos:
img_url = photo['urls']['full']
# 下载逻辑类似上面
# ...
def download_bing_daily():
url = 'https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1'
response = requests.get(url)
if response.status_code == 200:
data = response.json()
img_url = 'https://www.bing.com' + data['images'][0]['url']
# 下载逻辑
# ...
3.3 图片处理与验证
下载的图片需要进行基本验证和处理:
python复制from PIL import Image
def validate_image(file_path):
try:
with Image.open(file_path) as img:
# 检查基本图像属性
if img.format not in ['JPEG', 'PNG']:
return False
if img.mode not in ['RGB', 'RGBA']:
return False
return True
except Exception:
return False
def resize_image(file_path, target_size=(1920, 1080)):
try:
with Image.open(file_path) as img:
if img.size != target_size:
img = img.resize(target_size, Image.LANCZOS)
img.save(file_path)
print(f'Resized: {file_path}')
except Exception as e:
print(f'Error resizing {file_path}: {str(e)}')
4. 高级功能实现
4.1 自动更换壁纸
根据操作系统不同,自动更换壁纸的实现方式也不同:
python复制import platform
import ctypes
import subprocess
def set_wallpaper(file_path):
system = platform.system()
if system == 'Windows':
ctypes.windll.user32.SystemParametersInfoW(20, 0, file_path, 3)
elif system == 'Darwin': # macOS
script = f"""
tell application "System Events"
tell every desktop
set picture to "{file_path}"
end tell
end tell
"""
subprocess.run(['osascript', '-e', script])
elif system == 'Linux':
# 不同Linux发行版可能有不同方法
try:
subprocess.run(['gsettings', 'set', 'org.gnome.desktop.background',
'picture-uri', f"file://{file_path}"])
except:
try:
subprocess.run(['feh', '--bg-scale', file_path])
except:
print("Linux wallpaper setting failed - may need to install feh")
4.2 定时任务集成
使用schedule库实现定时下载和更换:
python复制import schedule
import time
def job():
print("Running wallpaper update...")
# 调用下载函数
# 调用设置壁纸函数
print("Wallpaper updated at", time.strftime("%Y-%m-%d %H:%M:%S"))
# 每天上午8点更新
schedule.every().day.at("08:00").do(job)
while True:
schedule.run_pending()
time.sleep(60) # 每分钟检查一次
4.3 配置文件管理
使用JSON配置文件增加灵活性:
json复制{
"sources": ["wallhaven", "unsplash", "bing"],
"keywords": ["nature", "city", "abstract"],
"resolution": "1920x1080",
"download_limit": 5,
"schedule": "08:00",
"save_path": "~/Pictures/Wallpapers"
}
对应的配置读取代码:
python复制import json
import os
def load_config():
config_path = os.path.join(os.path.dirname(__file__), 'wallpaper_config.json')
default_config = {
"sources": ["wallhaven"],
"keywords": ["nature"],
"resolution": "1920x1080",
"download_limit": 3,
"schedule": "08:00",
"save_path": "~/Pictures/Wallpapers"
}
try:
with open(config_path, 'r') as f:
config = json.load(f)
# 合并默认配置和用户配置
return {**default_config, **config}
except (FileNotFoundError, json.JSONDecodeError):
# 如果配置文件不存在或格式错误,创建默认配置
with open(config_path, 'w') as f:
json.dump(default_config, f, indent=4)
return default_config
5. 错误处理与优化
5.1 常见错误处理
在实际运行中,我遇到过以下几种常见错误:
-
SSL证书错误:
python复制import ssl ssl._create_default_https_context = ssl._create_unverified_context或者更安全的做法:
python复制session = requests.Session() session.verify = '/path/to/certificate.pem' -
连接超时:
python复制try: response = requests.get(url, timeout=10) except requests.exceptions.Timeout: print("请求超时,正在重试...") time.sleep(5) # 重试逻辑 -
图片损坏:
python复制def is_image_corrupted(file_path): try: with Image.open(file_path) as img: img.verify() return False except: return True
5.2 性能优化技巧
-
并发下载:
使用多线程提高下载速度:python复制from concurrent.futures import ThreadPoolExecutor def download_images(url_list): with ThreadPoolExecutor(max_workers=5) as executor: executor.map(download_single_image, url_list) -
缓存机制:
避免重复下载已存在的图片:python复制def get_existing_images(save_dir): return {f.split('.')[0] for f in os.listdir(save_dir) if f.endswith(('.jpg', '.png'))} -
智能选择:
根据时间、季节自动选择关键词:python复制from datetime import datetime def get_seasonal_keywords(): month = datetime.now().month if month in [12, 1, 2]: return ['winter', 'snow', 'christmas'] elif month in [3, 4, 5]: return ['spring', 'flowers', 'garden'] # 其他季节...
5.3 日志记录
添加详细的日志记录有助于调试:
python复制import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('wallpaper_downloader.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# 使用示例
try:
logger.info("Starting wallpaper download...")
# 下载逻辑
logger.info("Download completed successfully")
except Exception as e:
logger.error(f"Download failed: {str(e)}", exc_info=True)
6. 完整脚本整合
将所有功能整合成一个完整的、可配置的脚本:
python复制#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import requests
import time
import json
import logging
from bs4 import BeautifulSoup
from PIL import Image
import platform
import ctypes
import subprocess
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
import schedule
# 初始化日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(os.path.join(os.path.dirname(__file__), 'wallpaper_downloader.log')),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
class WallpaperDownloader:
def __init__(self):
self.config = self.load_config()
self.save_dir = os.path.expanduser(self.config['save_path'])
os.makedirs(self.save_dir, exist_ok=True)
def load_config(self):
config_path = os.path.join(os.path.dirname(__file__), 'wallpaper_config.json')
default_config = {
"sources": ["wallhaven"],
"keywords": ["nature"],
"resolution": "1920x1080",
"download_limit": 3,
"schedule": "08:00",
"save_path": "~/Pictures/Wallpapers",
"auto_set_wallpaper": True,
"shuffle_wallpapers": True
}
try:
with open(config_path, 'r') as f:
user_config = json.load(f)
return {**default_config, **user_config}
except (FileNotFoundError, json.JSONDecodeError):
with open(config_path, 'w') as f:
json.dump(default_config, f, indent=4)
return default_config
def download_all(self):
"""从所有配置的源下载壁纸"""
existing = self.get_existing_images()
for source in self.config['sources']:
if source == 'wallhaven':
self.download_wallhaven()
elif source == 'unsplash':
self.download_unsplash()
elif source == 'bing':
self.download_bing()
if self.config['auto_set_wallpaper']:
self.set_random_wallpaper()
def download_wallhaven(self):
"""从Wallhaven下载壁纸"""
base_url = 'https://wallhaven.cc/search'
for keyword in self.config['keywords']:
params = {
'q': keyword,
'page': 1,
'resolutions': self.config['resolution']
}
try:
response = requests.get(base_url, params=params, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
thumbnails = soup.find_all('img', class_='lazyload')[:self.config['download_limit']]
with ThreadPoolExecutor(max_workers=3) as executor:
executor.map(self.download_wallhaven_image, thumbnails)
except Exception as e:
logger.error(f"Wallhaven下载失败: {str(e)}")
def download_wallhaven_image(self, thumb):
"""下载单个Wallhaven图片"""
try:
img_url = thumb['data-src'].replace('small', 'full').replace('th.wallhaven.cc', 'w.wallhaven.cc')
img_id = img_url.split('/')[-1].split('.')[0]
final_url = f'https://w.wallhaven.cc/full/{img_id[:2]}/wallhaven-{img_id}.jpg'
save_path = os.path.join(self.save_dir, f'wallhaven-{img_id}.jpg')
if os.path.exists(save_path):
logger.info(f"图片已存在: {save_path}")
return
img_data = requests.get(final_url, timeout=15)
if img_data.status_code == 200:
with open(save_path, 'wb') as f:
f.write(img_data.content)
if self.validate_image(save_path):
logger.info(f"下载成功: {final_url}")
self.resize_image(save_path)
else:
os.remove(save_path)
logger.warning(f"图片验证失败,已删除: {final_url}")
time.sleep(1) # 礼貌延迟
except Exception as e:
logger.error(f"下载失败 {final_url}: {str(e)}")
# 其他下载方法类似...
def set_random_wallpaper(self):
"""随机设置一张已下载的壁纸"""
images = [f for f in os.listdir(self.save_dir) if f.endswith(('.jpg', '.png'))]
if images:
selected = os.path.join(self.save_dir, random.choice(images))
self.set_wallpaper(selected)
def set_wallpaper(self, file_path):
"""根据系统设置壁纸"""
system = platform.system()
try:
if system == 'Windows':
ctypes.windll.user32.SystemParametersInfoW(20, 0, file_path, 3)
elif system == 'Darwin':
script = f'tell application "System Events" to tell every desktop to set picture to "{file_path}"'
subprocess.run(['osascript', '-e', script])
elif system == 'Linux':
try:
subprocess.run(['gsettings', 'set', 'org.gnome.desktop.background',
'picture-uri', f"file://{file_path}"])
except:
try:
subprocess.run(['feh', '--bg-scale', file_path])
except:
logger.warning("Linux壁纸设置失败 - 可能需要安装feh")
logger.info(f"壁纸已设置为: {file_path}")
except Exception as e:
logger.error(f"设置壁纸失败: {str(e)}")
# 其他辅助方法...
def run_scheduled(self):
"""运行定时任务"""
schedule.every().day.at(self.config['schedule']).do(self.download_all)
logger.info(f"壁纸下载器已启动,计划每天 {self.config['schedule']} 更新")
while True:
schedule.run_pending()
time.sleep(60)
if __name__ == '__main__':
downloader = WallpaperDownloader()
downloader.download_all()
# 如果要作为守护进程运行,取消下面注释
# downloader.run_scheduled()
7. 部署与使用指南
7.1 首次运行准备
- 安装Python和依赖库(如前面所述)
- 创建配置文件
wallpaper_config.json - 根据需求修改配置参数
7.2 运行方式
手动运行:
bash复制python wallpaper_downloader.py
作为系统服务运行(Linux示例):
-
创建服务文件
/etc/systemd/system/wallpaper-downloader.service:code复制[Unit] Description=Auto Wallpaper Downloader After=network.target [Service] User=yourusername ExecStart=/usr/bin/python3 /path/to/wallpaper_downloader.py Restart=always [Install] WantedBy=multi-user.target -
启用并启动服务:
bash复制sudo systemctl enable wallpaper-downloader sudo systemctl start wallpaper-downloader
7.3 高级配置建议
-
关键词优化:
- 使用具体关键词获取更精准结果(如"mountain sunset"而非"nature")
- 定期更新关键词列表保持壁纸新鲜感
-
分辨率设置:
- 使用
xrandr命令(Linux)或系统设置查看实际分辨率 - 设置比屏幕分辨率稍大的尺寸以适应多显示器
- 使用
-
存储管理:
- 定期清理旧壁纸(可在脚本中添加自动清理功能)
- 考虑使用符号链接将壁纸文件夹指向云存储实现多设备同步
8. 实际使用中的经验分享
在长达半年的实际使用中,我总结了以下几点宝贵经验:
-
礼貌爬取:
- 为每个请求添加
User-Agent头 - 遵守网站的
robots.txt规则 - 在请求之间添加1-2秒延迟
- 为每个请求添加
-
异常处理:
- 网络波动是常态,重要操作都要有重试机制
- 对下载的图片进行验证后再使用
- 记录失败日志便于后续分析
-
性能平衡:
- 并发数不宜过高(3-5个线程为宜)
- 定时任务间隔至少6小时
- 限制单次下载数量(5-10张)
-
内容过滤:
- 添加黑名单关键词过滤不想要的内容
- 根据图片特征(如主色调)进行筛选
- 可集成NSFW检测库避免不适当内容
-
跨平台考虑:
- 路径处理使用
os.path而非硬编码 - 系统命令调用前检查可用性
- 提供配置选项适应不同环境
- 路径处理使用
这个脚本经过多次迭代已经相当稳定,现在我的电脑每天都能自动换上高质量的新壁纸,完全不需要手动干预。最让我满意的是可以根据季节自动切换主题 - 冬天是雪景,春天是花朵,让我的工作环境始终与自然同步。
