I used yahoo and then a google package but both had issues, so I modified 
my script to pull from finance.google.com. The json appeared to be broken 
so I used regex to extract price and date.

On Tuesday, November 7, 2017 at 8:36:25 AM UTC-6, Jim Robinson wrote:
>
> Hi Folks,
>
> Does anyone here have an alternative to the yahoo finance api for pulling 
> daily pricedb values?
>
> Looks like folks were abusing the yahoo site and they've shut down the 
> service.
>
> I could just plug in the data manually, but having an api I could kick off 
> periodically to pull down the dozen or so symbols was much nicer.
>
>
> Jim
>
>

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"Ledger" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
#!/usr/bin/env python

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import argparse
import re
import sys
from datetime import datetime

from dateutil.relativedelta import relativedelta

import requests

quote_url = 'https://finance.google.com/finance?q={}&output=json'

field_regex_pattern = r'"{}"\s*:\s*"([^"]+)"'
price_field_regex = re.compile(field_regex_pattern.format('nav_prior'))
date_field_regex = re.compile(field_regex_pattern.format('nav_time'))

date_regex_pattern = r'([A-Za-z]+)\s*([0-9]+),'
date_parts_regex = re.compile(date_regex_pattern)


def download(price_file=None):

    symbols = [
        'blah1',   # your stuff
        'blah2',   # your stuff
    ]

    for symbol in symbols:
        response = requests.get(quote_url.format(symbol))
        if response.status_code == 200:
            try:
                the_date, the_price = get_quote_data(response)
            except Exception as e:
                print('Error loading {}: {}'.format(symbol, e))
                continue
        else:
            print('Error downloading {symbol}. Received code {code}.'.format(
                symbol=symbol,
                code=response.status_code
            ))
            continue

        print('{date:12} {inv:8}   ${price}'.format(
            date=the_date,
            inv=symbol,
            price=the_price
        ))

        if price_file:
            with open(price_file, 'a') as the_file:
                the_file.write('P {date} {inv:10} ${price}\n'.format(
                    date=the_date,
                    inv=symbol,
                    price=the_price
                ))


def get_quote_data(response):
    # google finance json appears to be broken, so will use crude string stuff
    data = response.content[6:-2].decode('unicode_escape')
    the_price = regex_search(data, price_field_regex, 'price')
    the_date = regex_search(data, date_field_regex, 'date')
    return get_date(the_date), the_price


def regex_search(data, regex, label):
    match = regex.search(data)
    if match:
        return match.groups()[0]
    else:
        raise Exception("Couldn't find {}.".format(label))


def get_date(quote_date):
    last_month_abbreviated = (
        datetime.now() + relativedelta(months=-1)
    ).strftime('%b')

    date_parts_match = date_parts_regex.search(quote_date)
    if date_parts_match:
        quote_month_abbreviated = date_parts_match.groups()[0]
        quote_day = date_parts_match.groups()[1]
    else:
        raise Exception("Couldn't parse date parts.")

    if (quote_month_abbreviated == last_month_abbreviated
            and last_month_abbreviated == 'Dec'):
        quote_year = (datetime.now() + relativedelta(years=-1)).strftime('%Y')
    else:
        quote_year = datetime.now().strftime('%Y')

    # date seems to come back a day off, e.g. 6/15/17 instead of 6/16/17,
    # so we'll add 1
    the_date = datetime.strptime(
        '{} {} {}'.format(quote_month_abbreviated, quote_day, quote_year),
        '%b %d %Y'
    ) + relativedelta(days=1)
    return the_date.strftime('%Y/%m/%d')


class ArgHandler(object):

    @staticmethod
    def get_args(args):
        parser = argparse.ArgumentParser()

        parser.add_argument(
            '-f', '--file',
            type=str,
            help='save to this prices db file',
        )
        return parser.parse_args(args)


def main(argv=None):  # pragma: no cover

    if argv is None:
        argv = sys.argv[1:]

    args = ArgHandler.get_args(argv)

    download(args.file)


if __name__ == '__main__':  # pragma: no cover
    sys.exit(main())

Reply via email to