Python获取Bing图片做壁纸

这篇东西是之前发在微信公众号上的文章,现在整理一下发出来。

前言

用过Bing搜索的都知道,它首页每天都会更新一张图片,点击这里可以访问。

先说说结果吧,写了一个有GUI界面的小工具,可以查看和保存壁纸,有兴趣的可以在公众号回复“bing”下载玩玩。也可以点击我的GitHub下载Main.exe试试。

必应壁纸小工具

需要注意的一些问题:

  • 工具需要联网才能打开
  • 暂时不支持更改保存的文件夹
  • 设为壁纸之后注销或重启之后就无效了(用保存的图片手动设置壁纸的话就没问题。我在win10用的时候是这样,其他系统不知道,可能是用的pywin32这个库的问题。)

好了,不想看分析和代码的看到这里就好了。

准备工作(python 3.x环境)

  • 获取网页信息的requests,urllib库
  • 设置壁纸的pywin32,PIL库
  • 编写GUI的pyqt5库

分析网页

和以前一样,第一步就是打开网页开发者工具,发现在代码里是找不到图片的网址的,这时候就要看networks了:
必应networks
我们可以在XHR里发现下面这个请求:

1
https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1510118759864&pid=hp

请求的结果格式化之后是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"images": [
{
"startdate": "20171107",
"fullstartdate": "201711071600",
"enddate": "20171108",
"url": "/az/hprichbg/rb/PointArenaLH_ZH-CN12332642727_1920x1080.jpg",
"urlbase": "/az/hprichbg/rb/PointArenaLH_ZH-CN12332642727",
"copyright": "波因特阿里纳灯塔,美国加利福尼亚州 (© plainpicture/Westend61/Spotcatch)",
"copyrightlink": "/search?q=Point+Arena+Ligh&form=hpcapt&mkt=zh-cn",
"quiz": "/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20171107_PointArenaLH%22&FORM=HPQUIZ",
"wp": true,
"hsh": "ea5b137418244ac63db363f7276c95bb",
"drk": 1,
"top": 1,
"bot": 1,
"hs": [ ]
}
],
"tooltips": {
"loading": "正在加载...",
"previous": "上一个图像",
"next": "下一个图像",
"walle": "此图片不能下载用作壁纸。",
"walls": "下载今日美图。仅限用作桌面壁纸。"
}
}

没错,“url”加上域名就是图片的地址了,“enddate”的值就是当天日期,可以作为保存的文件名。另外,请求的链接里有个“idx”参数,0是今天的图片,1是昨天的,以此类推。知道这个,接下来的事就很简单了。

编写代码

首先先写一个获取url的函数,因为要让程序可以获取到前些天的图片,参数的默认值为0,也就是今天的图片:

1
2
3
def get_url(day=0):
url = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=" + str(day) + "&n=1&nc=1509675905008&pid=hp&video=1"
return url

然后,写一个保存图片的函数,用“enddate”作为文件名:

1
2
3
4
5
6
7
8
def get_img(url, path="D://wallpaper/"):
isExists = os.path.exists(path)
if not isExists:
os.makedirs(path)
html = requests.get(url)
content = html.json()
src = "https://www.bing.com" + content['images'][0]['url']
urlretrieve(src, path + content['images'][0]['enddate'] + '.jpg')

设置壁纸的方法来自网上,原理是通过pywin32访问注册表修改壁纸,至于为什么注销或重启之后会无效我也不是太懂……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def set_wallpaper_from_bmp(bmp_path):  
reg_key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, win32con.KEY_SET_VALUE)
win32api.RegSetValueEx(reg_key, "WallpaperStyle", 0, win32con.REG_SZ, "2")
win32api.RegSetValueEx(reg_key, "TileWallpaper", 0, win32con.REG_SZ, "0")
win32gui.SystemParametersInfo(win32con.SPI_SETDESKWALLPAPER, bmp_path, win32con.SPIF_SENDWININICHANGE)
def set_wallpaper(img_path):
isExists = os.path.exists(img_path)
if isExists:
img_dir = os.path.dirname(img_path)
bmpImage = Image.open(img_path)
new_bmp_path = os.path.join(img_dir, 'wallpaper.bmp')
bmpImage.save(new_bmp_path, "BMP")
set_wallpaper_from_bmp(new_bmp_path)
return True
else:
return False

