python 天气预报(v2.0)

python 天气预报(v2.0)

Jan 11, 2014
Coding
Python, Weather, WxPython

本文代码基于 python 2.x 版本

上一个版本 python 自动获取天气程序(Version1.0)实现了自动获取当前城市的天气信息,功能很简单,而且只是字符脚本。这一版本Version2.0中增强了天气预报功能,并提供了UI界面,使用起来更友好。

软件的主界面 main

主要菜单 menu_weather

工具栏 toolbar

软件功能 #

  1. 启动时,自动获取用户当前城市
  2. 选择任意自定义城市为当前城市,并查看该城市天气信息

city

  1. 显示城市当前的天气情况:天气、温度、湿度、风力、风向、高温低温
  2. 显示城市当前天气的各种天气指数:天气指数、舒适度、穿衣指数、晾晒指数等
  3. 显示后续6天的天气情况:天气、气温

实现 #

软件分为两个模块,WeatherInfo.py 和 WeatherInfoUI.py,前者负责后台的天气数据获取和处理,后者负责前段UI的设计和控制。

WeatherInfo.py 是 V1.0 版本中 appGetWeather_help.py 模块的增强。

WeatherInfoUI.py 基于 wxPython,主要用到的控件有wx.StaticText,wx.TextCtrl,wx.StaticBitmap,wx.Dialog等,使用BoxSizer和GridBagSizer布局管理器布局。

详细实现方法,后续有时间再完整补上。

代码 #

WeatherInfoUI.py 模块 #

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#author:JarvisChu
#blog:zhujiangtao.com

'''天气预报信息 UI'''

import wx,time,urllib2
import WeatherInfo
from datetime import datetime #日期计算
from datetime import timedelta

class CityDialog(wx.Dialog):
    '''选择城市对话框'''

    def __init__(self):
        wx.Dialog.__init__(self,None,-1,u'选择城市',size=(280,120))

        #GridBagSizer
        stTips = wx.StaticText(self,-1,u'请输入城市:')
        self.tcCity = wx.TextCtrl(self,-1)

        okButton = wx.Button(self, wx.ID_OK,u'确定')
        okButton.SetDefault()
        cancelButton = wx.Button(self, wx.ID_CANCEL, u'取消')

        gbs = wx.GridBagSizer(10,10)
        gbs.Add(stTips,pos=(0,0),span=wx.DefaultSpan,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)
        gbs.Add(self.tcCity,pos=(0,1),span=wx.DefaultSpan,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)
        gbs.Add(okButton,pos=(1,1),span=wx.DefaultSpan,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)
        gbs.Add(cancelButton,pos=(1,2),span=wx.DefaultSpan,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)

        self.SetSizer(gbs)

    def getCity(self):
        '''返回用户输入的城市'''

    return self.tcCity.GetValue()

