Update Weather.wunder to use BeautifulSoup. Remove the #! line and add a

__contributors__ line.
This commit is contained in:
James Vega 2004-09-19 21:14:43 +00:00
parent 3e44335f28
commit c873d0eabb

View File

@ -1,5 +1,3 @@
#!/usr/bin/env python
### ###
# Copyright (c) 2002-2004, Jeremiah Fincher # Copyright (c) 2002-2004, Jeremiah Fincher
# All rights reserved. # All rights reserved.
@ -34,14 +32,23 @@ This plugin does weather-related stuff. It can't change the weather, though,
so don't get your hopes up. We just report it. so don't get your hopes up. We just report it.
""" """
__revision__ = "$Id$" import supybot
import supybot.plugins as plugins __revision__ = "$Id$"
__contributors__ = {
supybot.authors.jamessan: ['cnn', 'wunder',
'temperatureUnit configuration variable',
'convert configuration variable'],
supybot.authors.jemfinch: ['weather'],
supybot.authors.bwp: ['ham'],
}
import re import re
import sets import sets
import urllib import urllib
import BeautifulSoup
import supybot.conf as conf import supybot.conf as conf
import supybot.utils as utils import supybot.utils as utils
import supybot.webutils as webutils import supybot.webutils as webutils
@ -84,9 +91,13 @@ class Weather(callbacks.Privmsg):
the name of 'weather' which should override this help.""" the name of 'weather' which should override this help."""
weatherCommands = ['ham', 'cnn', 'wunder'] weatherCommands = ['ham', 'cnn', 'wunder']
threaded = True threaded = True
def __init__(self):
self.__parent = super(Weather, self)
self.__parent.__init__()
def callCommand(self, name, irc, msg, *L, **kwargs): def callCommand(self, name, irc, msg, *L, **kwargs):
try: try:
super(Weather, self).callCommand(name, irc, msg, *L, **kwargs) self.__parent.callCommand(name, irc, msg, *L, **kwargs)
except webutils.WebError, e: except webutils.WebError, e:
irc.error(str(e)) irc.error(str(e))
@ -338,36 +349,9 @@ class Weather(callbacks.Privmsg):
else: else:
irc.error('Could not find weather information.') irc.error('Could not find weather information.')
_wunderUrl = 'http://www.weatherunderground.com/' \ _wunderUrl = 'http://mobile.wunderground.com/cgi-bin/' \
'cgi-bin/findweather/getForecast?query=' 'findweather/getForecast?query='
_wunderLoc = re.compile(r'<title>[^:]+: ([^<]+)</title>', re.I | re.S) _wunderLoc = re.compile(r'Page (.+?) Forecast</title>', re.I | re.S)
_wunderFTemp = re.compile(
r'graphics/conds.*?<nobr><b>(-?\d+)</b>&nbsp;(&#176;)(F)</nobr>',
re.I | re.S)
_wunderCond = re.compile(r'</b></font><br>\s+<font size=-1><b>([^<]+)</b>',
re.I | re.S)
_wunderHumid = re.compile(r'Humidity:</td><td[^>]+><b>(\d+%)</b>',
re.I | re.S)
_wunderDew = re.compile(r'Dew Point:</td><td[^>]+><b>\s+<nobr><b>'
r'(-?\d+)</b>&nbsp;(&#176;)(F)</nobr>',
re.I | re.S)
_wunderHeat = re.compile(
r'HeatIndex:</td><td[^>]+><b>\s+<nobr><b>(\d+)</b>&nbsp;([^F]+)(F)<',
re.I | re.S)
_wunderWind = re.compile(
r'Wind:</td><td[^>]+>\s+<b>\s+<nobr><b>(\d+)</b>&nbsp;(mph)'
r'</nobr>\s+/\s+<nobr><b>(\d+)</b>&nbsp;(km/h)</nobr>\s+</b>'
r'\s+from the\s+<b>(\w{3})</b>', re.I | re.S)
_wunderPressure = re.compile(
r'Pressure:</td><td[^<]+><b>\s+<b>(\d+\.\d+)</b>&nbsp;(in)\s+/\s+'
r'<b>(\d+)</b>&nbsp;(hPa)', re.I | re.S)
_wunderVisible = re.compile(
r'Visibility:</td><td[^>]+><b>\s+<nobr><b>([\w.]+)</b>&nbsp;(miles)'
r'</nobr>\s+/\s+<nobr><b>([\w.]+)</b>&nbsp;(kilometers)</nobr>',
re.I | re.S)
_wunderUv = re.compile(r'UV:</td><td[^>]+><b>(\d\d?)</b>( out of \d\d?)',
re.I | re.S)
_wunderTime = re.compile(r'Updated:\s+<b>([\w\s:,]+)</b>', re.I | re.S)
_wunderMultiLoc = re.compile(r'<a href="([^"]+)', re.I | re.S) _wunderMultiLoc = re.compile(r'<a href="([^"]+)', re.I | re.S)
def wunder(self, irc, msg, args): def wunder(self, irc, msg, args):
"""<US zip code | US/Canada city, state | Foreign city, country> """<US zip code | US/Canada city, state | Foreign city, country>
@ -376,74 +360,75 @@ class Weather(callbacks.Privmsg):
""" """
loc = ' '.join(args) loc = ' '.join(args)
url = '%s%s' % (self._wunderUrl, urllib.quote(loc)) url = '%s%s' % (self._wunderUrl, urllib.quote(loc))
text = webutils.getUrl(url) # Caught in callCommand. text = webutils.getUrl(url)
if 'Search not found' in text: if 'Search not found' in text:
irc.error(noLocationError, Raise=True) irc.error(noLocationError, Raise=True)
if 'Search results for' in text: if 'Click on a city name' in text:
text = text[text.index('Search results for'):] soup = BeautifulSoup.BeautifulSoup()
newloc = self._wunderMultiLoc.search(text) soup.feed(text)
newloc = soup.first('a').get('href')
if newloc is None: if newloc is None:
irc.error('Multiple locations found. ' irc.error('Multiple locations found. '
'Please be more specific.', Raise=True) 'Please be more specific.', Raise=True)
url = 'http://www.wunderground.com%s' % newloc.group(1) url = 'http://mobile.wunderground.com%s' % newloc
try: text = webutils.getUrl(url)
text = webutils.getUrl(url) soup.close()
except webutils.WebError, e: soup = BeautifulSoup.BeautifulSoup()
irc.error(str(e), Raise=True) soup.feed(text)
# Get the table with all the weather info
table = soup.first('table', {'border':'1'})
trs = table.fetch('tr')
try:
time = trs.pop(0).first('b').string
except AttributeError:
time = ''
info = {}
def isText(t):
return not isinstance(t,BeautifulSoup.NavigableText) and t.contents
def getText(t):
s = getattr(t, 'string', None)
if s is None:
t = t.contents
num = t[0].string
units = t[1].string
# htmlToText strips leading whitespace, so we have to handle
# strings with &nbsp; differently.
if units.startswith('&nbsp;'):
units = utils.htmlToText(units)
s = ' '.join((num, units))
else:
units = utils.htmlToText(units)
s = ' '.join((num, units[0], units[1:]))
return s
for tr in trs:
k = tr.first('td').string
v = filter(isText, tr.fetch('td')[1].contents)
value = map(getText, v)
info[k] = ' '.join(value)
location = self._wunderLoc.search(text) location = self._wunderLoc.search(text)
temp = self._wunderFTemp.search(text) temp = info['Temperature']
convert = self.registryValue('convert', msg.args[0]) convert = self.registryValue('convert', msg.args[0])
if location and temp: if location and temp:
location = location.group(1) (temp, deg, unit) = temp.split()
location = location.replace(' Forecast', '')
(temp, deg, unit) = temp.groups()
if convert: if convert:
temp = self._getTemp(int(temp), deg, unit, msg.args[0]) temp = self._getTemp(int(temp), deg, unit, msg.args[0])
else: else:
temp = deg.join((temp, unit)) temp = deg.join((temp, unit))
time = self._wunderTime.search(text) resp = ['The current temperature in %s is %s (%s).' %\
if time is not None: (location.group(1), temp, time)]
time = ' (%s)' % time.group(1) conds = info['Conditions']
resp.append('Conditions: %s.' % info['Conditions'])
humidity = info['Humidity']
resp.append('Humidity: %s.' % info['Humidity'])
(dew, deg, unit) = info['Dew Point'].split()
if convert:
dew = self._getTemp(int(dew), deg, unit, msg.args[0])
else: else:
time = '' dew = deg.join((dew, unit))
resp = ['The current temperature in %s is %s%s.' %\ resp.append('Dew Point: %s.' % dew)
(location, temp, time)] resp.append('Wind: %s at %s %s.' % tuple(info['Wind'].split()))
heat = self._wunderHeat.search(text) resp.append('Pressure: %s.' % info['Pressure'])
if heat is not None: resp.append('Visibility: %s.' % info['Visibility'])
(heat, deg, unit) = map(str.strip, heat.groups())
if convert:
heat = self._getTemp(int(heat), deg, unit, msg.args[0])
resp.append('Heat Index: %s.' % heat)
conds = self._wunderCond.search(text)
if conds is not None:
resp.append('Conditions: %s.' % conds.group(1))
humidity = self._wunderHumid.search(text)
if humidity is not None:
resp.append('Humidity: %s.' % humidity.group(1))
dewpt = self._wunderDew.search(text)
if dewpt is not None:
(dew, deg, unit) = dewpt.groups()
if convert:
dew = self._getTemp(int(dew), deg, unit, msg.args[0])
else:
dew = deg.join((dew, unit))
resp.append('Dew Point: %s.' % dew)
wind = self._wunderWind.search(text)
if wind is not None:
resp.append('Wind: %s at %s %s (%s %s).' % (wind.group(5),
wind.group(1),
wind.group(2),
wind.group(3),
wind.group(4)))
press = self._wunderPressure.search(text)
if press is not None:
resp.append('Pressure: %s %s (%s %s).' % press.groups())
vis = self._wunderVisible.search(text)
if vis is not None:
resp.append('Visibility: %s %s (%s %s).' % vis.groups())
uv = self._wunderUv.search(text)
if uv is not None:
resp.append('UV: %s%s' % uv.groups())
resp = map(utils.htmlToText, resp) resp = map(utils.htmlToText, resp)
irc.reply(' '.join(resp)) irc.reply(' '.join(resp))
else: else: