Re: Help with a Python Program

  • From: Jim Dunleavy <jim.dunleavy@xxxxxx>
  • To: programmingblind@xxxxxxxxxxxxx
  • Date: Wed, 08 Oct 2008 17:17:08 +0100

Hi,

I use the BeautifulSoup library from www.crummy.com.
The API is much more concise than calling those long-winded DOM
functions.
e.g.
cond = tree.find('yweather:condition')
result = '%s, %s' % (cond['temp'], cond['text'])

Or if you want speed, check out the lxml package and xpath.

--Jim

----- Original Message ----- 
From: Ken Perry 
To: programmingblind@xxxxxxxxxxxxx 
Sent: Wednesday, October 08, 2008 5:11 AM
Subject: RE: Help with a Python Program


 
 
Just a hint on this code you can speed it up  a heck of a lot if you get away 
from dom and use sax or the simple template parser in python.  Its not that 
important to speed up on a PC but I am currently coding on a PDA and this runs 
a bit slow do to the interpreter and the dom.
 
Ken



--------------------------------------------------------------------------------
From: programmingblind-bounce@xxxxxxxxxxxxx 
[mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of BlueScale
Sent: Monday, October 06, 2008 10:39 PM
To: programmingblind@xxxxxxxxxxxxx
Subject: RE: Help with a Python Program


Hi,
Thanks for responding.  I actually just finished writing my own.  I never did 
get that code shrunk down to size, so I visited the Yahoo developer site and 
read through the documentation and code samples.  It took a lot of trial and 
error, but I finally got it working!  I also learned a little more about Python 
in the process.
If anyone else would like the code, here it is:
#change zipCode to your zip code
zipCode = 0
def getWeather(zip_code):
  if zip_code != 0:
    import urllib
    from xml.dom import minidom
    WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss?p=%s'
    WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0'
    url = WEATHER_URL % zip_code
    dom = minidom.parse(urllib.urlopen(url))
    ycondition = dom.getElementsByTagNameNS(WEATHER_NS, 'condition')[0]
    weatherReport = ycondition.getAttribute('temp') + ' | ' + 
ycondition.getAttribute('text')
  else:
    weatherReport = "No zip code set."
  return weatherReport
print getWeather(zipCode)


     

On Mon, 2008-10-06 at 22:28 -0500, Ken Perry wrote: 
  This is pretty easy to do.  Unfortunately I am extremely busy right this 
minute.  However if no one gets to you till Wednesday I will get to it.  
  Ken 



------------------------------------------------------------------------------

  From: programmingblind-bounce@xxxxxxxxxxxxx 
[mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of BlueScale
  Sent: Sunday, October 05, 2008 10:39 PM
  To: programmingblind@xxxxxxxxxxxxx
  Subject: Help with a Python Program





  Hi,
  I found this program to get the weather with a commandline program.  I want 
to modify it for use inside another program, but every time I do anything to it 
I end up breaking it.  I am still very new at Python.  I would like it 
simplified quite a bit.  All I need is a variable set at the top with a 5 digit 
zipcode, so it is easy to modify.  I would like it to only return the current 
temp followed by the current condition.  For example, when ran it should return 
something like 78F | cloudy.  I need to remove the extended forecast and the 
commandline arguments.  Can someone please help with this and send me some info 
on how it was done? I thought it would be easy to do but apparently I was 
wrong. *grin*  It would be even better if the whole program could be simplified 
down to one function, but I am not sure that will be possible.
  Thanks for the help, and here is the code:
  #! /usr/bin/python

  """
  Fetches weather reports from Yahoo!

  Written by Thomas Upton (http://thomas.fiveuptons.com/),
  with contributions from Chris Lasher (http://igotgenes.blogspot.com/).

  This code is licensed under a BY-NC-SA Creative Commons license.
  http://creativecommons.org/licenses/by-nc-sa/3.0/us/
  """

  import sys
  import urllib
  from optparse import OptionParser
  from xml.dom.minidom import parse

  # Yahoo!'s limit on the number of days they will forecast for
  DAYS_LIMIT = 2
  WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss?p=%s'
  WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0'

  def get_weather(zip_code, days):
    """
    Fetches weather report from Yahoo!

    :Parameters:
    -`zip_code`: A five digit US zip code.
    -`days`: number of days to obtain forecasts for

    :Returns:
    -`weather_data`: a dictionary of weather data

    """

    # Get the correct weather url.
    url = WEATHER_URL % zip_code

    # Parse the XML feed.
    dom = parse(urllib.urlopen(url))

    # Get the units of the current feed.
    yunits = dom.getElementsByTagNameNS(WEATHER_NS, 'units')[0]

    # Get the location of the specified zip code.
    ylocation = dom.getElementsByTagNameNS(WEATHER_NS, 'location')[0]

    # Get the currrent conditions.
    ycondition = dom.getElementsByTagNameNS(WEATHER_NS, 'condition')[0]

    # Hold the forecast in a hash.
    forecasts = []

    # Walk the DOM in order to find the forecast nodes.
    for i, node in enumerate(
            dom.getElementsByTagNameNS(WEATHER_NS,'forecast')):
        # Stop if the number of obtained forecasts equals the number of 
requested days
        if i + 1 > days:
            break
        else:
            # Insert the forecast into the forcast dictionary.
            forecasts.append (
                {
                    'date': node.getAttribute('date'),
                    'low': node.getAttribute('low'),
                    'high': node.getAttribute('high'),
                    'condition': node.getAttribute('text')
                }
            )

    # Return a dictionary of the weather that we just parsed.
    weather_data = {
        'current_condition': ycondition.getAttribute('text'),
        'current_temp': ycondition.getAttribute('temp'),
        'forecasts': forecasts,
        'units': yunits.getAttribute('temperature'),
        'city': ylocation.getAttribute('city'),
        'region': ylocation.getAttribute('region'),
    }
    
    return weather_data

  def create_report(weather_data, options):
    """
    Constructs a weather report as a string.

    :Parameters:
    -`weather_data`: a dictionary of weather data
    -`options`: options to determine output selections

    :Returns:
    -`report_str`: a formatted string reporting weather

    """

    report = []
    
    if options.location:
        if options.verbose:
            # Add the location header.
            report.append("Location:")

        # Add the location.
        location_string = "%(city)s, %(region)s\n" % weather_data
        report.append(location_string)

    if (not options.nocurr):
        if options.verbose:
            # Add current conditions header.
            report.append("Current conditions:")

        # Add the current weather.
        currstr = "%(current_temp)s%(units)s | %(current_condition)s \n" % 
weather_data
        report.append(currstr)

    if (options.forecast > 0):
      if options.verbose:
          # Add the forecast header.
          report.append("Forecast:")

      # Add the forecasts.
      for forecast in weather_data['forecasts']:
        
          forecast['units'] = weather_data['units']
        
          forecast_str = """\
    %(date)s
      Low: %(low)s%(units)s
      High: %(high)s%(units)s
      Condition: %(condition)s
    """ % forecast

          report.append(forecast_str)

    report_str = "\n".join(report)
    
    return report_str

  def create_cli_parser():
    """Creates a command line interface parser."""

    usage = (
        "%prog [options] zip_code",
        __doc__,
        """\
  Arguments:
    ZIPCODE: The ZIP code for the region of interest.
  """
    )
    
    usage = "\n\n".join(usage)
    
    cli_parser = OptionParser(usage)
    
    # Add the CLI options
    cli_parser.add_option('-c', '--nocurr', action='store_true',
        help="Suppress reporting the current weather conditions"
    )
    
    cli_parser.add_option('-f', '--forecast', action='store', type='int',
        help="Show the forecast for DAYS days", metavar="DAYS")
    
    cli_parser.add_option('-l', '--location', action='store_true',
        help="Give the location of the weather"
    )
    
    cli_parser.add_option('-v', '--verbose', action='store_true',
        help="Print the weather section headers"
    )
    
    cli_parser.set_defaults(forecast=0)

    return cli_parser

  def main(argv):

    # Create the command line parser.
    cli_parser = create_cli_parser()
    
    # Get the options and arguments.
    opts, args = cli_parser.parse_args(argv)

    # Check that an argument was passed.
    if len(args) < 1:
        cli_parser.error("Not enough arguments supplied.")

    # Check the zip code
    zip_code = args[0]
    
    if len(zip_code) != 5 or not zip_code.isdigit():
        cli_parser.error("ZIP code must be 5 digits")
    
    if opts.forecast > DAYS_LIMIT or opts.forecast < 0:
       cli_parser.error("Days to forecast must be between 0 and %d" % 
DAYS_LIMIT)

    # Get the weather.
    weather = get_weather(zip_code, opts.forecast)

    # Create the report.
    report = create_report(weather, opts)

    print report

  if __name__ == "__main__":
    main(sys.argv[1:]) 
----------------------------------------------------------------------------
"Information in this email (including attachments) is confidential.  
It is intended for receipt and consideration only by the intended recipient.
If you are not an addressee or intended recipient, any use, dissemination,
distribution, disclosure, publication or copying of information contained in
this email is strictly prohibited.  Opinions expressed in this email may be
personal to the author and are not necessarily the opinions of the HSE.

If this email has been received by you in error we would be grateful if you 
could immediately notify the ICT Service Desk by telephone at +353 1 6352757 
or by email to service.desk@xxxxxxxxxxxx and thereafter delete this
e-mail from your system"
----------------------------------------------------------------------------

Other related posts: