rate.py
2.2 KB| 1 | #!/usr/bin/env python3 |
| 2 | # 汇率查询(Frankfurter / ECB 免费 API,无需 Key) |
| 3 | import argparse, json, sys, urllib.parse, urllib.request |
| 4 | |
| 5 | BASE = 'https://api.frankfurter.dev/v1' |
| 6 | |
| 7 | |
| 8 | def fetch(path): |
| 9 | url = BASE + path |
| 10 | req = urllib.request.Request(url, headers={'User-Agent': 'exchange-rate-skill/1.0'}) |
| 11 | with urllib.request.urlopen(req, timeout=15) as r: |
| 12 | return json.loads(r.read().decode()) |
| 13 | |
| 14 | |
| 15 | def fmt(v): |
| 16 | s = f'{v:.4f}' |
| 17 | return s.rstrip('0').rstrip('.') if '.' in s else s |
| 18 | |
| 19 | |
| 20 | def main(): |
| 21 | p = argparse.ArgumentParser(description='汇率查询') |
| 22 | p.add_argument('base', help='基准货币 ISO 代码,如 USD') |
| 23 | p.add_argument('symbol', nargs='?', help='目标货币 ISO 代码,如 CNY') |
| 24 | p.add_argument('amount', nargs='?', type=float, help='金额(默认 1)') |
| 25 | p.add_argument('--date', help='历史日期 YYYY-MM-DD(默认今日)') |
| 26 | p.add_argument('--list', action='store_true', help='列出支持的货币代码') |
| 27 | a = p.parse_args() |
| 28 | |
| 29 | if a.list: |
| 30 | data = fetch('/currencies') |
| 31 | cur = data.get('currencies', data) |
| 32 | codes = sorted(cur.keys()) |
| 33 | print(f'支持 {len(codes)} 种货币:{" ".join(codes)}') |
| 34 | return |
| 35 | |
| 36 | if not a.symbol: |
| 37 | p.error('需要目标货币,或用 --list 查看支持列表') |
| 38 | return |
| 39 | base = a.base.upper() |
| 40 | symbol = a.symbol.upper() |
| 41 | amount = a.amount if a.amount is not None else 1.0 |
| 42 | |
| 43 | try: |
| 44 | if a.date: |
| 45 | data = fetch(f'/{a.date}?base={base}&symbols={symbol}') |
| 46 | else: |
| 47 | data = fetch(f'/latest?base={base}&symbols={symbol}') |
| 48 | except urllib.error.HTTPError as e: |
| 49 | body = e.read().decode()[:200] |
| 50 | print(f'查询失败({e.code}):{body}') |
| 51 | sys.exit(1) |
| 52 | except Exception as e: |
| 53 | print(f'查询失败: {e}') |
| 54 | sys.exit(1) |
| 55 | |
| 56 | rates = data.get('rates', {}) |
| 57 | if symbol not in rates: |
| 58 | print(f'货币 {symbol} 不在支持列表(--list 查看)') |
| 59 | sys.exit(1) |
| 60 | rate = rates[symbol] |
| 61 | date = data.get('date', a.date or '今日') |
| 62 | print(f'{base} → {symbol}({date})') |
| 63 | print(f'1 {base} = {fmt(rate)} {symbol}') |
| 64 | if amount != 1: |
| 65 | print(f'{amount:g} {base} = {amount * rate:,.2f} {symbol}') |
| 66 | |
| 67 | |
| 68 | if __name__ == '__main__': |
| 69 | main() |
文件内容是平台检查时读出的文本,只供查看。平台不会运行包里的任何脚本或程序。

