Seite 1 von 1
Get Weather!
Verfasst: Freitag 11. September 2009, 20:17
von Dav1d
Ich hab hier ein kleines Snippet, was für den ein oder anderen vllt nützlich ist, geschrieben hab ichs eigentlich nur als Zwischenschritt (wird noch ne GUI drumrum gebaut!
Über das google-wetter-api, werden aktuelle daten geladen und als Unicode zurückgegeben
Vorraussetztungen: BeautifulSoup
Code: Alles auswählen
#!/usr/bin/python
try:
import urllib2 as ulib
except ImportError:
import urllib.request as ulib
try:
from BeautifulSoup import BeautifulStoneSoup
except ImportError:
print 'Pls install BeautifulSoup (http://www.crummy.com/software/BeautifulSoup/)'
di = ['city', 'postal_code', 'current_date_time']
dc = ['condition', 'temp_f', 'temp_c', 'humidity', 'wind_condition']
df = ['day_of_week', 'low', 'high', 'condition']
dis = []
dcs = []
dfs = []
class getweather:
def __init__(self, ort):
f = ulib.urlopen('http://www.google.de/ig/api?weather=' + ort)
encoding = f.info()['content-type'].split('charset=')[1]
f = f.read().decode(encoding)
stonesoup = BeautifulStoneSoup(f)
self.forecast_information = stonesoup.find('forecast_information')
self.current_conditions = stonesoup.find('current_conditions')
self.forecast_conditions = stonesoup.findAll('forecast_conditions')
def getdi(self):
for data in di:
dis.append(self.forecast_information.find(data)['data'])
return dis
def getdc(self):
for data in dc:
dcs.append(self.current_conditions.find(data)['data'])
return dcs
def getdf(self):
for forecast in self.forecast_conditions:
for data in df:
dfs.append(forecast.find(data)['data'])
return dfs
if __name__ == '__main__':
munich = getweather('80331')
print munich.getdi()
berlin = getweather('Berlin')
print berlin.getdc()
Code: Alles auswählen
Erklärung für die "Abkürzungen", ergibt sich aus der Api-XML
di = datainformation
dc = datacurrent
df = dataforecast
dis = datainformationsave
dic = datacurrentsave
dfs = dataforecastsave
mit dem
Code: Alles auswählen
try:
import urllib2 as ulib
except ImportError:
import urllib.request as ulib
urllib2 = Python 2
aber urllib.request = Python 3 (ich weiß es nicht), falls es nicht so ist pls berichtigt mich, zum testen hab ich gerade keiner Python 3 zur Hand
mfg
PS: Würde mich über Feedback freuen
Verfasst: Freitag 11. September 2009, 20:43
von cofi
Macht dich die "Erklaerung" nicht stutzig? Warum nimmst du nicht die Namen die keiner Erklaerung beduerfen? Um der API zu entsprechen ist in dem Fall IMHO ein sehr schwaches Argument.
Die Python2/3-Angelegenheit wuerde ich nicht ueber den ``ImportError``, sondern ueber eine Versionsabfrage (``sys.version_info``) loesen.
Was BeautifulSoup angeht, spricht IMHO nichts dagegen, wenn das Script nicht die Datei selbst in das aktuelle Verzeichnis herunterlaedt und erneut importiert, evtl nach Frage an den Benutzer.
Edit:
Und zum Code:
``f`` will geschlossen werden, auch ist die Neuzuweisung unguenstig. ``content`` waere ein besserer Name.
Warum stehen deine Listen ausserhalb der Klasse? Du brauchst keine globalen Variablen, v.a. da du sie als Instanzvariablen missbrauchst.
Deine ganzen ``get*`` lassen sich evtl besser als ``property`` schreiben auch waere ein Buffern oder ein komplettes Auslesen in ``__init__`` besser.
Verfasst: Samstag 12. September 2009, 18:18
von Dav1d
Ich hab das mal ein bisschen umgestellt:
Code: Alles auswählen
#!/usr/bin/python
import sys
import os
if sys.version_info[0] < 3:
import urllib2 as ulib
else:
import urllib.request as ulib
try:
if sys.argv[1] == '--beautifulsoup':
if not os.path.exists(os.path.join(os.path.split(sys.argv[0])[0], 'BeautifulSoup.py')):
dl = ulib.urlopen('http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.0.6.py')
bsoup = dl.read()
bsoupfile = open('BeautifulSoup.py', 'w')
bsoupfile.write(bsoup)
dl.close()
bsoupfile.close()
except IndexError:
pass
try:
from BeautifulSoup import BeautifulStoneSoup
except ImportError:
print('Pls install BeautifulSoup (http://www.crummy.com/software/BeautifulSoup/)')
print('or use the parameter: --beautifulsoup, to download it and use it after downloading')
sys.exit(1)
class getweather:
def __init__(self, place):
# List, which are needed to download the data, the d in the name of the lists present data
self.dinfo = ['city', 'postal_code', 'current_date_time']
self.dcurrent = ['condition', 'temp_f', 'temp_c', 'humidity', 'wind_condition']
self.dforecast = ['day_of_week', 'low', 'high', 'condition']
# Lists to save the datas
self.dinfos = []
self.dcurrents = []
self.dforecasts = []
self.place = place
self.getweatherdata()
def getweatherdata(self):
'''Downloading the whole data and extracting into the lists'''
f = ulib.urlopen('http://www.google.de/ig/api?weather=' + self.place)
encoding = f.info()['content-type'].split('charset=')[1]
self.content = f.read().decode(encoding)
f.close()
stonesoup = BeautifulStoneSoup(self.content)
forecast_information = stonesoup.find('forecast_information')
current_conditions = stonesoup.find('current_conditions')
forecast_conditions = stonesoup.findAll('forecast_conditions')
for data in self.dinfo:
self.dinfos.append(forecast_information.find(data)['data'])
for data in self.dcurrent:
self.dcurrents.append(current_conditions.find(data)['data'])
for forecast in forecast_conditions:
for data in self.dforecast:
self.dforecasts.append(forecast.find(data)['data'])
def returndata(self):
'''Retruning of the lists with data'''
return self.dinfos, self.dcurrents, self.dforecasts
if __name__ == '__main__':
munich = getweather('80331')
a, b, c = munich.returndata()
print(a, b, c)
Das hier:
Code: Alles auswählen
try:
if sys.argv[1] == '--beautifulsoup':
if not os.path.exists(os.path.join(os.path.split(sys.argv[0])[0], 'BeautifulSoup.py')):
dl = ulib.urlopen('http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.0.6.py')
bsoup = dl.read()
bsoupfile = open('BeautifulSoup.py', 'w')
bsoupfile.write(bsoup)
dl.close()
bsoupfile.close()
except IndexError:
pass
gefällt mir gar nicht (try, except-block), allerdings weis ich auch nicht wie ichs anders machen soll, wenn wer ne Idee hat her damit
//Edit: Code jetzt auf englisch mit Kommentaren und Docstrings
Verfasst: Samstag 12. September 2009, 19:01
von DasIch
Wieso machst du daraus nicht eine Funktion die ein dict mit den Daten zurück gibt? Vom Aufbau der XML Datei ist dass problemlos machbar.
Verfasst: Samstag 12. September 2009, 22:32
von Hyperion
DasIch hat geschrieben:Wieso machst du daraus nicht eine Funktion die ein dict mit den Daten zurück gibt? Vom Aufbau der XML Datei ist dass problemlos machbar.
Zumal der OP Klasse schon wie eine Funktion benannt hat - wenn man so etwas macht, ist das oftmals schon ein Indiz für den Missbrauch des Klassenkonstruktes.
Verfasst: Sonntag 13. September 2009, 09:50
von Dav1d
@DasIch, sowas in der Art wollte ich noch machen
@Hyperion, jo das stimmt die Namen sind nicht perfekt geweählt!
//Edit: So das ganze sieht jetzt etwas anders aus!
Code: Alles auswählen
#!/usr/bin/python
import sys
import os
if sys.version_info[0] < 3:
import urllib2 as ulib
else:
import urllib.request as ulib
try:
if sys.argv[1] == '--beautifulsoup':
if not os.path.exists(os.path.join(os.path.split(sys.argv[0])[0], 'BeautifulSoup.py')):
dl = ulib.urlopen('http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.0.6.py')
bsoup = dl.read()
bsoupfile = open('BeautifulSoup.py', 'w')
bsoupfile.write(bsoup)
dl.close()
bsoupfile.close()
except IndexError:
pass
try:
from BeautifulSoup import BeautifulStoneSoup
except ImportError:
print('Pls install BeautifulSoup (http://www.crummy.com/software/BeautifulSoup/)')
print('or use the parameter: --beautifulsoup, to download it and use it after downloading')
sys.exit(1)
def gwapi(place, lang='en'):
# Dictionaries to save the informations
winfo = {'city' : '',
'postal_code' : '',
'latitude_e6' : '',
'longitude_e6' : '',
'forecast_date' : '',
'current_date_time' : ''}
wcurrent = {'condition' : '',
'temp_f' : '',
'temp_c' : '',
'humidity' : '',
'wind_condition' : ''}
wforecast = {'day_of_week' : '',
'low' : '',
'high' : '',
'condition': ''}
# Available Languages
languages = { 'en' : 'com',
'de' : 'de'}
if lang in languages.keys():
lang = languages[lang]
else:
lang = languages['en']
f = ulib.urlopen('http://www.google.' + lang + '/ig/api?weather=' + place)
encoding = f.info()['content-type'].split('charset=')[1]
content = f.read().decode(encoding)
f.close()
stonesoup = BeautifulStoneSoup(content)
if stonesoup.find('problem_cause'):
raise ValueError('city not available')
forecast_information = stonesoup.find('forecast_information')
current_conditions = stonesoup.find('current_conditions')
forecast_conditions = stonesoup.findAll('forecast_conditions')
for data in winfo.keys():
winfo[data] = forecast_information.find(data)['data']
for data in wcurrent.keys():
wcurrent[data] = current_conditions.find(data)['data']
for forecast in forecast_conditions:
for data in wforecast.keys():
wforecast[data] = forecast.find(data)['data']
return winfo, wcurrent, wforecast
if __name__ == '__main__':
a, b, c = gwapi('Munich', lang='de')
print(a, b, c)
Verfasst: Sonntag 13. September 2009, 12:59
von Hyperion
Statt gwapi() würde ich eher etwas wie get_weather() als Namen wählen. Das passt besser zu einer Funktion.
Die Zeilen 56-59 würde ich eher so schreiben:
Wobei das Überschriben von Namen imho in den seltensten Fällen sinnvoll ist. Denn die Value-Werte entsprechen doch eher Domains.
Schlussendlich sind a, b und c keine guten Namen.
Ob die Keys für die dictionaries (oder das Sprach-Mapping komplett) innerhalb der Funktion definiert werden sollten, wäre die nächste Überlegung. Ich würde wohl die Keys global definieren und dann in der Funktion nur noch die Dicts anlegen. Das Sprachen-Dict würde ich komplett auf Modulebene definieren.
Desweiteren: Doku, Doku, Doku

Verfasst: Sonntag 13. September 2009, 13:20
von Dav1d
Mit
Ich würde wohl die Keys global definieren und dann in der Funktion nur noch die Dicts anlegen.
versteh ich nicht ganz was du meinst
Verfasst: Sonntag 13. September 2009, 16:50
von BlackJack
Ich würd's so machen:
Code: Alles auswählen
#!/usr/bin/env python
import urllib
from functools import partial
from pprint import pprint
from xml.etree import ElementTree as etree
URL_TEMPLATE = 'http://www.google.%s.//ig/api?weather=%s'
LANGUAGE_TO_DOMAIN = {'en': 'com', 'de': 'de'}
FORECAST_INFORMATION_KEYS = ['city', 'postal_code', 'latitude_e6',
'longitude_e6', 'forecast_date',
'current_date_time']
CURRENT_FORECAST_KEYS = ['condition', 'temp_f', 'temp_c', 'humidity',
'wind_condition']
FORECAST_KEYS = ['day_of_week', 'low', 'high', 'condition']
def node2dict(keys, node):
return dict((k, node.find(k).get('data')) for k in keys)
def get_weather(city, language='en'):
url = urllib.urlopen(URL_TEMPLATE % (LANGUAGE_TO_DOMAIN.get(language, 'en'),
city))
try:
doc = etree.fromstring(url.read())
finally:
url.close()
forecast_information = node2dict(FORECAST_INFORMATION_KEYS,
doc.find('./*/forecast_information'))
current_conditions = node2dict(CURRENT_FORECAST_KEYS,
doc.find('./*/current_conditions'))
forecast_conditions = map(partial(node2dict, FORECAST_KEYS),
doc.findall('./*/forecast_conditions'))
return (forecast_information, current_conditions, forecast_conditions)
def main():
result = get_weather('Munich', 'en')
pprint(result)
if __name__ == '__main__':
main()
Funktioniert allerdings nicht mit 'de' weil Google kaputtes XML liefert, und zwar welches, bei dem die Kodierungsangabe nicht stimmt. Es gibt keine, also muss man das eigentlich als UTF-8 dekodieren, aber es ist kein UTF-8. Eine Kodierungsangabe in den HTTP-Headern ist kein Ersatz für eine Angabe im XML selbst.
Verfasst: Freitag 18. September 2009, 02:06
von snafu
Hab's jetzt mal ein bißchen objektorientiert gemacht:
Code: Alles auswählen
>>> from weather import get_weather
>>> ge = get_weather('de-45881', 'de')
>>> ge.info.city
'Gelsenkirchen, NRW'
>>> ge.info.zipcode
('DE', 45881)
>>> ge.info.zipcode_string
'DE-45881'
>>> ge.info.datetime
datetime.datetime(2009, 9, 18, 0, 0, 4)
>>> ge.info.datetime_string
'Fri, 18 Sep 2009 00:00:04 +0000'
>>> ge.current.condition
'Klar'
>>> ge.current.temp_c
13
>>> ge.current.temp_f
55
>>> ge.forecast
{'Mo.': (22, 12, u'Vereinzelt st\xfcrmisch'), 'So.': (23, 13, 'Vereinzelt Regen'), 'Fr.': (21, 12, 'Klar'), 'Sa.': (24, 13, 'Klar')}
>>> ge = get_weather(45881)
>>> ge.info.city
'Rawson, OH'
>>> ny = get_weather('new york')
>>> ny.info.city
'New York, NY'
>>> paris = get_weather('paris', 'fr')
>>> paris.forecast
{'ven.': (24, 13, "Nuageux dans l'ensemble"), 'dim.': (23, 12, 'Brouillard'), 'sam.': (24, 12, 'Couverture nuageuse partielle'), 'lun.': (23, 11, 'Averses')}
>>> munich = get_weather('münchen', 'fr')
>>> munich.info.city
'Munich, BY'
>>> munich.forecast
{'ven.': (21, 11, 'Pluie'), 'dim.': (22, 11, 'Risques de pluie'), 'sam.': (22, 11, 'Risques de pluie'), 'lun.': (23, 11, u'Risques de temp\xeate')}
Der Code dazu
Hm, ich geh da morgen nochmal drüber. Ich glaub, ich mach mir die Sache mit dem Zipcode viel zu kompliziert. ^^
Verfasst: Freitag 18. September 2009, 06:13
von Dav1d
find ich gut, allerdings auch ziemlich umständlich man hätte die Liste die rauskommt zerlegen können
Verfasst: Freitag 18. September 2009, 07:40
von /me
Dav1d hat geschrieben:find ich gut, allerdings auch ziemlich umständlich man hätte die Liste die rauskommt zerlegen können
Ich verstehe jetzt nicht, was an einer Liste umständlich sein soll.
Wie würdest du das zerlegen wollen?
Verfasst: Freitag 18. September 2009, 09:18
von snafu
Welche Liste? Meinst du das Wörterbuch mit den Tupeln? Warum soll es umständlicher sein, eine Liste zu benutzen als etwas zu zerlegen? Aber kann ja gut sein, dass man manche Schritte noch vereinfachen kann. Habe das nach bestem Wissen und Gewissen strukturiert.

Verfasst: Freitag 18. September 2009, 12:57
von jbs
Was spricht denn gegen ``...&hl={1}`` anstatt von ``...google.{1}...``?
Ist doch schöner wenn man die Sprache explizit angibt und nicht auf die TLD setzt, oder?
Verfasst: Freitag 18. September 2009, 16:44
von snafu
@jbs: Daran hab ich gar nicht gedacht... Du hast recht: Es ist schöner. Ich schreibe gerade an einem Kommandozeilen-Interface und werd deinen Tipp einbauen, wenn ich's veröffentliche.
Verfasst: Freitag 18. September 2009, 18:47
von Dav1d
snafu hat geschrieben:Welche Liste? Meinst du das Wörterbuch mit den Tupeln? Warum soll es umständlicher sein, eine Liste zu benutzen als etwas zu zerlegen? Aber kann ja gut sein, dass man manche Schritte noch vereinfachen kann. Habe das nach bestem Wissen und Gewissen strukturiert.

Ah, stimmt, die Liste war in den alten 'Versionen'
Verfasst: Mittwoch 23. Dezember 2009, 19:20
von Dav1d
Ich hab das komplette Skript nochmal überarbeitet, diesmal wird lxml oder BeautifulSouo verwendet, welches gerade installiert ist!
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
if sys.version_info[0] < 3:
import urllib2 as ulib
else:
import urllib.request as ulib
try:
from lxml import etree
parser = 'etree'
except ImportError:
try:
from BeautifulSoup import BeautifulStoneSoup
parser = 'beautifulstonesoup'
except ImportError:
raise ImportError('lxml or BeautifulSoup must be installed')
langs = {'german' : 'de',
'french' : 'fr',
'english' : 'en',
'de' : 'de',
'fr' : 'fr',
'en' : 'en'}
def get_weather(location, lang):
'''parses a XML-Document from the Google-Weather API'''
lang = langs.get(lang, 'en')
url = 'http://www.google.com/ig/api?weather={location}&hl={lang}' \
.format(location=location, lang=lang)
f = ulib.urlopen(url)
encoding = f.info()['content-type'].split('charset=')[1]
content = f.read().decode(encoding)
#print type(content) # "unicode"?
f.close()
if parser == 'etree':
parsed = _parse_weather_lxml(content)
else:
parsed = _parse_weather_bss(content)
return parsed
def _parse_weather_lxml(data):
stored_data = {'forecast_information' : None,
'current_conditions' : None,
'forecast_conditions' : []}
etree_xml = etree.fromstring(data)
root = etree_xml.find('weather')
for r_child in root.getchildren():
tag = r_child.tag
buf = {}
if not tag == 'problem_cause': # error?
for child in r_child:
buf[child.tag] = child.get('data', '')
if not tag == 'forecast_conditions':
stored_data[tag] = buf
else:
stored_data[tag].append(buf)
else: # jep, error!
stored_data[tag] = r_child.get('data', '')
return stored_data
def _parse_weather_bss(data):
stored_data = {'forecast_information' : None,
'current_conditions' : None,
'forecast_conditions' : []}
stonesoup = BeautifulStoneSoup(data)
for r_child in stonesoup.find('weather'):
tag = r_child.name
buf = {}
if not tag == 'problem_cause': # error?
for child in r_child:
buf[child.name] = child.get('data', '')
if not tag == 'forecast_conditions':
stored_data[tag] = buf
else:
stored_data[tag].append(buf)
else: # jep, error
stored_data[tag] = r_child.get('data', '')
return stored_data
if __name__ == '__main__':
from pprint import pprint
location = raw_input('Ort/Location: ')
lang = raw_input('Sprache/Language: ')
parsed_xml = get_weather(location, lang)
if not 'problem_cause' in parsed_xml:
pprint(parsed_xml)
else:
print 'Error:', parsed_xml['problem_cause']