12 import sys, re, copy, logging
14 from urllib
import quote_plus
17 from lxml
import html, etree
23 from serverportfolio
import GlobalDicts
27 from serverportfolio
import Utils
30 MULTI_PLUS = re.compile(
r"\+{2,}")
31 MULTI_SPACE = re.compile(
r" {2,}")
35 """Cleans up a uri/url"""
36 url = url.replace(
"\n",
"")
37 return MULTI_PLUS.sub(
"+", url)
40 """Cleans up a query"""
41 query = query.replace(
"\n",
"")
43 query = query.replace(
"\t",
"")
44 query = MULTI_SPACE.sub(
" ", query)
52 __YQL_PUBLIC_URL=
'https://query.yahooapis.com/v1/public/yql?q='
58 super(YahooYQL, self).
__init__(e_action)
60 self.
logger = logging.getLogger(
'SP.YahooYQL')
61 self.logger.debug(
"Constructor Parser_YahooYQL")
69 self.logger.debug(
"create_url")
70 self.logger.debug(
"e_action: %s" % self.
e_action)
71 self.logger.debug(
"local stock: %s", self.
local_stock)
75 print "define query fundamental"
77 use "http://www.datatables.org/yahoo/finance/yahoo.finance.quotes.xml";
78 select * from yahoo.finance.quotes where symbol in (%s)
81 raise ParserError(
"wrong action for YahooYQL %s" % self.e_action.name, \
82 self.local_stock.keys(), self.e_action.name,
'None')
85 query = query % ( str_stocks_yahoo )
88 self.logger.debug(
"query: %s" % query)
89 self.logger.debug(
"encoded query: %s" % quote_plus(query) )
92 self.logger.info(
"url: %s" % self.
url)
98 self.logger.debug(
"YahooYQL::create_url_test")
102 print "query after clean ", query
105 print "encoded: ", quote_plus(query)
107 print "self.url: ", self.
url
114 self.logger.debug(
"parse()")
116 root = etree.fromstring( s )
118 self.logger.debug(
"%s" % etree.tostring(root, pretty_print=
True, encoding=
'unicode'))
125 if self.
e_action == EAction.Fundamental:
128 self.logger.error(
"wrong action in parse: %s" % self.e_action.name )
129 except ParserError
as ex:
130 self.logger.error(
"parse() catch ParserError: %s", ex)
132 except Exception
as ex:
133 self.logger.error(
"parse() catch Exception: %s", ex)
134 raise ParserError(ex, self.local_stock.keys(), self.e_action.name, self.
url)
141 self.logger.debug(
"parse_info()")
155 root = etree.fromstring( s )
157 self.logger.debug(
"%s" % etree.tostring(root, pretty_print=
True, encoding=
'unicode'))
160 for stock_xml
in root[0]:
163 dict_data_stock =
None
165 symbol_yahoo = stock_xml.get(
"symbol")
167 self.logger.debug(
"symbol: %s" % symbol)
173 if elem[
'symbol'] == symbol:
174 dict_data_stock = elem
175 self.logger.debug(
"found symbol in list_return_data break")
181 self.logger.debug(
"symbol not found in dict_return_data, create a new template parser")
183 dict_data_stock = StTmpl.get_template_parser( self.e_action.name )
184 dict_data_stock[
'symbol'] = symbol
185 self.list_return_data.append( dict_data_stock )
193 self.logger.debug(
"parse_fund")
197 for stock_xml
in root[0]:
200 error_code = stock_xml.find(
'ErrorIndicationreturnedforsymbolchangedinvalid').text
201 if error_code !=
None:
202 self.logger.warning(
"error code in YahooYQL:parse_fund %s" % error_code)
206 symbol_yahoo = stock_xml.get(
"symbol")
208 self.logger.debug(
"symbol: %s" % symbol)
210 dict_data_stock = StTmpl.get_template_parser( self.e_action.name )
211 dict_data_stock[
'symbol'] = symbol
214 tmpl_action = dict_data_stock[
'action_templ'][ self.e_action.name ]
219 self.list_return_data.append( dict_data_stock )
226 self.logger.debug(
"Entry run_parser_info")
228 if option_post !=
None:
230 self.logger.debug(
'option_post is present: %s' % option_post)
236 self.logger.error(
"No valid Stock after store_stock_copy")
238 except Exception
as ex:
239 self.logger.debug(
"Caught Exception in store_stock_copy: ex", ex)
244 use "http://www.datatables.org/yahoo/finance/yahoo.finance.stocks.xml";
245 select * from yahoo.finance.stocks where symbol in (%s)
248 query = query % ( str_stocks_yahoo )
253 self.logger.info(
"url: %s" % self.
url)
258 s = UtilsParsers.web_query( self.
url )
260 except QueryError
as ex:
261 self.logger.error(
"Got a QueryError from web_query %s" % ex )
264 except Exception
as ex:
265 self.logger.error(
"Got a general Exception from web_query %s" % ex )
267 raise ParserError( ex, self.local_stock.keys(), self.e_action.name, self.
url )
275 use "http://www.datatables.org/yahoo/finance/quote/yahoo.finance.quote.xml";
276 select * from yahoo.finance.quote where symbol in (%s)
280 query = query % ( str_stocks_yahoo )
284 self.logger.debug(
"query: %s" % query)
285 self.logger.debug(
"encoded query: %s" % quote_plus(query) )
288 self.logger.info(
"url: %s" % self.
url)
292 self.logger.debug(
"web_query")
294 s = UtilsParsers.web_query( self.
url )
295 except Exception
as ex:
296 self.logger.error(
"Got a general Exception from web_query %s" % ex )
298 raise ParserError( ex, self.local_stock.keys(), self.e_action.name, self.
url )
315 self.logger.debug(
"fill_dict_from_xml")
316 self.logger.debug(
"size stock_xml %d" % len(stock_xml) )
319 for elem
in stock_xml:
323 if elem.tag
in dict_stock:
326 dict_stock[ elem.tag ] = elem.text
330 dict_stock[
'other'][ elem.tag ] = elem.text
336 str_stocks_yahoo = str()
338 str_stocks_yahoo +=
'"' + self.
local_stock[stock_symbol].get_action(
'Static',
'code_yahoo') +
'"'
341 str_stocks_yahoo +=
','
344 self.logger.debug(
"string stocks for url:%s",str_stocks_yahoo)
345 return str_stocks_yahoo
360 if __name__ ==
"__main__":
362 print "YahooYQL main"
366 import types, traceback
369 logging.basicConfig(level=logging.DEBUG)
371 logging.getLogger(
'SP')
372 m_logger = logging.getLogger(
"SP.main")
378 m_stock = sys.argv[1]
379 m_action = sys.argv[2]
381 print " Only for debugging, should call ./Run_Parsers for all options"
383 print " YahooYQL FSLR,GSZ Info [-opt_yql]"
384 print " Action: Info / Fundamental"
385 print " optional -opt_yql to run a fixed(hard-coded) sql query and print the XML only, for testing"
389 m_list_stock = m_stock.split(
',')
392 if type(m_action) == types.StringType:
393 m_e_action = EAction[m_action]
396 m_e_action = m_action
398 m_logger.error(
"Exception from EAction enumeration, cannot assign an e_action from action: %s" % m_action)
403 if len(sys.argv) == 4:
404 m_option_sql = sys.argv[3]
407 if m_option_sql ==
'-opt_sql':
409 print "opt_sql ", m_opt_sql
413 print "\n== Test only SQL query"
433 use "http://www.datatables.org/yahoo/finance/quote/yahoo.finance.quote.xml";
434 select * from yahoo.finance.quote where symbol in ("GSZ.PA","FSLR")
437 m_parser.create_url_test( m_query_sql )
438 print "m_parser.url ", m_parser.url
441 m_s = UtilsParsers.web_query( m_parser.url )
443 except PortfolioError
as ex:
444 print "Catch PortfolioError from web_query"
446 print "get_format_string\n", ex.get_format_string()
449 except Exception
as ex:
450 print "Catch exception from web_query"
459 m_root = etree.fromstring( m_s )
461 print(etree.tostring(m_root, pretty_print=
True, encoding=
'unicode'))
470 if m_e_action == EAction.Info:
471 m_parser.run_parser_info( m_list_stock )
473 m_parser.run_parser( m_list_stock )
475 except PortfolioError
as ex:
476 print "Caught PortfolioError from run_parser_info()"
477 print ex.get_format_string()
478 except Exception
as ex:
479 m_logger.debug(
"Caught Exception from store_stock_copy: %s", ex)
483 for stock
in m_list_stock:
484 print Utils.pretty_dict(
DictionaryStocks().get_stocks( stock ).get_action() )
e_action
enumeration (EAction) of the type of query to perform
def _fill_dict_from_xml
Fill a dictionary template from the tags in the XML.
def store_stock_copy
Make a local copy of the Stock objects (linked of the original in DictionaryStocks in fact) into a lo...
def parse
Parse YQL request, always XML format.
Define the global variable StockTemplates.StTmpl and dictionary templates.
def parse_info
Parse XML for info action To get Industry,Sector and Name, this function is called 2 times by run_par...
Define 2 abstract methods which need to be overridden by the Parsers and a generic algorithm (run_pa...
Define custom and specific exceptions for the complete package.
Derived class specific to the parsers.
Define an abstract base class for specific Parsers.
def get_symbol_from_code
Retrieve the symbol (or Stock) from the code_yahoo or code_bourso.
def create_url
Create the URL from a sql query.
Container of all Stocks objects, it also reads the static stocks configuration file "dictstocks...
Global variables for configuration: paths, TCP ports and generic definitions.
url
save url, useful for reporting errors and exceptions
def update_stock
Update the local stocks with the new retrieved data.
def run_parser_info
Specific call to get Info.
def create_url_test
Only for testing, take a full sql query as input(hard-coded in main section)
def parse_fund
Extract fundamental data from the XML root element.
Define singleton class DictionaryStocks, act as the main container of Stocks objects.