像我这种喜欢动物,但不是 那么 喜欢清理那种……新陈代谢的产物的人,桌面宠物就真的是一大福音了
当然,我可不是一位称职的“铲屎官”(???)
所以我最近就做出了一个功能还算齐全的桌面宠物
功能如下:
1.在桌面走来走去,或者打个盹;
2.左键单击它可以打开功能页;
3.有天气预报;
4.有语言微聊(得登录图灵账号,但私信我免费拿账号密码);
5.一些有趣的天气提示。
好了,解析源码↓
import tkinter
import os
import random
from platform import system
import easygui
import requests
from bs4 import BeautifulSoup
import tkinter
from prettytable import PrettyTable
这里是导入一些库↑
def weather(self):
url = f'http://wthrcdn.etouch.cn/weather_mini?citykey=101281601'
res = requests.get(url)
res.encoding = 'utf-8'
res_json = res.json()
# 2、数据格式化
data = res_json['data']
city = f"城市:{data['city']}\n"
# 字符串格式化的一种方式 f"{}" 通过字典传递值
today = data['forecast'][0]
date = f"日期:{today['date']}\n" # \n 换行
now = f"实时温度:{data['wendu']}度\n"
temperature = f"波动范围:{today['high']} {today['low']}\n"
fengxiang = f"风向:{today['fengxiang']}\n"
type = f"天气:{today['type']}\n"
tips = f"提醒:{data['ganmao']}\n"
result = city + date + now + temperature + fengxiang + type + tips
return result
这些就是关于天气小贴士的东西↑
def getHTMLText(self,url,timeout = 30):
try:
r = requests.get(url, timeout = 30) #用requests抓取网页信息
r.raise_for_status() #可以让程序产生异常时停止程序
r.encoding = r.apparent_encoding
return r.text
except:
return '产生异常'
def get_data(self,html):
final_list = []
soup = BeautifulSoup(html,'html.parser') #用BeautifulSoup库解析网页
body = soup.body
data = body.find('div',{'id':'7d'})
ul = data.find('ul')
lis = ul.find_all('li')
for day in lis:
temp_list = []
date = day.find('h1').string #找到日期
temp_list.append(date)
info = day.find_all('p') #找到所有的p标签
temp_list.append(info[0].string)
if info[1].find('span') is None: #找到p标签中的第二个值'span'标签——最高温度
temperature_highest = ' ' #用一个判断是否有最高温度
else:
temperature_highest = info[1].find('span').string
temperature_highest = temperature_highest.replace('℃',' ')
if info[1].find('i') is None: #找到p标签中的第二个值'i'标签——最高温度
temperature_lowest = ' ' #用一个判断是否有最低温度
else:
temperature_lowest = info[1].find('i').string
temperature_lowest = temperature_lowest.replace('℃',' ')
temp_list.append(temperature_highest) #将最高气温添加到temp_list中
temp_list.append(temperature_lowest) #将最低气温添加到temp_list中
wind_scale = info[2].find('i').string #找到p标签的第三个值'i'标签——风级,添加到temp_list中
temp_list.append(wind_scale)
final_list.append(temp_list) #将temp_list列表添加到final_list列表中
return final_list
def print_data(self,final_list,num):
a="{:^10}\t{:^8}\t{:^8}\t{:^8}\t{:^8}".format('日期','天气','最高温度','最低温度','风级')
for i in range(num):
final = final_list[i]
a=a+"\n"+"{:^10}\t{:^8}\t{:^8}\t{:^8}\t{:^8}".format(final[0],final[1],final[2],final[3],final[4])
print(a)
#用main()主函数将模块连接
def main(self):
url = 'http://www.weather.com.cn/weather/101281601.shtml'
html = pet.getHTMLText(url)
final_list = pet.get_data(html)
pet.print_data(final_list,7)
这些就是爬虫抓包↑(这是我这的天气抓包,main函数中url地址后面16进制的数字改一改即可)
def __init__(self):
self.root = tkinter.Tk() # create window
self.delay = 200 # delay in ms
self.pixels_from_right = 200 # change to move the pet's starting position
self.pixels_from_bottom = 200 # change to move the pet's starting position
self.move_speed = 6 # change how fast the pet moves in pixels
# initialize frame arrays
self.animation = dict(
idle = [tkinter.PhotoImage(file=os.path.abspath('gifs/idle.gif'), format = 'gif -index %i' % i) for i in range(5)],
idle_to_sleep = [tkinter.PhotoImage(file=os.path.abspath('gifs/idle-to-sleep.gif'), format = 'gif -index %i' % i) for i in range(8)],
sleep = [tkinter.PhotoImage(file=os.path.abspath('gifs/sleep.gif'), format = 'gif -index %i' % i) for i in range(3)]*3,
sleep_to_idle = [tkinter.PhotoImage(file=os.path.abspath('gifs/sleep-to-idle.gif'), format = 'gif -index %i' % i) for i in range(8)],
walk_left = [tkinter.PhotoImage(file=os.path.abspath('gifs/walk-left.gif'), format = 'gif -index %i' % i) for i in range(8)],
walk_right = [tkinter.PhotoImage(file=os.path.abspath('gifs/walk-right.gif'),format = 'gif -index %i' % i) for i in range(8)]
)
# window configuration
self.root.overrideredirect(True) # remove UI
if system() == 'Windows':
self.root.wm_attributes('-transparent','black')
else: # platform is Mac/Linux
# https://stackoverflow.com/questions/19080499/transparent-background-in-a-tkinter-window
self.root.wm_attributes('-transparent', True) # do this for mac, but the bg stays black
self.root.config(bg='systemTransparent')
self.root.attributes('-topmost', True) # put window on top
self.root.bind("<Button-1>", self.onLeftClick)
self.root.bind("<Button-2>", self.onRightClick)
self.root.bind("<Button-3>", self.onRightClick)
self.root.bind("<Key>", self.onKeyPress)
self.label = tkinter.Label(self.root,bd=0,bg='black') # borderless window
if system() != 'Windows':
self.label.config(bg='systemTransparent')
self.label.pack()
screen_width = self.root.winfo_screenwidth() # width of the entire screen
screen_height = self.root.winfo_screenheight() # height of the entire screen
self.min_width = 10 # do not let the pet move beyond this point
self.max_width = screen_width-110 # do not let the pet move beyond this point
# change starting properties of the window
self.curr_width = screen_width-self.pixels_from_right
self.curr_height = screen_height-self.pixels_from_bottom
self.root.geometry('%dx%d+%d+%d' % (100, 100, self.curr_width, self.curr_height))
def update(self, i, curr_animation):
# print("Curently: %s" % curr_animation)
self.root.attributes('-topmost', True) # put window on top
animation_arr = self.animation[curr_animation]
frame = animation_arr[i]
self.label.configure(image=frame)
# move the pet if needed
if curr_animation in ('walk_left', 'walk_right'):
self.move_window(curr_animation)
i += 1
if i == len(animation_arr):
# reached end of this animation, decide on the next animation
next_animation = self.getNextAnimation(curr_animation)
self.root.after(self.delay, self.update, 0, next_animation)
else:
self.root.after(self.delay, self.update, i, curr_animation)
这些就是建一个透明tkinter窗口,把gif塞进去↑
def onLeftClick(self, event):
print("detected left click")
a=easygui.choicebox(msg=pet.weather(),title="",choices=["天气预报","语音微聊"])
if a =="天气预报":
pet.main()
elif a=="语音微聊":
newchat="你好"
chat="(聊天记录已清空)"
API_KEY=""#账号要注册
API_SECRET=""
person="我"
while True:
if not len(chat) >= 100:
if newchat:
url=('http://i.itpk.cn/api.php?question='+newchat+"&api_key="+API_KEY+"&api_secret="+API_SECRET)
file=requests.get(url)#获取网页代码文件
data=file.text#把代码转换成文字
chat=chat+"\n"+person+":"+newchat+"\n"+"小睿:"+data#说话
else:
pet.run()
newchat=easygui.textbox(chat,"和小睿的聊天")
else:
chat=""
这里就是主控制台,连接一下天气、机器人之类的东西↑
def onRightClick(self, event):
self.quit()
quit()
def onKeyPress(self, event):
if event.char in ('q', 'Q'):
self.quit()
def move_window(self, curr_animation):
if curr_animation == 'walk_left':
if self.curr_width > self.min_width:
self.curr_width -= self.move_speed
elif curr_animation == 'walk_right':
if self.curr_width < self.max_width:
self.curr_width += self.move_speed
self.root.geometry('%dx%d+%d+%d' % (100, 100, self.curr_width, self.curr_height))
def getNextAnimation(self, curr_animation):
if curr_animation == 'idle':
return random.choice(['idle', 'idle_to_sleep', 'walk_left', 'walk_right'])
elif curr_animation == 'idle_to_sleep':
return 'sleep'
elif curr_animation == 'sleep':
return random.choice(['sleep', 'sleep_to_idle'])
elif curr_animation == 'sleep_to_idle':
return 'idle'
elif curr_animation == 'walk_left':
return random.choice(['idle', 'walk_left', 'walk_right'])
elif curr_animation == 'walk_right':
return random.choice(['idle', 'walk_left', 'walk_right'])
def run(self):
self.root.after(self.delay, self.update, 0, 'idle') # start on idle
self.root.mainloop()
def quit(self):
self.root.destroy()
这些就是触发事件了(左右键单击)↑
if __name__ == '__main__':
print('Initializing your desktop pet...')
print('To quit, right click on the pet')
pet = Pet()
pet.run()
这些就很简单了,主函数召唤class pet↑
源码如下:
import tkinter
import os
import random
from platform import system
import easygui
import requests
from bs4 import BeautifulSoup
import tkinter
from prettytable import PrettyTable
class Pet:
def weather(self):
url = f'http://wthrcdn.etouch.cn/weather_mini?citykey=101281601'
res = requests.get(url)
res.encoding = 'utf-8'
res_json = res.json()
# 2、数据格式化
data = res_json['data']
city = f"城市:{data['city']}\n"
# 字符串格式化的一种方式 f"{}" 通过字典传递值
today = data['forecast'][0]
date = f"日期:{today['date']}\n" # \n 换行
now = f"实时温度:{data['wendu']}度\n"
temperature = f"波动范围:{today['high']} {today['low']}\n"
fengxiang = f"风向:{today['fengxiang']}\n"
type = f"天气:{today['type']}\n"
tips = f"提醒:{data['ganmao']}\n"
result = city + date + now + temperature + fengxiang + type + tips
return result
def getHTMLText(self,url,timeout = 30):
try:
r = requests.get(url, timeout = 30) #用requests抓取网页信息
r.raise_for_status() #可以让程序产生异常时停止程序
r.encoding = r.apparent_encoding
return r.text
except:
return '产生异常'
def get_data(self,html):
final_list = []
soup = BeautifulSoup(html,'html.parser') #用BeautifulSoup库解析网页
body = soup.body
data = body.find('div',{'id':'7d'})
ul = data.find('ul')
lis = ul.find_all('li')
for day in lis:
temp_list = []
date = day.find('h1').string #找到日期
temp_list.append(date)
info = day.find_all('p') #找到所有的p标签
temp_list.append(info[0].string)
if info[1].find('span') is None: #找到p标签中的第二个值'span'标签——最高温度
temperature_highest = ' ' #用一个判断是否有最高温度
else:
temperature_highest = info[1].find('span').string
temperature_highest = temperature_highest.replace('℃',' ')
if info[1].find('i') is None: #找到p标签中的第二个值'i'标签——最高温度
temperature_lowest = ' ' #用一个判断是否有最低温度
else:
temperature_lowest = info[1].find('i').string
temperature_lowest = temperature_lowest.replace('℃',' ')
temp_list.append(temperature_highest) #将最高气温添加到temp_list中
temp_list.append(temperature_lowest) #将最低气温添加到temp_list中
wind_scale = info[2].find('i').string #找到p标签的第三个值'i'标签——风级,添加到temp_list中
temp_list.append(wind_scale)
final_list.append(temp_list) #将temp_list列表添加到final_list列表中
return final_list
def print_data(self,final_list,num):
a="{:^10}\t{:^8}\t{:^8}\t{:^8}\t{:^8}".format('日期','天气','最高温度','最低温度','风级')
for i in range(num):
final = final_list[i]
a=a+"\n"+"{:^10}\t{:^8}\t{:^8}\t{:^8}\t{:^8}".format(final[0],final[1],final[2],final[3],final[4])
print(a)
#用main()主函数将模块连接
def main(self):
url = 'http://www.weather.com.cn/weather/101281601.shtml'
html = pet.getHTMLText(url)
final_list = pet.get_data(html)
pet.print_data(final_list,7)
def __init__(self):
self.root = tkinter.Tk() # create window
self.delay = 200 # delay in ms
self.pixels_from_right = 200 # change to move the pet's starting position
self.pixels_from_bottom = 200 # change to move the pet's starting position
self.move_speed = 6 # change how fast the pet moves in pixels
# initialize frame arrays
self.animation = dict(
idle = [tkinter.PhotoImage(file=os.path.abspath('gifs/idle.gif'), format = 'gif -index %i' % i) for i in range(5)],
idle_to_sleep = [tkinter.PhotoImage(file=os.path.abspath('gifs/idle-to-sleep.gif'), format = 'gif -index %i' % i) for i in range(8)],
sleep = [tkinter.PhotoImage(file=os.path.abspath('gifs/sleep.gif'), format = 'gif -index %i' % i) for i in range(3)]*3,
sleep_to_idle = [tkinter.PhotoImage(file=os.path.abspath('gifs/sleep-to-idle.gif'), format = 'gif -index %i' % i) for i in range(8)],
walk_left = [tkinter.PhotoImage(file=os.path.abspath('gifs/walk-left.gif'), format = 'gif -index %i' % i) for i in range(8)],
walk_right = [tkinter.PhotoImage(file=os.path.abspath('gifs/walk-right.gif'),format = 'gif -index %i' % i) for i in range(8)]
)
# window configuration
self.root.overrideredirect(True) # remove UI
if system() == 'Windows':
self.root.wm_attributes('-transparent','black')
else: # platform is Mac/Linux
# https://stackoverflow.com/questions/19080499/transparent-background-in-a-tkinter-window
self.root.wm_attributes('-transparent', True) # do this for mac, but the bg stays black
self.root.config(bg='systemTransparent')
self.root.attributes('-topmost', True) # put window on top
self.root.bind("<Button-1>", self.onLeftClick)
self.root.bind("<Button-2>", self.onRightClick)
self.root.bind("<Button-3>", self.onRightClick)
self.root.bind("<Key>", self.onKeyPress)
self.label = tkinter.Label(self.root,bd=0,bg='black') # borderless window
if system() != 'Windows':
self.label.config(bg='systemTransparent')
self.label.pack()
screen_width = self.root.winfo_screenwidth() # width of the entire screen
screen_height = self.root.winfo_screenheight() # height of the entire screen
self.min_width = 10 # do not let the pet move beyond this point
self.max_width = screen_width-110 # do not let the pet move beyond this point
# change starting properties of the window
self.curr_width = screen_width-self.pixels_from_right
self.curr_height = screen_height-self.pixels_from_bottom
self.root.geometry('%dx%d+%d+%d' % (100, 100, self.curr_width, self.curr_height))
def update(self, i, curr_animation):
# print("Curently: %s" % curr_animation)
self.root.attributes('-topmost', True) # put window on top
animation_arr = self.animation[curr_animation]
frame = animation_arr[i]
self.label.configure(image=frame)
# move the pet if needed
if curr_animation in ('walk_left', 'walk_right'):
self.move_window(curr_animation)
i += 1
if i == len(animation_arr):
# reached end of this animation, decide on the next animation
next_animation = self.getNextAnimation(curr_animation)
self.root.after(self.delay, self.update, 0, next_animation)
else:
self.root.after(self.delay, self.update, i, curr_animation)
def onLeftClick(self, event):
print("detected left click")
a=easygui.choicebox(msg=pet.weather(),title="",choices=["天气预报","语音微聊"])
if a =="天气预报":
pet.main()
elif a=="语音微聊":
newchat="你好"
chat="(聊天记录已清空)"
API_KEY=""#记得登录,否则报错
API_SECRET=""
while True:
if newchat:
url=('http://i.itpk.cn/api.php?question='+newchat+"&api_key="+API_KEY+"&api_secret="+API_SECRET)
file=requests.get(url)#获取网页代码文件
data=file.text#把代码转换成文字
chat=chat+"\n"+person+":"+newchat+"\n"+"机器人:"+data#说话
else:
onLeftClick(event)
newchat=easygui.textbox(chat,"和智能机器人的聊天")
def onRightClick(self, event):
self.quit()
quit()
def onKeyPress(self, event):
if event.char in ('q', 'Q'):
self.quit()
def move_window(self, curr_animation):
if curr_animation == 'walk_left':
if self.curr_width > self.min_width:
self.curr_width -= self.move_speed
elif curr_animation == 'walk_right':
if self.curr_width < self.max_width:
self.curr_width += self.move_speed
self.root.geometry('%dx%d+%d+%d' % (100, 100, self.curr_width, self.curr_height))
def getNextAnimation(self, curr_animation):
if curr_animation == 'idle':
return random.choice(['idle', 'idle_to_sleep', 'walk_left', 'walk_right'])
elif curr_animation == 'idle_to_sleep':
return 'sleep'
elif curr_animation == 'sleep':
return random.choice(['sleep', 'sleep_to_idle'])
elif curr_animation == 'sleep_to_idle':
return 'idle'
elif curr_animation == 'walk_left':
return random.choice(['idle', 'walk_left', 'walk_right'])
elif curr_animation == 'walk_right':
return random.choice(['idle', 'walk_left', 'walk_right'])
def run(self):
self.root.after(self.delay, self.update, 0, 'idle') # start on idle
self.root.mainloop()
def quit(self):
self.root.destroy()
if __name__ == '__main__':
print('Initializing your desktop pet...')
print('To quit, right click on the pet')
pet = Pet()
pet.run()
拿(留)走(下)不(评)谢(论)
记得关注鸭