python 學習筆記 12 -- 寫一個腳本獲取城市天氣信息

近期在玩樹莓派,前面寫過一篇在樹莓派上使用1602液晶顯示屏,那麼能夠顯示後最重要的就是顯示什麼的問題了。html

最easy想到的就是顯示時間啊,CPU利用率啊。IP地址之類的。那麼我認爲呢,假設能夠顯示當前時間、溫度也是甚好的。做爲一個桌面小時鐘仍是很是精緻的。python


1. 眼下有哪些工具

眼下比較好用的應該是 weather-util, 以前我獲取天氣信息通常都是經過它。git

使用起來也很是easy:github

 (1) Debian/Ubuntu 用戶使用 sudo apt-get install weather-util 安裝web

 (2) 使用可以直接終端下輸入「 weather 城市名拼音」  查詢,如shell



因此咱們僅僅要對查詢語句進行一點點改進就能夠獲得:
app

        $ weather lanzhou
        Searching via name...
        [using result Lanzhou / Zhongchuan, China]
        Current conditions at Lanzhou / Zhongchuan, China (ZLLL) 36-01-12N 103-45E
        Last updated Jul 05, 2014 - 03:00 AM EDT / 2014.07.05 0700 UTC
           Temperature: 86 F (30 C)
           Relative Humidity: 28%
           Wind: Variable at 4 MPH (4 KT)
           Sky conditions: partly cloudy

因此,假設我在樹莓派的程序/腳本中直接調用,就可很是輕鬆的獲得我想要的天氣信息。
dom

        $ weather "lanzhou" | grep "Temperature" | cut -d "(" -f2 | cut -d ")" -f1
        30 C
函數

但是,作很是多事都怕都這麼一個但是啊!!工具

在樹莓派上調用weather 查詢天氣耗時太可怕了:

       $ time weather "lanzhou" | grep "Temperature" | cut -d "(" -f2 | cut -d ")" -f1
      25 C

      real  4m30.381s
      user  4m27.010s
      sys   0m1.560s
而在個人臺式機端,耗時儘管比較長,但是也消耗了15s 之久。
      $ time weather "lanzhou" | grep "Temperature" | cut -d "(" -f2 | cut -d ")" -f1
      30 C

      real  0m15.609s
      user  0m15.405s
      sys   0m0.203s


那麼爲何使用weather 查詢個天氣需要耗時這麼久?依據參考資料[1] 中所述,「Weather」工具從METAR(Meteorological Terminal Aviation Routine Weather Report, 航空例行天氣報告), NOAA (the USA National Oceanic and Atmospheric Administration, 美國國家海洋和大氣管理局)和NWS (the USA National Weather Service, 美國國家氣象服務)檢索獲取天氣情況和預報信息。這使得這個工具主要以美國爲中心,然而你也能獲取到全球有國際機場的地區的天氣信息。

原來這個工具是針對美國國土以及一些國際機場,既然咱們不在美國國土。那麼咱們查一下國際機場的信息試試時間會不會快上很是多:

        $ time weather egll
        Searching via station...
        [caching result London / Heathrow Airport, United Kingdom]
        Current conditions at London / Heathrow Airport, United Kingdom (EGLL) 51-29N 000-27W 0M
        Last updated Jul 05, 2014 - 03:20 AM EDT / 2014.07.05 0720 UTC
           Temperature: 62 F (17 C)
           ..
        real    0m3.958s
        user    0m2.890s
        sys    0m0.072s

咱們可以看到。速度確實要快上很多。

(而且由於此工具的優化,第二次查詢時。耗時可達 0.08s 級別!

)看來咱們使用現成的 weather-util 工具查詢天氣信息算是泡湯了。


咱們需要更快的速度、更全面的區域。因此我認爲咱們需要本土的天氣查詢。



2. 使用什麼接口

