読者です 読者をやめる 読者になる 読者になる

ElementTreeでLivedoor Weather Hacksを解析する

Python XML

いまさらながら、LivedoorWeather Hackで遊んでみました。
今日はlibxml2ではなく、cElementTreeを使って、XMLからPython辞書型に変換してみます。
cElementTreeのiterparseを使うと、驚くほど簡潔にXMLからPythonのコレクション型に変換できます。
「天気」「日付」「場所」「気温」「天気のアイコン」の情報があれば、ほとんどのアプリケーションには十分でしょうから、これらの要素のみを取り出すことにします。
Weather Hacksは「あさって」までの天気を配信しているようですが、今回は「今日」の天気だけを解析対象にすることにしました。
解析結果は、もとのXML文書の構造にあわせて、以下のような辞書型に変換することにします。

{
    'title' : u'宮城県 仙台 - 明日の天気',
    'link' : ....,
    'telop' : ....,
    'image' : {
         'title', ....,
         'link', .....,
    },
    'temperature' : {
         'max' : {
              'celsius' : 10,
              'fahrenheit' : 50
         },
         'min' : {
              ....
         }
    }
}

cElementTreeのiterparseを使って変換を行います。
気温をfloat型にしたり、imageのwidth, heightをint型に変換したりすることもできましたが、できるだけ短く、簡潔に書きたかったので、省略しました。

import urllib
try:
	from xml.etree.cElementTree import iterparse # for Python2.5
except ImportError:
	from cElementTree import iterparse

def get_weather(city):
	try:
		reader = urllib.urlopen("http://weather.livedoor.com/forecast/webservice/rest/v1?city=%d&day=tomorrow" % city)
	except:
		return {}

	elements = iterparse(reader)
	last = None
	for event, el in elements:
		target = {
			'max' : ("celsius", "fahrenheit"),
			'min' : ("celsius", "fahrenheit"),
			'temperature' : ("max", "min"),
			'image' : ("title", "link", "url", "width", "height"),
			'lwws' : ("title", "link", "publictime", "telop", "temperature", "image")
		}.get(el.tag, None)
		if target:
			el.text = dict([(a, el.findtext(a)) for a in target])

		last = el

	return last.text

if __name__ == '__main__':
	import sys
	# the default city is Sendai(25)
	city = (len(sys.argv) > 1 and int(sys.argv[1])) or 25
	res = get_weather(city)
	print res