python 学习笔记 12 -- 写一个脚本获取城市天气信息
近期在玩树莓派,前面写过一篇在树莓派上使用1602液晶显示屏,那么可以显示后最重要的就是显示什么的问题了。
最easy想到的就是显示时间啊,CPU利用率啊。IP地址之类的。那么我认为呢,假设可以显示当前时间、温度也是甚好的。作为一个桌面小时钟还是非常精致的。
1. 眼下有哪些工具
眼下比較好用的应该是 weather-util, 之前我获取天气信息一般都是通过它。
使用起来也非常easy:
(1) Debian/Ubuntu 用户使用
sudo apt-get install weather-util 安装
(2) 使用能够直接终端下输入“ weather 城市名拼音” 查询,如
所以我们仅仅要对查询语句进行一点点改进就可以得到:
$ 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
所以,假设我在树莓派的程序/脚本中直接调用,就可非常轻松的得到我想要的天气信息。
$ 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
python 学习笔记 12 -- 写一个脚本获取城市天气信息的更多相关文章
- python学习笔记:建立一个自己的搜索引擎
写学习笔记是我学习python以来养成的一个习惯,每学习一个知识点,便整理成文字记录下来.搜索引擎大家经常都有在使用,国内外也很很多搜索引擎平台. Google搜索引擎建立至今已经快20年了,之后全球 ...
- MiZ702学习笔记12——封装一个普通的VGA IP
还记得<MiZ702学习笔记(番外篇)--纯PL VGA驱动>这篇文章中,用verilog写了一个VGA驱动.我们今天要介绍的就是将这个工程打包成一个普通的IP,目的是为后面的一篇文章做个 ...
- [原创]java WEB学习笔记12:一个简单的serlet连接数据库实验
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- python 学习笔记12(事件驱动、IO多路复用、异步IO)
阻塞IO和非阻塞IO.同步IO和异步IO的区别 讨论背景:Linux环境下的network IO. 1.先决条件(几个重要概念) 1.1.用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32 ...
- 《python灰帽子》学习笔记:写一个windos 调试器(一)
一.开发内容介绍 为了对一个进程进行调试,你首先必须用一些方法把调试器和进程连接起来.所以, 我们的调试器要不然就是装载一个可执行程序然后运行它, 要不然就是动态的附加到一个运行的进程.Windows ...
- python学习笔记12 ----线程、进程
进程和线程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进程里的 ...
- 【Python学习笔记三】一个简单的python爬虫
这里写爬虫用的requests插件 1.一般那3.x版本的python安装后都带有相应的安装文件,目录在python安装目录的Scripts中,如下: 2.将scripts的目录配置到环境变量pa ...
- Python 学习笔记:根据输入年月获取该月的第一天和最后一天
目的: 给定一个时间,比如:2020.02,要求返回所输入月份的第一天及最后一天,比如:('2020.02.01', '2020.02.29') 参考博客:https://blog.csdn.net/ ...
- DuiLib学习笔记2——写一个简单的程序
我们要独立出来自己创建一个项目,在我们自己的项目上加皮肤这才是初衷.我的新建项目名为:duilibTest 在duilib根目录下面有个 Duilib入门文档.doc 我们就按这个教程开始入门 首先新 ...
随机推荐
- 原生mysql读出来数据有乱码
加入这个后mysql_query("set names utf8");,可以将读出来的数据变成utf8的格式,可能是解决问题的一个好方法.
- 记一个男默女泪的 BUG
姗姗来迟的词频统计代码 BUG 的发现 1. 此前提交的第一次代码作业总结博客 http://www.cnblogs.com/ustczwq/p/8680704.html 2. BUG 本天成,妙手偶 ...
- 【Oracle】RAC集群中的命令
数据库名称:racdb 节点名称:rac3.rac4 注:以下命令均在grid用户中执行 1.查看集群节点的状态: [grid@rac3 ~]$ crsctl check cluster [grid@ ...
- promise待看文档备份
http://swift.gg/2017/03/27/promises-in-swift/ http://www.cnblogs.com/feng9exe/p/9043715.html https:/ ...
- ubuntu16.04 国内源(网易、阿里)
ubuntu16.04 网易源 deb http://mirrors.163.com/ubuntu/ xenial main restricted universe multiversedeb htt ...
- Jenkins 部署 PHP 应用
安装 Jenkins 方式一:docker方式安装 拉取jenkins官方镜像,按照镜像文档启动镜像就可以了 方式二:手动安装 以下所有操作都使用 root 用户进行操作. 在各项目官网,下载 Jav ...
- 自定义View(未完待续)
一.概述 android提供了丰富的系统控件,但在实际开发中,这些控件依然不能完全覆盖我们的需求.有时,我们需要自定义控件来满足一些个性化产品需求.自定义控件,主要有以下三种方式: 继承现有控件,对其 ...
- java中Map遍历的四种方式
在java中所有的map都实现了Map接口,因此所有的Map(如HashMap, TreeMap, LinkedHashMap, Hashtable等)都可以用以下的方式去遍历. 方法一:在for循环 ...
- 天使轮 A轮 B轮 上市...等名词解释
看到一篇漫画解释的很形象:
- GDI 设备环境句柄(2)
WM_PAINT 消息的触发 Windows 程序在以下情况会触发WM_PAINT消息: 窗口被移动导致被遮盖部分暴露出来 用户调整窗口的大小(当窗口类的 style 字段被设置为 CS_HREDRA ...