最后是用pyqt5写GUI界面,我也是第一次使用,所以不是太好看,代码也有点乱,大家凑和看看吧哈哈……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
class Bing(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(400, 200, 500, 325)
self.setFixedSize(self.width(), self.height());
self.setWindowTitle('Bing Wallpaper')
self.setWindowIcon(QIcon('Bing.ico'))
self.add_position_layout()
# 添加布局部件
def add_position_layout(self):
bg_label = QLabel(self)
bg_label.resize(self.width(), self.height())
bg_label.setScaledContents(True)
def set_background_image(img):
photo = QtGui.QPixmap()
photo.loadFromData(img)
bg_label.setPixmap(photo)
# img = time.strftime("%Y%m%d") + '.jpg'
img, self.filename = sp.show_img(sp.get_url())
set_background_image(img)
# label_1 = QLabel("<p style='font-size:25px;text-align:center;'><b>Path:</b></p>", self)
label_1 = QLabel(" 保存目录: ", self)
label_1.setStyleSheet("QLabel{background:rgb(255,255,255,100)}")
path_edit = QLineEdit()
path_edit.setText('D:/wallpaper')
path_edit.setToolTip('抱歉!暂时不支持更换路径!')
path_edit.setReadOnly(True)
# def btn_change():
# filename = QFileDialog.getExistingDirectory(self, directory=path_edit.text())
# path_edit.setText(filename)
self.day = 0
def btn_previous(day):
img,self.filename = sp.show_img(sp.get_url(self.day + 1))
set_background_image(img)
self.day += 1
print(self.day)
def btn_next(day):
if self.day > 0:
img,self.filename = sp.show_img(sp.get_url(self.day - 1))
set_background_image(img)
self.day -= 1
print(self.day)
else:
QMessageBox.information(self, " ", "明天的壁纸还未更新哦!")
def btn_save(day):
img = sp.get_img(sp.get_url(self.day))
def btn_set_wallpaper(day):
flag = sw.set_wallpaper('D:/wallpaper/' + self.filename)
if not flag:
QMessageBox.information(self, " ", "请先保存此壁纸!")
# button_1 = QPushButton("更改路径", self)
# button_1.clicked.connect(btn_change)
button_2 = QPushButton("前一张", self)
button_2.setToolTip('查看前一天的必应图片!')
button_2.clicked.connect(btn_previous)
button_3 = QPushButton("设为壁纸", self)
button_3.setToolTip('设置壁纸要先保存哦!')
button_3.clicked.connect(btn_set_wallpaper)
button_4 = QPushButton("保存", self)
button_4.setToolTip('保存在该目录下!')
button_4.clicked.connect(btn_save)
button_5 = QPushButton("后一张", self)
button_5.setToolTip('查看后一天的必应图片!')
button_5.clicked.connect(btn_next)
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(label_1, 2, 0)
grid.addWidget(path_edit, 2, 1, 1, 2)
# grid.addWidget(button_1, 2, 3)
grid.addWidget(button_2, 3, 0)
grid.addWidget(button_3, 3, 1, 1, 2)
grid.addWidget(button_4, 2, 3)
grid.addWidget(button_5, 3, 3)
grid.setAlignment(Qt.AlignTop)
layout_widget = QWidget()
layout_widget.setLayout(grid)
self.setCentralWidget(layout_widget)
if __name__ == '__main__':
sp.get_img(sp.get_url())
app = QApplication(sys.argv)
bing = Bing()
bing.show()
sys.exit(app.exec_())

简单来说,程序会先通过网络获取图片显示,所以没有联网的话就用不了,要设置壁纸的话需要先点击保存会把图片保存下来,运行结果是这样的:

必应壁纸程序效果

结语

另外,完成之后,我用pyinstaller打包成了exe文件,打包完之后我发现左上角的那个小图标没了,不过不影响使用……大家在公众号回复“bing”就有下载地址了,或者点击我的GitHub,有源码也有exe程序,注意一下前面说的几个问题就好。