上文討論到,咱們需要使用本土的天氣查詢,百度上找到了一個帖子(見參考資料[2])。上面給出了中國天氣網(www.weather.com.cn)提供的查詢結構,並且如下還給出了城市編碼。

在此感謝一下做者。


那麼咱們在此查看一下這些接口會給咱們哪些新息:

接口1 : http://www.weather.com.cn/data/cityinfo/***.html   (「***」 處替換爲你想要查詢的城市的編碼。下同)

這個網址會給咱們例如如下信息(我感受實用的信息已用顏色標出):

    {"weatherinfo":{"city":"蘭州","cityid":"101160101","temp1":"19℃","temp2":"33℃","weather":"晴","img1":"n0.gif","img2":"d0.gif","ptime":"18:00"}}

因此咱們可以經過此接口獲得城市的氣候"weather"),低溫"temp1"),高溫("temp2")。



接口2 : http://www.weather.com.cn/data/sk/***.html

這個接口會給咱們例如如下信息:

   {"weatherinfo":{"city":"蘭州","cityid":"101160101","temp":"26","WD":"北風","WS":"1 級","SD":"36%","WSE":"1","time":"21:00","isRadar":"1","Radar":"JC_RADAR_AZ9931_JB"}}

因此經過此結構咱們可以獲得的是一個城市的實時溫度("temp")。

接口3:http://m.weather.com.cn/data/***.html

感受這個接口給的信息比較雜亂:

{"weatherinfo":{"city":"蘭州","city_en":"lanzhou","date_y":"2014年3月4日","date":"","week":"星期二","fchh":"11","cityid":"101160101","temp1":"11℃~0℃","temp2":"12℃~0℃","temp3":"11℃~2℃","temp4":"13℃~2℃","temp5":"15℃~2℃","temp6":"18℃~4℃","tempF1":"51.8℉~32℉","tempF2":"53.6℉~32℉","tempF3":"51.8℉~35.6℉","tempF4":"55.4℉~35.6℉","tempF5":"59℉~35.6℉","tempF6":"64.4℉~39.2℉","weather1":"晴","weather2":"多雲","weather3":"多雲轉小雨","weather4":"小雨轉多雲","weather5":"多雲轉晴","weather6":"晴","img1":"0","img2":"99","img3":"1","img4":"99","img5":"1","img6":"7","img7":"7","img8":"1","img9":"1","img10":"0","img11":"0","img12":"99","img_single":"0","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":"微風","wind2":"微風","wind3":"微風","wind4":"微風","wind5":"微風","wind6":"微風","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":"10","st2":"1","st3":"12","st4":"0","st5":"11","st6":"2","index_cl":"適宜","index_ls":"基本適宜","index_ag":"極易發"}}


3. 實現

有了這些接口信息,外加城市代碼文件,咱們可以很是輕鬆濾清所要作的順序: 依據用戶輸入的城市在代碼文件裏查找城市代碼,使用城市代碼替換結構中的代碼。使用python的urllib2 獲取此結構的內容。而後解析並輸出。


3.1 搜索城市代碼

城市代碼文件裏的內容格式爲:

101010100=北京
101010200=海淀
101010300=朝陽

而整個文件有2000多行。假設逐行讀取並匹配,我的認爲效率仍是不高,因此我使用 os.popen 調用shell 中的grep 來進行全文匹配查找。


def get_city_code(test_city, citycode_f = "citycode"):
    if os.path.exists(citycode_f):      # 先檢查城市代碼文件是否存在
        ret = os.system("grep %s %s >/dev/null" % (test_city,citycode_f))   
        if ret == 0:        # 檢測os.system 的返回值從而得知城市名是否在代碼文件裏存在
            grep_content = os.popen("grep %s %s" % (test_city,citycode_f)).read()
            city_code = grep_content.split("=")[0]  # 假設存在獲取匹配行,如"101010100=北京",使用‘=’做爲分隔符獲取第一列
            return city_code
        else:
            print "\t搜索\"%s\"失敗,請又一次搜索(市級城市)" % test_city
            sys.exit(-1)
    else:
        print "當前文件夾沒有\"%s\"文件。沒法搜索" % citycode_f
        sys.exit(-1)



3.2 替換結構代碼獲取內容

經過調用上述函數獲得城市代碼,使用例如如下的簡單字符串方法就能夠改動城市url :

weather_url = "http://www.weather.com.cn/data/sk/%s.html" % city_code

info_url = "http://www.weather.com.cn/data/cityinfo/%s.html" % city_code

因此咱們此時僅僅需要使用urllib2 模塊獲取url 的內容,並對內容進行解析。

獲取url 內容,這裏使用了一個簡單的函數:

def use_urllib2(url):  
    try:  
        f = urllib2.urlopen(url, timeout=5).read()  
    except urllib2.URLError, e:    
        print e.reason  
        return -1
    else:
        return f


因此使用此函數打開上面的url ,打開後分析返回值假設是 -1 則打開出錯,給出錯誤信息並調用 sys.exit 退出程序。假設正常打開。對內容進行解析獲取關心的內容就能夠:

    weather_url = "http://www.weather.com.cn/data/sk/%s.html" % city_code   
    wea_str = use_urllib2(weather_url)
    if wea_str == -1:
        print "Sorry that I can't find the weather info of this city now, please check or retry"
        sys.exit(-1)
    else:
        wea_list = wea_str.split(",")
        for item in wea_list:
            if "city" in item and "cityid" not in item:
                city_name = get_content(item)
            if "temp" in item:
                city_temp = get_content(item)
            if "time" in item:
                update_time = get_content(item)



3.3 中文輸入or英文輸入

對於城市的代碼文件,咱們可以看出:假設想要匹配。咱們僅僅能使用中文城市名。那麼假設我想用城市名的拼音怎麼辦?因此僅僅能從根本處借決問題。那麼怎麼解決?一個個手動打進去?2000多行哦! 這時候我想到了上面的接口3 中有這麼一條實用的信息:"city":"蘭州","city_en":"lanzhou"

貌似一切都要變得簡單。

我將原來原來拷貝過來的 citycode 更名爲citycode1。

並寫了一個腳本:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib2
import sys
import os
def file_append(filename,string):
    try:
        f = open(filename,"a")
        try:
            f.write(string+"\n")
        except IOError:
            print("Append %s occurs some errors" % filename)
            return 0
        except:
            print("Append %s occurs some errors" % filename)
            return 0
        else:
            return 1
    except IOError:
        print("open %s file error" % filename)
        return 0
        traceback.print_exc()
    finally:
        f.close()


def use_urllib2(url):
    try:
        f = urllib2.urlopen(url, timeout=5).read()
    except urllib2.URLError, e:
        print e.reason
        return -1
    else:
        return f


def deal_with_file(sour_file, tar_file):
    try:
        open_file = file(sour_file)
        file_len = len(open(sour_file,'rU').readlines())    # 獲取文件長度

        for cur_line in range(0, file_len):
            content = open_file.readline().strip("\n")
            print "No.%d\tNow dealing with %s" %(cur_line, content)
            if len(content) == 0:
                file_append(tar_file, content)
            else:
                city_code = content.split("=")[0]
                get_city_content_url = "http://m.weather.com.cn/data/%s.html" % city_code
                web_content = use_urllib2(get_city_content_url)
                if web_content == -1:
                    print "%s has no the web content, pass it " % content
                else:
                    web_list = web_content.split(",")
                    for item in web_list:
                        if "city_en" in item:
                            dealed_content = content+"="+item.split(":")[1].replace("\"", "")
                            file_append(tar_file, dealed_content)
            
    except IOError:
        print("open %s file error" % sour_file)
        sys.exit(-1)
    finally:
        print("we will close file %s" % sour_file)
        open_file.close()


