汇率转换器

"""
一个货币转换器,支持货币汇率实时转换,汇率使用 https://finance.google.cn/finance/converter 谷歌的服务
"""
import unittest
import re
from parameterized import parameterized, param
from app.apis.fliggy.utils import LogManager, RequestClient, decorators, RedisManager
from app import config as app_config


class CurrencyConverter(object):
    _rate_pattern = re.compile('<span class=bld>(\S*?) .*?</span>')
    _redis = None
    _log = LogManager('CurrencyConverter').get_logger_and_add_handlers()

    def __init__(self, from_currency, to_currency='CNY'):
        """
        :param from_currency: 需要被转换的货币
        :param to_currency: 需要兑换成的货币
        """
        self._from_currency = from_currency
        self._to_currency = to_currency
        self._rate = None
        if not self._redis:  # 使用数据库7
            self.__class__._redis = RedisManager(app_config.redis_host, port=app_config.redis_port,
                                                 db=7, password=app_config.redis_password).get_redis()
        self._redis_key_name = 'rate:{}_{}'.format(self._from_currency, self._to_currency)

    @decorators.handle_exception(3)  # 发生错误后重试三次
    def _acquire_rate_from_google_finance(self):
        """从谷歌网站实时请求和解析出汇率"""
        url = 'https://finance.google.cn/finance/converter'
        params = {
            'a': 1,
            'from': self._from_currency,
            'to': self._to_currency,
            'meta': ''
        }
        resp = RequestClient().request_with_proxy('get', url, params=params)
        self._rate = self._rate_pattern.search(resp.text).group(1)

    def get_rate(self):
        """获取汇率,汇率优先使用reids,redis中不存在的汇率则从google实时获取,获取后放入redis中设置1小时过期"""
        if not self._redis.exists(self._redis_key_name):
            self._log.debug('开始从google获取汇率')
            self._acquire_rate_from_google_finance()
            rate = self._rate
            if rate:
                self._redis.set(self._redis_key_name, rate)
                self._redis.expire(self._redis_key_name, 60 * 60)
                return float(rate)
            else:
                self._log.error('从google获取汇率失败')
                raise Exception('从google获取汇率失败')
        else:
            self._log.debug('开始从redis中获取汇率')
            return float(self._redis.get(self._redis_key_name).decode('utf8'))


class _Test(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.log = LogManager('test').get_logger_and_add_handlers()

    @parameterized.expand([param('USD'),
                           param('CNY', to_currency='USD')
                           ])
    def test_from_usd_to_cny(self, from_currency, to_currency='CNY'):
        """
        测试美元和人民币之间的转换
        :return:
        """
        converter = CurrencyConverter(from_currency, to_currency)
        rate = converter.get_rate()
        self.assertIsNotNone(rate, msg='获取的汇率错误')
        self.log.debug('从 {} 转换为 {} 的汇率是 --> {}'.format(from_currency, to_currency, rate))


if __name__ == '__main__':
    unittest.main()

 

posted @ 2018-06-05 16:21  北风之神0509  阅读(724)  评论(0编辑  收藏  举报