查天气(python实用教程一,会认字的都学的会)

PART1

给大家看一个程序:




你输入一个城市的名称,就会告诉你这个城市现在的天气情况。接下来的几节课,我就说一下怎么实现这样一个小程序。


之所以能知道一个城市的天气,是因为用了中国天气网(www.weather.com.cn)提供的天气查询接口。在浏览器里试着访问一下:

http://www.weather.com.cn/data/cityinfo/101010100.html

你就能看到北京现在的天气。这段看上去有点像python中字典类的文字是一种称作json格式的数据。


而我们的程序要做的事情,就是按照用户输入的城市名称,去天气网的接口请求对应的天气信息,再把结果展示给用户。


于是,在这个程序中,我们要用到两个新模块:

1. urllib2

用来发送网络请求,获取数据


2. json

用来解析获得的数据


听上去似乎还挺不算太复杂?但是注意刚才那个例子,我们请求北京天气时,用了“101010100”这样的数字。这是天气网设定的城市代码。然而令人蛋疼的是,天气网并没有直接给出所有城市代码的对应关系,而是给了3个接口:


1. http://m.weather.com.cn/data5/city.xml

获取所有省/直辖市的编号,如“01|北京,02|上海,03|天津”


2. http://m.weather.com.cn/data5/city省编号.xml

获取二级地区编号,如江苏是:city19.xml


3. http://m.weather.com.cn/data5/city二级编号.xml

获取三级编号,如南京是:city1901.xml


得到最终的三级编号之后,再加上中国101的前缀,就得到了城市代码,如南京市区就是“101190101”


所以,你可以选择,再写一个python程序,事先把这些复杂的编码全部抓取下来,整理成你要的格式;或者,偷懒一下,跳过这个过程,直接拿我抓好的编码。我放在了网盘里:

http://pan.baidu.com/share/link?shareid=1471212773&uk=204484850


PART2

先来看python中的urllib2,这是python中一个用来获取网络资源的模块。我们平常上网,在浏览器地址栏中输入一个网址,浏览器根据这个网址拿到一些内容,然后展现在页面上,这大约就是浏览网页的过程。类似的,urllib2会跟据你提供的网址,请求对应的内容。


打开一个链接和打开一个文件有点像:

import urllib2

web = urllib2.urlopen('http://www.baidu.com')

content = web.read()

print content


我们引入urllib2的模块,用其中的urlopen方法打开百度,然后用read方法把其中的内容读取到一个变量中并输出。运行后,你会看到控制台中输出了一堆看不懂的代码文字。这段代码中有html,有css,还有javascript。我们在浏览器中看到的网页大部分就是由这些代码所组成。如果你把content保存到一个以“.html”结尾的文件中(保存文件的方法前面已经说过很多),再打开这个html文件,就会看到“百度的首页”,只是这个首页在你的电脑上,所以你无法进行搜索。


回到我们的查天气程序,我们要向中国天气网发一个查询天气的请求。昨天说了,如何获取查询的url是个问题。先说简单的办法,用我提供的城市代码列表city.py。


city.py这个文件里有一个叫做city的字典,它里面的key是城市的名称,value是对应的城市代码。不用把它copy到自己的程序中,只要放在和你的代码同一路径下,用

from city import city


就可以引入city这个字典。这里相当于用了一个自定义的模块,前一个“city”是模块名,也就是py文件的名称,后一个“city”是模块中变量的名称。


构造我们需要的url:

cityname = raw_input('你想查哪个城市的天气?\n')

citycode = city.get(cityname)

if citycode:

   url = ('http://www.weather.com.cn/data/cityinfo/%s.html' % citycode)

   content = urllib2.urlopen(url).read()


为了防止你输入列表中没有的城市,所以用了if判断citycode是否存在。


运行一下看看能不能得到结果。如果提示编码的错误,试试在文件最开始加上:

# -*- coding: utf-8 -*-