#### Real start here
file_name = "citycode1"        # 原始文件,格式爲"101010100=北京"
result_f = "citycode"            # 終於將改完的格式爲"101010100=北京=beijing"內容存入此文件
if os.path.exists(result_f):
    os.remove(result_f)
deal_with_file(file_name, result_f)



此時咱們打開城市代碼文件,裏面的內容都是這個格式的大笑

101010100=北京=beijing
101010200=海淀=haidian
101010300=朝陽=chaoyang


注: 改動完的的城市代碼信息,原本我上傳csdn下載,但是苦於被刪除,因此你們可以克隆此倉庫



3.4 中文輸出or英文輸出

那麼這個程序打印究竟應該是中文仍是英文呢?我採取了本系列前文《python 學習筆記 11 -- 使用參數使你的程序變得更性感 》中的方法。加入參數選擇"-zh"/"-en"。假設使用的是 "./getweather.py  -zh **" 則以中文輸出(不填加選項,直接使用 "./getweather.py ***" 查詢採取的默認輸出也是中文,只是可經過改動代碼中的初始值設置進行改動)。假設使用"./getweather.py  -en **" 則以英文輸出。

使用的方法很是easy:設置一個全局變量叫 "chinese_flag" 並設初始值爲1。獲取用戶參數時。假設有 "-zh" 則不變,假設有"-en" 則改成0。不論什麼printf 打印時對此變量進行推斷後使用不一樣的輸出。



4. 總結

本文中儘管總共寫了不到300 行的python 代碼,但是終於效果以及健壯性仍是很是不錯的:

$ ./getweather.py 蘭州
你僅僅使用一個參數"蘭州"(且不是"-h"),將其做爲城市名搜索
timed out
對不起。臨時搜尋不到此城市信息,請檢查或稍後再試
$ ./getweather.py 蘭州
你僅僅使用一個參數"蘭州"(且不是"-h"),將其做爲城市名搜索
    今天"蘭州市"天氣是:
    ========================
    今日天氣 : 晴
    實時溫度 : 32℃
    今日的溫度區間 : 19℃ ~ 33℃
    更新時間: 16:10
    ========================
    不少其它請參見:http://www.weather.com.cn/weather/101160101.shtml
$ ./getweather.py lanzhou
你僅僅使用一個參數"lanzhou"(且不是"-h"),將其做爲城市名搜索
    今天"蘭州市"天氣是:
    ========================
    今日天氣 : 晴
    實時溫度 : 32℃
    今日的溫度區間 : 19℃ ~ 33℃
    更新時間: 16:10
    ========================
    不少其它請參見:http://www.weather.com.cn/weather/101160101.shtml
$ ./getweather.py -en lanzhou
    The weather info of "蘭州":
    ========================
    The weather today is : 晴
    Currenttly the temperature is : 32℃
    The weather section today is : 19℃ ~ 33℃
    Update time: 16:10
    ========================
    See more: http://en.weather.com.cn/weather/101160101.shtml
$ ./getweather.py -en lanzhou1
    Search city "lanzhou1" fail, please check the city and retry(at lease city size)
$ ./getweather.py -zg lanzhou1
你選擇了錯誤的結果選項,請又一次輸入或者使用'-h'查看怎樣使用
$ ./getweather.py -zh lanzhou1
    搜索"lanzhou1"失敗,請又一次搜索(市級城市)


關於本文代碼。我已經提交在前文《Shell 腳本小試牛刀(番外) -- 捷報 》中提到的github 倉庫中。且git 倉庫已改名: cool_script 。

可直接克隆倉庫: git clone https://github.com/longerzone/easy_script  .而後進入 get_weather 文件夾查看。




================

參考資料:

[1] 關於weather-util :  http://www.iraspberrypi.com/archives/539

[2] 關於中國天氣網的結構: http://www.iteye.com/topic/1106241


================================================

注: 轉載註明出處: http://blog.csdn.net/longerzone

相關文章
相關標籤/搜索