class WeatherInfoFrame(wx.Frame):
    '''程序主框架'''

    def __init__(self,parent=None, id=-1,title="Frame",pos=wx.DefaultPosition,size=(800,600), style=wx.DEFAULT_FRAME_STYLE,name='frame'):
        wx.Frame.__init__(self,parent=parent,id=id,title=title,pos=pos,size=size,style=style,name=name)

        #—-外观设置—-
        self.SetBackgroundColour(wx.WHITE)
        self.EmptyWeatherData() #将城市和所有天气数据,清除为N/A

        #定位城市
        self.current_city = self.LocateCity() #当前城市
        self.UpdateWeatherInfo()#更新天气数据到系统的变量中

        #—-初始化界面—-
        self.InitUI()

    def SetWindowTitle(self, cityname):
        '''设置窗体的名字'''

        title = u'天气预报(v2.0) – ' + cityname.decode('gbk')
        self.SetTitle(title)

    def EmptyWeatherData(self):
        '''将城市和所有天气数据,清除为N/A'''

        self.current_temp = u'N/A'
        self.current_wet = u'N/A'
        self.current_wind_direction =u'N/A'
        self.current_wind_strong =u'N/A'
        self.current_real_time =u'N/A'
        self.current_weather =u'N/A'
        self.high_temp =u'N/A'
        self.low_temp =u'N/A'
        self.current_weather_img =u'N/A'
        self.weather_index =u'N/A'
        self.dress_index =u'N/A'
        self.uv_index =u'N/A'
        self.wash_car_index=u'N/A'
        self.travel_index =u'N/A'
        self.cosy_index =u'N/A'
        self.excise_index =u'N/A'
        self.shine_index =u'N/A'
        self.sick_index =u'N/A'
        self.six_day_temp = {'temp1':u'N/A','temp2':u'N/A','temp3':u'N/A','temp4':u'N/A','temp5:u'N/A','temp6':u'N/A',}
        self.six_day_weather = {'weather1':u'N/A','weather2':u'N/A','weather3':u'N/A','weather4':u'N/A','weather5':u'N/A','weather6':u'N/A',}

    def LocateCity(self):
        '''定位当前的城市'''

        try:
            city_info = urllib2.urlopen('http://pv.sohu.com/cityjson').read()
            city = city_info.split('=')[1].split(',')[2].split('"')[3] #split out the city name”'
        except:
            print u'自动定位城市出错'
            return u'N/A'
        else:
            print u"您的城市:",city.decode('gbk')
            #city = unicode(city,'gbk')
            return city

    def UpdateWeatherInfo(self):
        '''更新天气数据'''

        #self.current_city = unicode(self.LocateCity(),'gbk') #当前城市
        #self.current_city = self.LocateCity() #当前城市
        #print self.LocateCity()
        if self.current_city != u'N/A':
            self.SetWindowTitle(self.current_city)
            #查找id
            self.current_city_id = WeatherInfo.getCityCodeFromName(self.current_city)
            if self.current_city_id != 'N/A':
                #获取具体城市天气信息
                #实时数据
                dicRealTime = WeatherInfo.getCityWeather_RealTime(self.current_city_id)
                self.current_temp = dicRealTime['temp'] #温度
                self.current_wet = dicRealTime['sd'] #湿度
                self.current_wind_direction = dicRealTime['wd'] #风向
                self.current_wind_strong = dicRealTime['ws'] #风力 '2级'
                self.current_real_time = dicRealTime['time'] #时间

                #全天数据
                dicAllDay = WeatherInfo.getCityWeather_AllDay(self.current_city_id)
                self.current_weather = dicAllDay['weather'] #天气,'晴转多云'
                self.high_temp = dicAllDay['high'] #最高温
                self.low_temp = dicAllDay['low'] #最低温
                self.current_weather_img = dicAllDay['img']

                #详细的天气信息和最近6天的天气
                dicDetail = WeatherInfo.getCityWeatherDetail_SixDay(self.current_city_id)
                self.weather_index = dicDetail['index'] #天气指数 #冷
                self.dress_index = dicDetail['cy'] #穿衣指数 #建议….
                self.uv_index = dicDetail['zw'] #紫外线指数 #最弱
                self.wash_car_index= dicDetail['xc'] #洗车指数 #不宜
                self.travel_index = dicDetail['tr'] #旅游指数 #很适宜
                self.cosy_index = dicDetail['co'] #舒适度 #较舒适
                self.excise_index = dicDetail['cl'] #晨练指数 #较适宜
                self.shine_index = dicDetail['ls'] #晾晒指数 #不太适宜
                self.sick_index = dicDetail['ag'] #过敏指数 #不易发"

                self.six_day_temp = {}
                self.six_day_weather = {}
                for i in range(1,7):
                    temp = 'temp'+str(i)
                    weather = 'weather'+str(i)
                    self.six_day_temp[temp] = dicDetail[temp]
                    self.six_day_weather[weather] = dicDetail[weather]
                return True
            else:
                return False
        else:
            return False

    def InitMenu(self):
        '''初始化菜单栏'''

        #菜单ID
        self.IDM_EXIT = wx.NewId()
        self.IDM_ABOUT = wx.NewId()
        self.IDM_UPDATE = wx.NewId()
        self.IDM_TREND = wx.NewId()
        self.IDM_CITY = wx.NewId()

        #菜单图标
        self.imgExit = wx.Bitmap('img/exit.png')
        self.imgAbout = wx.Bitmap('img/about.png')
        self.imgUpdate = wx.Bitmap('img/update.png')
        self.imgTrend = wx.Bitmap('img/trend.png')
        self.imgCity = wx.Bitmap('img/city.png')

        #菜单栏
        self.menuBar = wx.MenuBar()

        #菜单: 文件
        menuFile = wx.Menu()
        miExit = wx.MenuItem(menuFile,self.IDM_EXIT,u'退出(&E)',u'退出软件')#图标菜单项
        miExit.SetBitmap(self.imgExit)
        menuFile.AppendItem(miExit)
        self.menuBar.Append(menuFile,u'文件(&F)')

        #菜单:天气
        menuWeather = wx.Menu()
        miUpdate = wx.MenuItem(menuWeather,self.IDM_UPDATE,u'更新(&U)',u'更新天气信息')
        miTrend = wx.MenuItem(menuWeather,self.IDM_TREND,u'趋势(&Q)',u'天气趋势图表')
        miCity = wx.MenuItem(menuWeather,self.IDM_CITY,u'城市(&C)',u'选择城市')
        miUpdate.SetBitmap(self.imgUpdate)
        miTrend.SetBitmap(self.imgTrend)
        miCity.SetBitmap(self.imgCity)
        menuWeather.AppendItem(miUpdate)
        menuWeather.AppendItem(miTrend)
        menuWeather.AppendItem(miCity)
        self.menuBar.Append(menuWeather,u'天气(&W)')

        #菜单:关于
        menuAbout = wx.Menu() #
        miAbout = wx.MenuItem(menuAbout,self.IDM_ABOUT,u'关于',u'天气预报(v2.0) – JarvisChu – zhujiangtao.com')
        miAbout.SetBitmap(self.imgAbout)
        menuAbout.AppendItem(miAbout)
        self.menuBar.Append(menuAbout,u'关于(&A)')

        #菜单栏附加到窗口
        self.SetMenuBar(self.menuBar)

        #—-菜单事件响应—-
        self.Bind(wx.EVT_MENU,self.OnExit,id=self.IDM_EXIT)
        self.Bind(wx.EVT_MENU,self.OnAbout,id=self.IDM_ABOUT)
        self.Bind(wx.EVT_MENU,self.OnUpdate,id=self.IDM_UPDATE)
        self.Bind(wx.EVT_MENU,self.OnTrend,id=self.IDM_TREND)
        self.Bind(wx.EVT_MENU,self.OnCity,id=self.IDM_CITY)
        pass

    def InitToolBar(self):
        '''初始化快捷工具栏'''

        self.toolBar = self.CreateToolBar()
        self.toolBar.AddSimpleTool(self.IDM_UPDATE,self.imgUpdate,u'更新(&U)',u'更新天气信息')
        self.toolBar.AddSimpleTool(self.IDM_TREND,self.imgTrend,u'趋势(&Q)',u'天气趋势图表')
        self.toolBar.AddSimpleTool(self.IDM_CITY, self.imgCity,u'城市',u'选择城市')
        self.toolBar.AddSimpleTool(self.IDM_ABOUT, self.imgAbout,u'关于',u'天气预报(v2.0) – JarvisChu – zhujiangtao.com')
        self.toolBar.AddSimpleTool(self.IDM_EXIT,self.imgExit,u'退出',u'退出软件')
        self.toolBar.Realize()

    def InitMainWindowControls(self):
        '''初始化主界面窗口的控件'''

        self.mainPanel = wx.Panel(self,-1)

        #——————————————————————-
        #上

        self.imgLocatedCity = wx.Bitmap('img/location.png')
        #当前城市
        sbCity = wx.StaticBitmap(self.mainPanel,bitmap=self.imgLocatedCity)
        #self.current_city = u'杭州'
        self.stCurCity = wx.StaticText(self.mainPanel,-1,self.current_city)
        font18 = wx.Font(18, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL)
        self.stCurCity.SetFont(font18)

        #更新时间,初始化为当前时间
        stUpdateTime = wx.StaticText(self.mainPanel,-1,u'更新时间: ')
        stUpdateTime.SetFont(wx.Font(14, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        update_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
        self.tcUpdateTime = wx.TextCtrl(self.mainPanel,-1,update_time,style=wx.TE_LEFT|wx.TE_READONLY|wx.TE_RICH2)
        self.tcUpdateTime.SetBackgroundColour(wx.Colour(250,250,250))
        self.tcUpdateTime.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        #更新按钮事件响应
        self.IDC_BTN_UPDATE = wx.NewId()
        btnUpdate =wx.BitmapButton(self.mainPanel,id=self.IDC_BTN_UPDATE,bitmap=self.imgUpdate,style=wx.BU_EXACTFIT)
        btnUpdate.Bind(wx.EVT_BUTTON,self.OnClickBtnUpdate)

        #BoxSizer布局 – 上
        bsHead = wx.BoxSizer(wx.HORIZONTAL)
        bsHead.Add(sbCity,0,flag=wx.ALL|wx.ALIGN_CENTER|wx.EXPAND,border=10)
        bsHead.Add(self.stCurCity,2,flag=wx.ALL|wx.ALIGN_CENTER,border=10)
        bsHead.Add(stUpdateTime,0,flag=wx.TOP|wx.BOTTOM|wx.LEFT|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL,border=10)
        bsHead.Add(self.tcUpdateTime,2,flag=wx.TOP|wx.BOTTOM|wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL,border=10)
        bsHead.Add(btnUpdate,0,flag=wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL,border=10)

        #——————————————————————-
        #中

        #当前温度
        self.imgTemp = wx.Bitmap('img/temperature.png')
        sbCurTemp = wx.StaticBitmap(self.mainPanel,bitmap=self.imgTemp)
        self.stCurTemp = wx.StaticText(self.mainPanel,-1,u'当前温度: '+str(self.current_temp)+u' ℃')
        self.stCurTemp.SetFont(wx.Font(14, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        #当前湿度
        self.imgWet = wx.Bitmap('img/wet.png')
        sbCurWet = wx.StaticBitmap(self.mainPanel,bitmap=self.imgWet)
        self.stCurWet = wx.StaticText(self.mainPanel,-1,u'当前湿度: '+str(self.current_wet))
        self.stCurWet.SetFont(wx.Font(14, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        #当前风向
        self.imgWindDirection = wx.Bitmap('img/wind_direction.png')
        sbCurWindDirection = wx.StaticBitmap(self.mainPanel,bitmap=self.imgWindDirection)
        self.stCurWindDirection = wx.StaticText(self.mainPanel,-1,u'当前风向:'+self.current_wind_direction)
        self.stCurWindDirection.SetFont(wx.Font(14, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        #当前风力
        self.imgWindStrong = wx.Bitmap('img/wind_strong.png')
        sbCurWindStrong = wx.StaticBitmap(self.mainPanel,bitmap=self.imgWindStrong)
        self.stCurWindStrong = wx.StaticText(self.mainPanel,-1,u'当前风力: '+self.current_wind_strong)
        self.stCurWindStrong.SetFont(wx.Font(14, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        #当前天气
        self.imgWeather = wx.Bitmap('img/weather.png')
        sbWeatherInfo = wx.StaticBitmap(self.mainPanel,bitmap=self.imgWeather)
        self.stCurWeather = wx.StaticText(self.mainPanel,-1,u'天气情况:'+self.current_weather)
        self.stCurWeather.SetFont(wx.Font(14, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        #最低最高温
        self.imgTempRange = wx.Bitmap('img/temprange.png')
        sbTempRange = wx.StaticBitmap(self.mainPanel,bitmap=self.imgTempRange)
        self.stCurTempRange = wx.StaticText(self.mainPanel,-1,u'温度范围:'+self.low_temp+u'~'+self.high_temp)
        self.stCurTempRange.SetFont(wx.Font(14, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        #GridBagSizer布局
        gbsMid = wx.GridBagSizer(10,10)
        gbsMid.Add(sbCurTemp,pos=(0,0),span=wx.DefaultSpan,flag=wx.EXPAND)
        gbsMid.Add(self.stCurTemp,pos=(0,1),span=wx.DefaultSpan,flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT,border=5)
        gbsMid.Add(sbCurWet,pos=(0,2),span=wx.DefaultSpan,flag=wx.LEFT|wx.EXPAND,border=10)
        gbsMid.Add(self.stCurWet,pos=(0,3),span=wx.DefaultSpan,flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT,border=5)

        gbsMid.Add(sbCurWindDirection,pos=(1,0),span=wx.DefaultSpan,flag=wx.EXPAND)
        gbsMid.Add(self.stCurWindDirection,pos=(1,1),span=wx.DefaultSpan,flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT,border=5)
        gbsMid.Add(sbCurWindStrong,pos=(1,2),span=wx.DefaultSpan,flag=wx.LEFT|wx.EXPAND,border=10)
        gbsMid.Add(self.stCurWindStrong,pos=(1,3),span=wx.DefaultSpan,flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT,border=5)

        gbsMid.Add(sbWeatherInfo,pos=(2,0),span=wx.DefaultSpan,flag=wx.BOTTOM|wx.EXPAND,border=10)
        gbsMid.Add(self.stCurWeather,pos=(2,1),span=wx.DefaultSpan,flag=wx.BOTTOM|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT,border=10)
        gbsMid.Add(sbTempRange,pos=(2,2),span=wx.DefaultSpan,flag=wx.BOTTOM|wx.LEFT|wx.EXPAND,border=10)
        gbsMid.Add(self.stCurTempRange,pos=(2,3),span=wx.DefaultSpan,flag=wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT,border=10)

        gbsMid.AddGrowableCol(1,1)
        gbsMid.AddGrowableCol(3,1)
        gbsMid.AddGrowableRow(0,1)
        gbsMid.AddGrowableRow(1,1)
        gbsMid.AddGrowableRow(2,1)

        #GridBagSizer – 天气指数
        #天气指数 #冷
        #穿衣指数 #建议….
        #紫外线指数 #最弱
        #洗车指数 #不宜
        #旅游指数 #很适宜
        #舒适度 #较舒适
        #晨练指数 #较适宜
        #晾晒指数 #不太适宜
        #过敏指数 #不易发"

        gbsWeatherIndex = wx.GridBagSizer(5,5)
        labelWeatherIndex = wx.StaticText(self.mainPanel,-1,u'天气指数:')
        self.stWeatherIndex = wx.StaticText(self.mainPanel,-1,self.weather_index)
        labelWeatherIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stWeatherIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelDressIndex = wx.StaticText(self.mainPanel,-1,u'穿衣指数:')
        #self.stDressIndex = wx.StaticText(self.mainPanel,-1,self.dress_index)
        self.stDressIndex = wx.TextCtrl(self.mainPanel,-1,self.dress_index,style=wx.TE_RIGHT|wx.TE_READONLY|wx.TE_RICH2)
        labelDressIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stDressIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelCosyIndex = wx.StaticText(self.mainPanel,-1,u'舒适度:')
        self.stCosyIndex = wx.StaticText(self.mainPanel,-1,self.cosy_index)
        labelCosyIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stCosyIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelExciseIndex = wx.StaticText(self.mainPanel,-1,u'晨练指数:')
        self.stExciseIndex = wx.StaticText(self.mainPanel,-1,self.excise_index)
        labelExciseIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stExciseIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelUVIndex = wx.StaticText(self.mainPanel,-1,u'紫外线指数:')
        self.stUVIndex = wx.StaticText(self.mainPanel,-1,self.uv_index)
        labelUVIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stUVIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelShineIndex = wx.StaticText(self.mainPanel,-1,u'晾晒指数:')
        self.stShineIndex = wx.StaticText(self.mainPanel,-1,self.shine_index)
        labelShineIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stShineIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelWashCarIndex = wx.StaticText(self.mainPanel,-1,u'洗车指数:')
        self.stWashCarIndex = wx.StaticText(self.mainPanel,-1,self.wash_car_index)
        labelWashCarIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stWashCarIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelTravelIndex = wx.StaticText(self.mainPanel,-1,u'旅游指数:')
        self.stTravelIndex = wx.StaticText(self.mainPanel,-1,self.travel_index)
        labelTravelIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stTravelIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        labelSickIndex = wx.StaticText(self.mainPanel,-1,u'过敏指数:')
        self.stSickIndex = wx.StaticText(self.mainPanel,-1,self.sick_index)
        labelSickIndex.SetFont(wx.Font(12, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))
        self.stSickIndex.SetFont(wx.Font(10, wx.DECORATIVE, wx.FONTWEIGHT_NORMAL, wx.NORMAL))

        flag_tmp = wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT
        gbsWeatherIndex.Add(labelWeatherIndex,pos=(0,0),span=wx.DefaultSpan,flag=flag_tmp,border=5)#天气指数 #row 0
        gbsWeatherIndex.Add(self.stWeatherIndex,pos=(0,1),span=(1,2),flag=flag_tmp,border=5)
        gbsWeatherIndex.Add(labelCosyIndex,pos=(0,3),span=wx.DefaultSpan,flag=flag_tmp,border=5) #舒适度
        gbsWeatherIndex.Add(self.stCosyIndex,pos=(0,4),span=(1,2),flag=flag_tmp,border=5)
        gbsWeatherIndex.Add(labelDressIndex,pos=(1,0),span=wx.DefaultSpan,flag=flag_tmp,border=5) #穿衣 #row 1
        gbsWeatherIndex.Add(self.stDressIndex,pos=(1,1),span=(1,5),flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=5)

        gbsWeatherIndex.Add(labelExciseIndex,pos=(2,0),span=wx.DefaultSpan,flag=flag_tmp,border=5) #晨练#row 2
        gbsWeatherIndex.Add(self.stExciseIndex,pos=(2,1),span=(1,2),flag=flag_tmp,border=5)
        gbsWeatherIndex.Add(labelShineIndex,pos=(2,3),span=wx.DefaultSpan,flag=flag_tmp,border=5) #晾晒
        gbsWeatherIndex.Add(self.stShineIndex,pos=(2,4),span=(1,2),flag=flag_tmp,border=5)
        gbsWeatherIndex.Add(labelWashCarIndex,pos=(3,0),span=wx.DefaultSpan,flag=flag_tmp,border=5) #洗车 #row 3
        gbsWeatherIndex.Add(self.stWashCarIndex,pos=(3,1),span=(1,2),flag=flag_tmp,border=5)
        gbsWeatherIndex.Add(labelTravelIndex,pos=(3,3),span=wx.DefaultSpan,flag=flag_tmp,border=5) #旅游
        gbsWeatherIndex.Add(self.stTravelIndex,pos=(3,4),span=(1,2),flag=flag_tmp,border=5)
        gbsWeatherIndex.Add(labelUVIndex,pos=(4,0),span=wx.DefaultSpan,flag=flag_tmp,border=5) #紫外线 #row 4
        gbsWeatherIndex.Add(self.stUVIndex,pos=(4,1),span=(1,2),flag=flag_tmp,border=5)
        gbsWeatherIndex.Add(labelSickIndex,pos=(4,3),span=wx.DefaultSpan,flag=flag_tmp,border=5)#过敏
        gbsWeatherIndex.Add(self.stSickIndex,pos=(4,4),span=(1,2),flag=flag_tmp,border=5)

        #gbsWeatherIndex.AddGrowableCol(0,1)
        gbsWeatherIndex.AddGrowableCol(1,1)
        gbsWeatherIndex.AddGrowableCol(3,1)

        gbsWeatherIndex.AddGrowableRow(0,1)
        gbsWeatherIndex.AddGrowableRow(1,1)
        gbsWeatherIndex.AddGrowableRow(2,1)
        gbsWeatherIndex.AddGrowableRow(3,1)
        gbsWeatherIndex.AddGrowableRow(4,1)

        #BoxSizer – 中
        vline = wx.StaticLine(self.mainPanel,style=wx.LI_VERTICAL)

        bsMid = wx.BoxSizer(wx.HORIZONTAL)
        bsMid.Add(gbsMid,1,flag=wx.ALL|wx.EXPAND,border=10)
        bsMid.Add(vline,0,flag=wx.LEFT|wx.RIGHT|wx.EXPAND,border=10)
        bsMid.Add(gbsWeatherIndex,1,flag=wx.ALL|wx.EXPAND,border=10)

        #——————————————————————-
        #下

        #GridBagSizer布局 – 下
        gbsFooter = wx.GridBagSizer()

        self.tcDaySix = []
        self.tcWeatherSix=[]
        self.tcTempSix=[]
        today = datetime.now()
        for i in range(1,7):
            dif = timedelta(days=i)
            day = today+dif
            sDay = day.strftime('%Y-%m-%d')
            weather = 'weather'+str(i)
            temp = 'temp'+str(i)
            self.tcDaySix.append(wx.StaticText(self.mainPanel,-1,sDay))
            self.tcWeatherSix.append(wx.StaticText(self.mainPanel,-1,self.six_day_weather[weather]))
            self.tcTempSix.append(wx.StaticText(self.mainPanel,-1,self.six_day_temp[temp]))

            gbsFooter.Add(self.tcDaySix[i-1],pos=(0,i-1),span=(1,1),flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER,border=10)
            gbsFooter.Add(self.tcWeatherSix[i-1],pos=(1,i-1),span=(1,1),flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER,border=10)
            gbsFooter.Add(self.tcTempSix[i-1],pos=(2,i-1),span=(1,1),flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER,border=10)
        gbsFooter.AddGrowableCol(0,1)
        gbsFooter.AddGrowableCol(1,1)
        gbsFooter.AddGrowableCol(2,1)
        gbsFooter.AddGrowableCol(3,1)
        gbsFooter.AddGrowableCol(4,1)
        gbsFooter.AddGrowableCol(5,1)

        #———————————————————————
        #BoxSizer布局 – 整体框架

        line1 = wx.StaticLine(self.mainPanel)
        line2 = wx.StaticLine(self.mainPanel)

        bsAll = wx.BoxSizer(wx.VERTICAL)
        bsAll.Add(bsHead,0,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=5)
        bsAll.Add(line1,0,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)
        bsAll.Add(bsMid,1,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)
        bsAll.Add(line2,0,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)
        bsAll.Add(gbsFooter,0,flag=wx.TOP|wx.BOTTOM|wx.EXPAND,border=10)
        self.mainPanel.SetSizer(bsAll)

    def InitUI(self):
        '''初始化UI界面,包括菜单、工具栏、窗口控件'''

        self.mainIcon = wx.Icon('img/main.ico',wx.BITMAP_TYPE_ICO)
        self.SetIcon(self.mainIcon) #设置窗口图标

        self.InitMenu()#初始化菜单栏
        self.InitToolBar() #初始化快捷工具栏
        self.statusBar = self.CreateStatusBar()#状态栏

        self.InitMainWindowControls()#初始化主界面窗口的控件

    def OnExit(self,event):
        '''退出程序'''

        self.Close(True)

    def OnAbout(self,event):
        '''关于对话框'''

        about = wx.MessageDialog(None, u'天气预报(v2.0)\n作者:JarvisChu\n博客:zhujiangtao.com',u'关于', wx.OK)
        about.ShowModal()
        about.Destroy()

    def OnTrend(self,event):
        '''趋势,菜单的点击响应'''

        print 'OnTrend'

    def OnCity(self,event):
        '''选择城市'''

        print 'OnCity'

        #cityFrame = wx.Frame(self,-1,title=u'输入城市')
        #cityFrame.Show()
        #cityFrame.Destroy()

        cityDlg = CityDialog()
        if cityDlg.ShowModal() == wx.ID_OK:
            rst = cityDlg.getCity()
            print rst
            city = WeatherInfo.getCityCodeFromName(rst.encode('gbk'))
            if city != u'N/A':
                print city
                self.current_city = rst.encode('gbk')
                self.UpdateWeatherUI()
        cityDlg.Destroy()

    def OnUpdate(self,event):
        '''更新天气,菜单的点击响应'''

        print 'Click Update menu'
        self.UpdateWeatherUI()

    def OnClickBtnUpdate(self,event):
        '''更新天气,Button按钮的点击响应'''

        print 'Click Button'
        self.UpdateWeatherUI()

    def UpdateWeatherUI(self):
        '''更新窗口上各控件的天气'''

        self.UpdateWeatherInfo()

        #城市
        self.stCurCity.SetLabel(self.current_city)

        #更新时间
        update_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
        self.tcUpdateTime.SetLabel(update_time)

        self.stCurTemp.SetLabel(u'当前温度: '+self.current_temp+u' ℃')
        self.stCurWet.SetLabel(u'当前湿度: '+self.current_wet)
        self.stCurWindDirection.SetLabel(u'当前风向: '+self.current_wind_direction)
        self.stCurWindStrong.SetLabel(u'当前风力: '+self.current_wind_strong)
        self.stCurWeather.SetLabel(u'天气情况:'+self.current_weather)
        self.stCurTempRange.SetLabel(u'温度范围:'+self.low_temp+u'~'+self.high_temp)
        #
        self.stWeatherIndex.SetLabel(self.weather_index)
        self.stCosyIndex.SetLabel(self.cosy_index)
        self.stDressIndex.SetLabel(self.dress_index)
        self.stExciseIndex.SetLabel(self.excise_index)
        self.stShineIndex.SetLabel(self.shine_index)
        self.stWashCarIndex.SetLabel(self.wash_car_index)
        self.stTravelIndex.SetLabel(self.travel_index)
        self.stSickIndex.SetLabel(self.sick_index)

        #
        today = datetime.now()
        for i in range(1,7):
            dif = timedelta(days=i)
            day = today+dif
            sDay = day.strftime('%Y-%m-%d')
            weather = 'weather'+str(i)
            temp = 'temp'+str(i)
            (self.tcDaySix[i-1]).SetLabel(sDay)
            (self.tcWeatherSix[i-1]).SetLabel(self.six_day_weather[weather])
            (self.tcTempSix[i-1]).SetLabel(self.six_day_temp[temp])

class WeatherInfoApp(wx.App):
    '''主程序类'''

    def OnInit(self):
        mainFrmId = wx.NewId()
        self.frame = WeatherInfoFrame(parent=None, id=mainFrmId, title=u'天气预报(v2.0)')
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

if __name__ == "__main__":
app = WeatherInfoApp()
app.MainLoop()

WeatherInfo.py模块 #

#! /usr/bin/env python
#coding=utf-8
#Author: JarvisChu
#Blog: zhujiangtao.com,blog.csdn.net/jarvischu

import sys,urllib2,json

cityList_main = [ #全国主要城市
#华北
{'code':"101010100", 'name':"北京"},
{'code':"101030100", 'name':"天津"},
{'code':"101090101", 'name':"石家庄"},
{'code':"101100101", 'name':"太原"},
{'code':"101080101", 'name':"呼和浩特"},
{'code':"101090201", 'name':"保定"},
{'code':"101100201", 'name':"大同"},
{'code':"101080201", 'name':"包头"},
{'code':"101090402", 'name':"承德"},
{'code':"101100401", 'name':"晋中"},
{'code':"101080501", 'name':"通辽"},
{'code':"101091101", 'name':"秦皇岛"},
#东北
{'code':"101050101", 'name':"哈尔滨"},
{'code':"101060101", 'name':"长春"},
{'code':"101070101", 'name':"沈阳"},
{'code':"101050201", 'name':"齐齐哈尔"},
{'code':"101060201", 'name':"吉林"},
{'code':"101070201", 'name':"大连"},
{'code':"101050301", 'name':"牡丹江"},
{'code':"101060301", 'name':"延吉"},
{'code':"101070301", 'name':"鞍山"},
{'code':"101050501", 'name':"绥化"},
{'code':"101060601", 'name':"白城"},
{'code':"101071401", 'name':"葫芦岛"},
#华南
{'code':"101280101", 'name':"广州"},
{'code':"101300101", 'name':"南宁"},
{'code':"101310101", 'name':"海口"},
{'code':"101320101", 'name':"香港"},
{'code':"101330101", 'name':"澳门"},
{'code':"101280601", 'name':"深圳"},
{'code':"101300501", 'name':"桂林"},
{'code':"101310201", 'name':"三亚"},
{'code':"101280701", 'name':"珠海"},
{'code':"101281701", 'name':"中山"},
{'code':"101301001", 'name':"百色"},
{'code':"101310215", 'name':"万宁"},
#西北
{'code':"101110101", 'name':"西安"},
{'code':"101160101", 'name':"兰州"},
{'code':"101150101", 'name':"西宁"},
{'code':"101170101", 'name':"银川"},
{'code':"101130101", 'name':"乌鲁木齐"},
{'code':"101110300", 'name':"延安"},
{'code':"101110901", 'name':"宝鸡"},
{'code':"101160901", 'name':"天水"},
{'code':"101170301", 'name':"吴忠"},
{'code':"101130501", 'name':"吐鲁番"},
{'code':"101160801", 'name':"酒泉"},
{'code':"101170401", 'name':"固原"},
#西南
{'code':"101040100", 'name':"重庆"},
{'code':"101270101", 'name':"成都"},
{'code':"101260101", 'name':"贵阳"},
{'code':"101290101", 'name':"昆明"},
{'code':"101140101", 'name':"拉萨"},
{'code':"101270401", 'name':"绵阳"},
{'code':"101260201", 'name':"遵义"},
{'code':"101290201", 'name':"大理"},
{'code':"101271401", 'name':"乐山"},
{'code':"101260801", 'name':"六盘水"},
{'code':"101291401", 'name':"丽江"},
#华东
{'code':"101020100", 'name':"上海"},
{'code':"101230101", 'name':"福州"},
{'code':"101220101", 'name':"合肥"},
{'code':"101240101", 'name':"南昌"},
{'code':"101120101", 'name':"济南"},
{'code':"101210301", 'name':"嘉兴"},
{'code':"101190101", 'name':"南京"},
{'code':"101210401", 'name':"宁波"},
{'code':"101210101", 'name':"杭州"},
{'code':"101190401", 'name':"苏州"},
{'code':"101120201", 'name':"青岛"},
{'code':"101230201", 'name':"厦门"},
{'code':"101340101", 'name':"台北"},
#华中
{'code':"101180101", 'name':"郑州"},
{'code':"101200101", 'name':"武汉"},
{'code':"101250101", 'name':"长沙"},
{'code':"101180201", 'name':"安阳"},
{'code':"101200201", 'name':"襄阳"},
{'code':"101250201", 'name':"湘潭"},
{'code':"101250301", 'name':"株洲"},
{'code':"101180401", 'name':"许昌"},
{'code':"101250601", 'name':"常德"},
{'code':"101251101", 'name':"张家界"},
{'code':"101200401", 'name':"孝感"},
{'code':"101201401", 'name':"荆门"}
]

def convertName(cityName):
    '''#将 “浙江省杭州市” 转换成“杭州”'''

    name = unicode(cityName, "gbk")

    if name.find(u"省") !=-1:# 包含'省'
        #print u'有省'
        name=name.split(u'省')[1]
    if name.find(u"市") != -1:#包含'市'
        #print u'有市'
        name=name.split(u'市')[0]
        return name

def getCityCodeFromName(cityName):
    '''从城市名获取城市ID'''

    cityName = convertName(cityName)
    for item in cityList_main:
        #n = unicode(item['name'],'utf-8')
        #print n,cityName
        if unicode(item['name'],'utf-8')==cityName:
            #print 'equal'
            return item['code']
    return 'N/A'

def getCityWeather_RealTime(cityID):
    '''获取实时天气,返回温度、湿度、风向、风力、时间的字典类型数据'''

    url = "http://www.weather.com.cn/data/sk/" + str(cityID) + ".html"
    try:
        req=urllib2.Request(url)
        stdout = urllib2.urlopen(url)
        weatherInfomation = stdout.read().decode('utf-8')
        print 'realtime- ',weatherInfomation
        #{"weatherinfo":{"city":"杭州","cityid":"101210101","temp":"8","WD":"东南风","WS":"1级","SD":"45%","WSE":"1","time":"15:45","isRadar":"1","Radar":"JC_RADAR_AZ9571_JB"}}

        jsonDatas = json.loads(weatherInfomation)

        city = jsonDatas["weatherinfo"]["city"] #城市
        cityid = jsonDatas["weatherinfo"]["cityid"] #城市id
        temp = jsonDatas["weatherinfo"]["temp"] #温度
        wd = jsonDatas["weatherinfo"]["WD"] #风向
        ws = jsonDatas["weatherinfo"]["WS"] #风力
        sd = jsonDatas["weatherinfo"]["SD"] #相对湿度
        wse = jsonDatas["weatherinfo"]["WSE"] #风力,不含“级”字
        tm = jsonDatas["weatherinfo"]["time"] #时间
        isRadar = jsonDatas["weatherinfo"]["isRadar"] #是否有雷达图
        Radar = jsonDatas["weatherinfo"]["isRadar"] #有雷达图
    except:
        print 'getCityWeather_RealTime Error!'
        return {}
    else:
        return {'temp':temp,'sd':sd,'wd':wd,'ws':ws,'time':tm}

#返回dict类型:
def getCityWeatherDetail_SixDay(cityID):
    url = "http://m.weather.com.cn/data/" + str(cityID) + ".html"
    try:
        print 'aaaa'
        req=urllib2.Request(url)
        stdout = urllib2.urlopen(url)
        weatherInfomation = stdout.read().decode('utf-8')

        print 'detail – ',weatherInfomation

        '''
        {"weatherinfo":{"city":"杭州","city_en":"hangzhou","date_y":"2014年1月10日","date":"","week":"星期五","fchh":"18","cityid":"101210101",\
        "temp1":"3℃~7℃","temp2":"5℃~6℃","temp3":"2℃~6℃","temp4":"1℃~6℃","temp5":"-1℃~7℃","temp6":"-2℃~7℃",\
        "tempF1":"37.4℉~44.6℉","tempF2":"41℉~42.8℉","tempF3":"35.6℉~42.8℉","tempF4":"33.8℉~42.8℉","tempF5":"30.2℉~44.6℉","tempF6":"28.4℉~44.6℉",\
        "weather1":"小雨","weather2":"小雨","weather3":"小雨转雨夹雪","weather4":"雨夹雪转阴","weather5":"多云转晴","weather6":"晴转多云",\
        "img1":"7","img2":"99","img3":"7","img4":"99","img5":"7","img6":"6","img7":"6","img8":"2","img9":"1","img10":"0","img11":"0","img12":"1",\
        "img_single":"7","img_title1":"小雨","img_title2":"小雨","img_title3":"小雨","img_title4":"小雨","img_title5":"小雨","img_title6":"雨夹雪","img_title7":"雨夹雪","img_title8":"阴","img_title9":"多云","img_title10":"晴","img_title11":"晴","img_title12":"多云",\
        "img_title_single":"小雨",\
        "wind1":"东风转东北风小于3级","wind2":"东北风小于3级","wind3":"东北风小于3级","wind4":"东北风小于3级","wind5":"东北风小于3级","wind6":"东北风小于3级",\
        "fx1":"东风","fx2":"东北风","fl1":"小于3级","fl2":"小于3级","fl3":"小于3级","fl4":"小于3级","fl5":"小于3级","fl6":"小于3级",\
        "index":"较冷","index_d":"建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。",\
        "index48":"较冷","index48_d":"建议着厚外套加毛衣等服装。年老体弱者宜着大衣、呢外套加羊毛衫。",\
        "index_uv":"最弱","index48_uv":"最弱","index_xc":"不宜","index_tr":"适宜","index_co":"较舒适",\
        "st1":"7","st2":"4","st3":"6","st4":"6","st5":"6","st6":"3","index_cl":"较不宜","index_ls":"不宜","index_ag":"极不易发"}}
        '''
        jsonDatas = json.loads(weatherInfomation)

        rst = {}

        city = jsonDatas["weatherinfo"]["city"]
        tempF1 = jsonDatas["weatherinfo"]["tempF1"]
        weather = jsonDatas["weatherinfo"]["img_title1"]
        img = jsonDatas["weatherinfo"]["img1"]
        fx = jsonDatas["weatherinfo"]["fx1"] #风向

        rst['index'] = jsonDatas["weatherinfo"]["index"] #天气指数 #冷
        rst['cy'] = jsonDatas["weatherinfo"]["index_d"] #穿衣指数 #建议….
        rst['zw'] = jsonDatas["weatherinfo"]["index_uv"] #紫外线指数 #最弱
        rst['xc'] = jsonDatas["weatherinfo"]["index_xc"] #洗车指数 #不宜
        rst['tr'] = jsonDatas["weatherinfo"]["index_tr"] #旅游指数 #很适宜
        rst['co'] = jsonDatas["weatherinfo"]["index_co"] #舒适度 #较舒适
        rst['cl'] = jsonDatas["weatherinfo"]["index_cl"] #晨练指数 #较适宜
        rst['ls'] = jsonDatas["weatherinfo"]["index_ls"] #晾晒指数 #不太适宜
        rst['ag'] = jsonDatas["weatherinfo"]["index_ag"] #过敏指数 #不易发"

        rst['temp1'] = jsonDatas["weatherinfo"]["temp1"] #接下来第 1 天的温度
        rst['temp2'] = jsonDatas["weatherinfo"]["temp2"] #接下来第 2 天的温度
        rst['temp3'] = jsonDatas["weatherinfo"]["temp3"]
        rst['temp4'] = jsonDatas["weatherinfo"]["temp4"]
        rst['temp5'] = jsonDatas["weatherinfo"]["temp5"]
        rst['temp6'] = jsonDatas["weatherinfo"]["temp6"]

        rst['weather1'] = jsonDatas["weatherinfo"]["weather1"] #接下来第 1 天的天气
        rst['weather2'] = jsonDatas["weatherinfo"]["weather2"]
        rst['weather3'] = jsonDatas["weatherinfo"]["weather3"]
        rst['weather4'] = jsonDatas["weatherinfo"]["weather4"]
        rst['weather5'] = jsonDatas["weatherinfo"]["weather5"]
        rst['weather6'] = jsonDatas["weatherinfo"]["weather6"]
    except:
        print 'getCityWeatherDetail_SixDay Error'
        return {}
    else:
        return rst

#返回dict类型
def getCityWeather_AllDay(cityID):
    '全天天气数据,返回”'

    url = "http://www.weather.com.cn/data/cityinfo/" + str(cityID) + ".html"
    try:
        req=urllib2.Request(url)
        stdout = urllib2.urlopen(url)
        weatherInfomation = stdout.read().decode('utf-8')
        print 'allday – ',weatherInfomation

        #{"weatherinfo":{"city":"杭州","cityid":"101210101","temp1":"7℃","temp2":"2℃","weather":"多云转阴","img1":"d1.gif","img2":"n2.gif","ptime":"11:00"}}

        jsonDatas = json.loads(weatherInfomation)

        city = jsonDatas["weatherinfo"]["city"] #城市
        temp1 = jsonDatas["weatherinfo"]["temp1"]#最高温度
        temp2 = jsonDatas["weatherinfo"]["temp2"]#最低温度
        weather = jsonDatas["weatherinfo"]["weather"]#天气信息,如“多云转晴”
        img1 = jsonDatas["weatherinfo"]["img1"] # 图片,http://www.weather.com.cn/m/i/weatherpic/29×20/d1.gif
        img2 = jsonDatas["weatherinfo"]["img2"] # 图片
        ptime = jsonDatas["weatherinfo"]["ptime"]# 发布时间

    except:
        print "getCityWeather_AllDay Error"
        return {}
    else:
        return {'high':temp1,'low':temp2,'weather':weather,'img':img1,'ptime':ptime}
    finally:
        None

if __name__=="__main__":
    '''main function'''

    title_small = "【实时】"
    #实时数据
    dicRealTime = getCityWeather_RealTime(101210101)
    current_temp = u'N/A'
    current_wet = u'N/A'
    current_wind_direction = u'N/A'
    current_temp = dicRealTime['temp'] #温度
    current_wet = dicRealTime['sd'] #湿度
    current_wind_direction = dicRealTime['wd'] #风向
    current_wind_strong = dicRealTime['ws'] #风力 '2级'
    current_real_time = dicRealTime['time'] #时间getCityWeather_RealTime(101210101)

    print current_temp,current_wet,current_wind_direction
    #print title_small , twitter['message']

    #for city in cityList_bsgs:
    title_small = "【全天】"
    #getCityWeather_AllDay(101210101)
    #print title_small , twitter["message"]

    title_small = "【六天】"
    #getCityWeatherDetail_SixDay(101210101)
    #print title_small , twitter["message"]