iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python制作的天气预报小工具(gui界面)
  • 939
分享到

python制作的天气预报小工具(gui界面)

python天气预报pythongui 2022-06-02 22:06:19 939人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录一.准备工作二.预览1.启动2.添加城市3.展示多个城市天气三.设计流程1.获取城市天气信息过程四.源代码1.Weather_Tool-v1.0.py2.Weather_Spider.py五.总结一.准备工作

目录
  • 一.准备工作
  • 二.预览
    • 1.启动
    • 2.添加城市
    • 3.展示多个城市天气
  • 三.设计流程
    • 1.获取城市天气信息过程
  • 四.源代码
    • 1.Weather_Tool-v1.0.py
    • 2.Weather_Spider.py
  • 五.总结

    一.准备工作

    不需要准备。

    二.预览

    1.启动

    启动以后自动定位所在城市,展示定位城市的天气。

    2.添加城市

    3.展示多个城市天气

    添加天气之后能够显示多个城市天气信息。

    三.设计流程

    1.获取城市天气信息过程

    用此流程图展示定位城市信息到获取城市天气信息过程。

    四.源代码

    1.Weather_Tool-v1.0.py

    
    from tkinter import *
    from tkinter import ttk
    from PIL import Image,ImageTk
    from tkinter import messagebox
    from Weather_Spider import Weather_Get
    from threading import Thread
    import datetime
    import time
    
    '''
    5-1
    1.打开首页定位当前位置获取天气    (ip定位+jieba分词+城市号+城市天气) **5.11实现**
    2.用户手动选择,查看当前所选城市天气 (Toplevel+Combobox) **已实现**
    
    5-14
    1.加入notepad,显示多个城市天气    (notebook Frame)    **已实现**
    2.频繁刷新检测(线程计时10秒)   **已实现**
    3.用户选择主题    (Menu.add_radiobutton())    **已实现**
    4.一个窗口多个Combobox,怎样处理选择事件	**已实现**
    
    5-15
    1.右击notebook frame标题出现“关闭”菜单	**已砍掉**
    2.用户添加了城市后,label出现在了最后的Frame中	**未实现**
    
    '''
    imgs=['./img/loading.png']
    class App:
        def __init__(self):
            self.w=Tk()
            self.w.title('天气预报小工具-v1.0')
            width=600
            height=282
            left=(self.w.winfo_screenwidth()-width)/2
            top=(self.w.winfo_screenheight()-height)/2
            self.w.geometry('%dx%d+%d+%d'%(width,height,left,top))
            self.w.iconbitmap('biticon.ico')
            self.w.resizable(False,False)
            self.cerate_widgets()
            self.first_launch()
            self.set_widgets()
            self.place_widgets()
            self.thread_it(self.show_local_weather)
            self.w.mainloop()
    
        def cerate_widgets(self):
            self.note=ttk.Notebook()
            self.f1=Frame()
            self.tree=ttk.Treeview(self.f1)
            self.l1_var=StringVar()
            self.l1=ttk.Label(self.f1,textvariable=self.l1_var)
            self.m=Menu(self.w)
            self.w['menu']=self.m
            self.s1=Menu(self.m,tearoff=False)
            self.s2=Menu(self.m,tearoff=False)
            self.s3=Menu(self.m,tearoff=False)
    
        def set_widgets(self):
            self.location=[]
            style = ttk.Style(self.w)
            style.theme_use("default")
            columns=('rq','tq','flfx','zdqw','zgqw')
            self.tree.config(show='headings',columns=columns)
            self.tree.column(columns[0],anchor=CENTER,minwidth=95,width=110)
            self.tree.column(columns[1],anchor=CENTER,minwidth=60,width=70)
            self.tree.column(columns[2],anchor=CENTER,minwidth=90,width=100)
            self.tree.column(columns[3],anchor=CENTER,minwidth=90,width=100)
            self.tree.column(columns[4],anchor=CENTER,minwidth=90,width=100)
            self.tree.heading('rq', text='日期')
            self.tree.heading('tq', text='天气')
            self.tree.heading('flfx', text='风向风力')
            self.tree.heading('zdqw', text='最低气温')
            self.tree.heading('zgqw', text='最高气温')
            self.m.add_cascade(label='开始',menu=self.s1)
            self.s1.add_command(label='aaa',command='')
            self.s1.add_separator()
            self.s1.add_command(label='退出',command=self.quit_window)
            self.m.add_cascade(label='操作',menu=self.s2)
            self.s2.add_command(label='刷新',command=lambda:self.thread_it(self.refresh_weather))
            self.s2.add_command(label='添加城市',command=lambda:self.thread_it(self.select_city),state='disable')
            s2_sub = Menu(self.s2, tearoff=0)
            self.s2.add_separator()
            self.s2.add_cascade(label='更换主题',menu=s2_sub)
            self.m.add_cascade(label='关于',menu=self.s3)
            self.s3.add_command(label='关于作者',command=lambda :messagebox.showinfo('关于作者','作者很神秘,什么都没留下'))
            self.tree.tag_configure('evenColor',background='lightblue')
            self.w.protocol('WM_DELETE_WINDOW',self.quit_window)
            themes=[ 'default','clam', 'alt', 'classic']
            self.themevar=StringVar()
            for i,t in enumerate(themes):
                s2_sub.add_radiobutton(label=t,variable=self.themevar,command=lambda:self.thread_it(self.change_theme),value=t)
            self.themevar.set('default')
    
        def place_widgets(self):
            self.note.place(x=0,y=0,width=600,height=282)
            self.tree.place(x=0,y=0,width=600,height=150)
            self.l1.place(x=0,y=150,height=85,width=600)
    
        def first_launch(self):
            '''
            第一次启动,展示加载图片提示信息
            :return:
            '''
            self.start_time=time.time()
            paned = PanedWindow(self.w)
            self.img = imgs
            img = Image.open(self.img[0])
            paned.image = ImageTk.PhotoImage(img)
            self.load_img = Label(self.w, image=paned.image)
            self.load_lab = Label(self.w, text='Loading...')
            self.load_img.pack()
            self.load_lab.pack()
    
        def show_local_weather(self):
            '''
            展示定位天气信息
            :return:
            '''
            self.l1_var.set('正在刷新天气......')
            items = self.tree.get_children()
            for item in items:
                self.tree.delete(item)
            try:
                city,item=Weather_Get().get_local_weather()
                self.load_img.destroy()
                self.load_lab.destroy()
                self.s2.entryconfig('添加城市', state='nORMal')
                self.note.add(self.f1,text=city)
                i=0
                for data in item['recent']:
                    self.tree.insert('', i, values=(
                    data.get('日期'), data.get('天气'), data.get('风力风向'), data.get('最低气温'), data.get('最高气温')))
                    i+=1
                self.l1_var.set(f'今天:{self.show_date()}\n当前所在地区:{city}\n当前气温:{item["now"]}\n感冒指数:{item["ganmao"]}')
            except TypeError:
                messagebox.showerror('错误','天气信息加载失败!')
                self.l1_var.set('天气信息加载失败!')
                self.s2.entryconfig('添加城市', state='normal')
    
        def refresh_weather(self):
            """
            刷新天气后,10秒内不能点击刷新
            :return:
            """
            self.s2.entryconfig('刷新', state='disable')
            self.show_local_weather()
            self.thread_it(self.wait_time)
    
        def wait_time(self):
            '''
            线程计时10s,十秒后刷新按钮可点击
            :return:
            '''
            time.sleep(10)
            self.s2.entryconfig('刷新', state='normal')
    
    
    
        def show_date(self):
            """
            展示日期信息,便于天气展示
            :return:
            """
            date = str(datetime.date.today())
            year,month,day=date.split('-')
            week_day_dict = {
                0: '星期一',
                1: '星期二',
                2: '星期三',
                3: '星期四',
                4: '星期五',
                5: '星期六',
                6: '星期日 ',
            }
            now=datetime.datetime.now()
            date_index = now.weekday()
            return f'{year}年{month}月{day}日 {week_day_dict[date_index]}'
    
        def select_city(self):
            '''
            Toplevel让用户选择城市,后台获取城市号
            :return:
            '''
            self.t=Toplevel()
            self.t.resizable(0,0)
            width=300
            height=140
            left=(self.t.winfo_screenwidth()-width)/2
            top=(self.t.winfo_screenheight()-height)/2
            self.t.geometry('%dx%d+%d+%d'%(width,height,left,top))
            self.t.title('选择城市')
            self.tl1=ttk.Label(self.t,text='请选择城市:')
            self.tl1.pack()
            provinces=Weather_Get().get_provinces()
            self.tc1=ttk.Combobox(self.t,justify='center',state='readonly',value=provinces)
            self.tc2=ttk.Combobox(self.t,justify='center',state='readonly')
            self.tc1.pack()
            self.tc1.bind('<<ComboboxSelected>>',self.show_tc2_value)
            self.tc2.bind('<<ComboboxSelected>>',self.show_tc3_value)
            self.tc2.pack()
            self.tc3=ttk.Combobox(self.t,justify='center',state='readonly')
            self.tc3.pack()
            self.tb1=ttk.Button(self.t,text='选择',command=lambda :self.thread_it(self.ack_city))
            self.tb1.pack(pady=10)
    #----待完善
        def ack_city(self):
            '''
            Toplevel中选择了城市,选择使用notebook中建立Frame展示所选城市信息
            :return:
            '''
            cityno=self.get_city_no()
            weather_item=Weather_Get().get_weather(cityno)
            location=self.province_name+self.city_name+self.region
            if location in self.location:
                messagebox.showwarning('警告','此城市已添加,请勿重复添加!')
            else:
                self.location.append(location)
                self.f2= Frame(takefocus=True)
                self.note.add(self.f2, text=location)
                self.tree2 = ttk.Treeview(self.f2)
                columns = ('rq', 'tq', 'flfx', 'zdqw', 'zgqw')
                self.tree2.config(show='headings', columns=columns)
                self.tree2.column(columns[0], anchor=CENTER, minwidth=95, width=110)
                self.tree2.column(columns[1], anchor=CENTER, minwidth=60, width=70)
                self.tree2.column(columns[2], anchor=CENTER, minwidth=90, width=100)
                self.tree2.column(columns[3], anchor=CENTER, minwidth=90, width=100)
                self.tree2.column(columns[4], anchor=CENTER, minwidth=90, width=100)
                self.tree2.heading('rq', text='日期')
                self.tree2.heading('tq', text='天气')
                self.tree2.heading('flfx', text='风向风力')
                self.tree2.heading('zdqw', text='最低气温')
                self.tree2.heading('zgqw', text='最高气温')
                self.tree2.place(x=0,y=0,width=600,height=150)
                # label_='label'+str(self.click_no)
                # label_var='label'+str(self.click_no)+'_var'
                self.fl1_var=StringVar()
                self.fl1=ttk.Label(self.f2,textvariable=self.fl1_var)
                self.fl1.place(x=0,y=150,height=85,width=600)
                items = self.tree2.get_children()
                for item in items:
                    self.tree2.delete(item)
                try:
                    item = weather_item
                    city=location
                    i = 0
                    for data in item['recent']:
                        self.tree2.insert('', i, values=(
                            data.get('日期'), data.get('天气'), data.get('风力风向'), data.get('最低气温'), data.get('最高气温')))
                        i += 1
                    self.fl1_var.set(f'今天:{self.show_date()}\n当前所在地区:{city}\n当前气温:{item["now"]}\n感冒指数:{item["ganmao"]}')
                except TypeError:
                    messagebox.showerror('错误','天气信息加载失败!')
                    self.fl1_var.set(f'{city}天气信息加载失败!')
            self.t.destroy()
    
        def change_tab(self,*args):
            pass
    
        def show_tc2_value(self,event):
            '''
            展示"市"级信息
            :param event:
            :return:
            '''
            self.tc2.config(value=[])
            self.tc3.config(value=[])
            self.province_name=self.tc1.get()
            cities=Weather_Get().get_cities(self.province_name)
            self.tc2.config(value=cities)
    
        def show_tc3_value(self,event):
            '''
            展示"区/县"级信息
            :param event:
            :return:
            '''
            self.city_name=self.tc2.get()
            regions=Weather_Get().get_regions(self.province_name,self.city_name)
            self.tc3.config(value=regions)
    
        def get_city_no(self):
            """
            根据省、市、区、县 获取城市号
            :return: 城市号
            """
            self.region=self.tc3.get()
            city_no=Weather_Get().get_city_id_by_add(self.province_name,self.city_name,self.region)
            return city_no
    
        def change_theme(self,):
            '''
            更换主题
            :return:
            '''
            theme=self.themevar.get()
            style = ttk.Style(self.w)
            style.theme_use(theme)
    
    
        def quit_window(self):
            ret=messagebox.askyesno('退出','是否要退出?')
            if ret:
                self.w.destroy()
    
        def thread_it(self,func,*args):
            '''
            防止线程冲突
            :param func:
            :param args:
            :return:
            '''
            t=Thread(target=func,args=args)
            t.setDaemon(True)
            t.start()
    
    if __name__ == '__main__':
        a=App()
    

    2.Weather_Spider.py

    
    #coding:utf-8
    import requests
    import JSON
    from lxml import etree
    import jieba
    
    class Weather_Get():
    
        def __init__(self):
            self.base_ip_url='Http://ip-api.com/json'
            self.location_url='https://ip.tool.chinaz.com/'
            #获取中国国内城市--number接口
            self.city_number_url='http://static.2ktq.com/sktq/common/city_China.json'
            #天气查询接口
            self.base_weather_url='http://wthrcdn.etouch.cn/weather_mini?citykey={}'
            self.headers={
                'user-agent': 'Mozilla/5.0 (windows NT 10.0; WOW64) AppleWEBKit/537.36 (Khtml, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
            }
            self.item=self.get_city_item()
    
    
        def request(self,url,headers):
            """
            请求url,可自定义请求头
            :param url: 请求的url
            :param headers: 自定义的请求头
            :return: 网页文本数据
            """
            s=requests.session()
            s.keep_alive=False
            try:
                r=s.get(url,headers=headers)
                r.encoding='utf-8'
                if r.status_code==200:
                    r.encoding = r.apparent_encoding
                    return r.text
                else:
                    return None
            except requests.exceptions.ConnectionError:
                return None
    
        def get_city(self):
            """
            通过ip定位到当前城市
            :return:所在省市位置信息
            """
            my_headers={
                'Connection': 'keep-alive',
                'Host': 'ip.tool.chinaz.com',
                'sec-ch-ua': '"Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"',
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
                'Upgrade-Insecure-Requests': '1'
            }
            res = etree.HTML(self.request(self.location_url,headers=my_headers))
            location = res.xpath('//div[@class="WhoIpWrap jspu"]//span[@class="Whwtdhalf w30-0 lh24 tl ml80"]/em/text()')
            #结巴分词好费时间啊
            jieba_cut_result = jieba.lcut(''.join(location))
            try:
                #去除首位的国家和网络类型
                del jieba_cut_result[0]
                del jieba_cut_result[-1]
                item = {}
                # 如果结果为类似 石家庄裕华 则自动加入市区
                if jieba_cut_result[0]!=jieba_cut_result[1]:
                    item['province'] = jieba_cut_result[0] + '市'
                    item['city'] = jieba_cut_result[1] + "区"
                    return item
                else:
                    # 如果结果为类似 北京北京 则自动加入市
                    item['province'] = jieba_cut_result[0] + '市'
                    item['city'] = jieba_cut_result[1] + "市"
                    return item
            except IndexError:
                return False
    
        def get_city_item(self):
            res =self.request(self.city_number_url,headers=self.headers)
            item=eval("{'cities':"+res+"}")
            return item
    
        def get_provinces(self):
            province=[p for p in self.item['cities']]
            #print(province)
            return province
    
        def get_cities(self,province):
            cities_=self.item['cities'][province]
            cities=[city for city in cities_.keys()]
            return cities
    
        def get_regions(self,province,city):
            regions_=self.item['cities'][province][city]
            regions=[region for region in regions_.keys()]
            #print(province,city,regions)
            return regions
    
        def get_city_id_by_add(self,province,city,region=''):
            if region=='':
                city_no=self.item['cities'][province][city][city].replace('CN','')
    
            else:
                city_no=self.item['cities'][province][city][region].replace('CN','')
            return city_no
    
    
        def get_cityid(self,province,city):
            """
            通过省、市在字典中查找对应的城市号
            :param province: 省
            :param city: 市
            :return: 城市号
            """
            if province in self.item['cities'].keys():
                try:
                    #河北省唐山市唐山市(通常的省市)
                    number=self.item['cities'][province].get(city).get(city).replace('CN','')
                    return number
                except AttributeError:
                    number=self.item['cities'][province].get(province).get(city).replace('CN','')
                    return number
            else:
                print('未检索到关于{}{}的信息!'.format(province,city))
    
        def get_weather(self,number):
            weather_data = json.loads(self.request(self.base_weather_url.format(number),self.headers))
            # pprint.pprint(weather_data)
            data=weather_data['data']
            item={}
            yesterday={}
            item_list=[]
            yesterday['日期']=data['yesterday']['date']+'(昨天)'
            item['now']=data['wendu']+'℃'
            item['ganmao']=data['ganmao']
            yesterday['天气']=data['yesterday']['type']
            yesterday['风力风向']=data['yesterday']['fx']+data['yesterday']['fl'].replace('<![CDATA[','').replace(']]>','')
            yesterday['最低气温']=data['yesterday']['low'].replace('低温 ','')
            yesterday['最高气温']=data['yesterday']['high'].replace('高温 ','')
            item_list.append(yesterday)
            count=0
            for weateher in data['forecast']:
                item2={}
                if count==0:
                    date=weateher['date']+'(今天)'
                elif count==1:
                    date=weateher['date']+'(明天)'
                elif count==2:
                    date=weateher['date']+'(后天)'
                else:
                    date=weateher['date']+f'({count-1}天后)'
                item2['日期']=date
                item2['天气'] = weateher['type']
                item2['风力风向']=weateher['fengxiang']+weateher['fengli'].replace('<![CDATA[','').replace(']]>','')
                item2['最低气温'] = weateher['low'].replace('低温 ', '')
                item2['最高气温'] = weateher['high'].replace('高温 ', '')
                item_list.append(item2)
                count+=1
            item['recent']=item_list
            return item
    
        def get_local_weather(self):
            item=Weather_Get().get_city()
            if item:
                p=item['province']
                c=item['city']
                number=Weather_Get().get_cityid(p,c)
                weather=Weather_Get().get_weather(number)
                return p+c,weather
            else:
                return False
    
    

    五.总结

    本次使用Tkinter写了一款天气预报小工具,基本支持全国每个省市的天气预报,支持历史天气(昨天)查看,虽然基本功能能够实现,但是仍旧存在两个小问题
    1.添加超过两个城市天气后,具体城市信息会显示在最新添加的Freame中。
    2.ip定位不准确。

    本程序还有两个特色:

    支持更换主题。
    2.程序首次启动加入了加载过渡。
    其他的彩蛋,您自己去发现吧!
    程序放在了蓝奏云。思路、代码方面有什么不足欢迎各位大佬指正、批评!

    以上就是python制作的天气预报小工具(gui界面)的详细内容,更多关于Python 天气预报工具的资料请关注编程网其它相关文章!

    --结束END--

    本文标题: python制作的天气预报小工具(gui界面)

    本文链接: https://www.lsjlt.com/news/10756.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • python制作的天气预报小工具(gui界面)
      目录一.准备工作二.预览1.启动2.添加城市3.展示多个城市天气三.设计流程1.获取城市天气信息过程四.源代码1.Weather_Tool-v1.0.py2.Weather_Spider.py五.总结一.准备工作 ...
      99+
      2022-06-02
      python 天气预报 python gui
    • python如何制作的天气预报小工具
      这篇文章主要介绍python如何制作的天气预报小工具,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一.准备工作不需要准备。二.预览1.启动启动以后自动定位所在城市,展示定位城市的天气。2.添加城市3.展示多个城市天气...
      99+
      2023-06-15
    • python 制作一个gui界面的翻译工具
      目录一.准备工作二.预览1.主界面2.翻译3.支持多种语言哦三.源代码3.1 My_Translator-v2.0.py3.2 Translator.py四.总结一.准备工作 除了Tkinter,还需要google...
      99+
      2022-06-02
      python 翻译工具 python gui
    • 如何解决Win7桌面天气预报小工具不能用的问题
        Windows 7 系统中自带有9个小工具,如 CPU 仪表盘、天气、时钟和货币等等,如图所示:   Windows 7自带桌面小工具   通过这些小工具,您可以轻松查看即时信息、访问常用工具。  天气预报小工具无法...
      99+
      2023-05-25
      桌面 天气预报 工具 问题
    • java制作带界面的聊天工具
      本文实例为大家分享了java聊天工具的具体制作代码,供大家参考,具体内容如下首先建立一个工程,导入数据库驱动工程图解释一下 entity包是 bin目录 Message包下 和 User包下 是对象相关的操作Message package ...
      99+
      2023-05-31
      java 聊天工具
    • 基于Python3制作一个带GUI界面的小说爬虫工具
      目录效果图开发完成后的界面采集过程界面采集后存储主要功能用到的第三方模块打包为 exe 命令全部源码效果图 最近帮朋友写个简单爬虫,顺便整理了下,搞成了一个带GUI界面的小说爬虫工具...
      99+
      2022-11-13
    • 如何使用Python3制作一个带GUI界面的小说爬虫工具
      这篇文章主要介绍如何使用Python3制作一个带GUI界面的小说爬虫工具,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!效果图最近帮朋友写个简单爬虫,顺便整理了下,搞成了一个带GUI界面的小说爬虫工具,用来从笔趣阁爬取...
      99+
      2023-06-29
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作