汇率转换器
""" 一个货币转换器,支持货币汇率实时转换,汇率使用 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()
反对极端面向过程编程思维方式,喜欢面向对象和设计模式的解读,喜欢对比极端面向过程编程和oop编程消耗代码代码行数的区别和原因。致力于使用oop和36种设计模式写出最高可复用的框架级代码和使用最少的代码行数完成任务,致力于使用oop和设计模式来使部分代码减少90%行,使绝大部分py文件最低减少50%-80%行的写法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」