可以看到,已经拿到了json格式的天气信息。


PART3

看一下我们已经拿到的json格式的天气数据:


{

   "weatherinfo": {

       "city": "南京",

       "cityid": "101190101",

       "temp1": "37℃",

       "temp2": "28℃",

       "weather": "多云",

       "img1": "d1.gif",

       "img2": "n1.gif",

       "ptime": "11:00"

   }

}


直接在命令行中看到的应该是没有换行和空格的一长串字符,这里我把格式整理了一下。可以看出,它像是一个字典的结构,但是有两层。最外层只有一个key--“weatherinfo”,它的value是另一个字典,里面包含了好几项天气信息,现在我们最关心的就是其中的temp1,temp2和weather。


虽然看上去像字典,但它对于程序来说,仍然是一个字符串,只不过是一个满足json格式的字符串。我们用python中json模块提供的loads方法,把它转成一个真正的字典。


import json


data = json.loads(content)


这时候的data已经是一个字典,尽管在控制台中输出它,看上去和content没什么区别,只是编码上有些不同:

{u'weatherinfo': {u'city': u'\u5357\u4eac', u'ptime': u'11:00', u'cityid': u'101190101', u'temp2': u'28\u2103', u'temp1': u'37\u2103', u'weather': u'\u591a\u4e91', u'img2': u'n1.gif', u'img1': u'd1.gif'}}


但如果你用type方法看一下它们的类型:


print type(content)

print type(data)


就知道区别在哪里了。


之后的事情就比较容易了。


result = data['weatherinfo']

str_temp = ('%s\n%s ~ %s') % (

   result['weather'],

   result['temp1'],

   result['temp2']

)

print str_temp


为了防止在请求过程中出错,我加上了一个异常处理。


try:

   ###

   ###

except:

   print '查询失败'


以及没有找到城市时的处理:


if citycode:

   ###

   ###

else:

   print '没有找到该城市'



LAST

这一课算是“查天气”程序的附加内容。没有这一课,你也查到天气了。但了解一下城市代码的抓取过程,会对网页抓取有更深的理解。


天气网的城市代码信息结构比较复杂,所有代码按层级放在了很多xml为后缀的文件中。而这些所谓的“xml”文件又不符合xml的格式规范,导致在浏览器中无法显示,给我们的抓取又多加了一点难度。


首先,抓取省份的列表:

url1 = 'http://m.weather.com.cn/data5/city.xml'

content1 = urllib2.urlopen(url1).read()

provinces = content1.split(',')


输出content1可以查看全部省份代码:

01|北京,02|上海,03|天津,...


对于每个省,抓取城市列表:

url = 'http://m.weather.com.cn/data3/city%s.xml'

for p in provinces:

   p_code = p.split('|')[0]

   url2 = url % p_code

   content2 = urllib2.urlopen(url2).read()

   cities = content2.split(',')


输出content2可以查看此省份下所有城市代码:

1901|南京,1902|无锡,1903|镇江,...


再对于每个城市,抓取地区列表:

for c in cities[:3]:

   c_code = c.split('|')[0]

   url3 = url % c_code

   content3 = urllib2.urlopen(url3).read()

   districts = content3.split(',')


content3是此城市下所有地区代码:

190101|南京,190102|溧水,190103|高淳,...


最后,对于每个地区,我们把它的名字记录下来,然后再发送一次请求,得到它的最终代码:

for d in districts:

   d_pair = d.split('|')

   d_code = d_pair[0]

   name = d_pair[1]

   url4 = url % d_code

   content4 = urllib2.urlopen(url4).read()

   code = content4.split('|')[1]


name和code就是我们最终要得到的城市代码信息。它们格式化到字符串中,最终保存在文件里:

line = "    '%s': '%s',\n" % (name, code)

result += line


同时你也可以输出它们,以便在抓取的过程中查看进度:

print  name + ':' + code



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值