将该请求放入一个追加写入文件的小脚本,并用 cron 每天运行一次:每天拉取黄金和 USD/IDR 共 2 次请求,每月约 62 次。每日数值带有 00:00 UTC 的时间戳,因此请在 UTC 午夜之后运行。
用 API 定时拉取数据
金价请求和汇率请求使用同一个 Narwhal API 密钥。脚本带着 Authorization: Bearer YOUR_KEY 请求头把每个请求发送到 https://api.narwhalapi.com,然后将返回的值追加到 daily.csv。该文件会同时保留拉取时间、以美元计的金价和 USD/IDR 汇率。
- 把密钥放进环境文件 获取一个免费密钥,把
export NARWHAL_API_KEY=...写入~/.narwhal.env。将该文件的权限设为600,这样只有你能读取;定时执行的命令会在启动 Python 之前先加载这个文件。 - 保存每日拉取脚本 将其保存为
/home/me/daily_pull.py。当daily.csv是新文件时,脚本会先写入列名;请求成功后,再追加一行包含run_at_utc、xau_usd和usd_idr的数据。#!/usr/bin/env python3 """Append today's gold price and USD/IDR rate to daily.csv. Run it once a day.""" import csv, os, pathlib from datetime import datetime, timezone import requests API = "https://api.narwhalapi.com/v1" H = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} gold = requests.get(f"{API}/commodities/spot/XAU/USD", headers=H, timeout=10) fx = requests.get( f"{API}/fx/rates/USD", params={"currencies": "IDR"}, headers=H, timeout=10 ) gold.raise_for_status() # a failed run exits non-zero, so cron mail or your monitor sees it fx.raise_for_status() path = pathlib.Path("daily.csv") new = not path.exists() with path.open("a", newline="") as f: w = csv.writer(f) if new: w.writerow(["run_at_utc", "xau_usd", "usd_idr"]) w.writerow( [ datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), gold.json()["price"], fx.json()["rates"][0]["rate"], ] ) - 添加每日 cron 条目 在 UTC 服务器上,用这条 crontab 条目把拉取安排在 UTC 午夜之后。它从环境文件读取密钥,并把脚本的输出和错误写入
/home/me/daily_pull.log。15 1 * * * . $HOME/.narwhal.env && /usr/bin/python3 /home/me/daily_pull.py >> /home/me/daily_pull.log 2>&1
每个请求的超时时间为 10 秒。脚本从响应的 price 字段读取金价,从 rates 中的 rate 字段读取 USD/IDR,并把两个值写入同一行。之后的每次拉取都是追加到文件中,只有文件是新建时才写入列标题。
crontab 中写入环境文件的路径,密钥则保留在 NARWHAL_API_KEY 中。Narwhal 的各个数据 API 共用一个账户、一个 API 密钥和一份余额,因此定时的黄金和汇率请求都从该余额中扣费。响应带有 X-RateLimit-Remaining,表示剩余的速率限制额度。
run_at_utc 列记录脚本写入该行的时间,请将其视为拉取时间。每日数值带有 00:00 UTC 的时间戳,因此把文件追加安排在 UTC 午夜之后,可使每日任务与数据采用相同的时间基准。
不写代码安排流程
每日流程可以由 n8n 的 Schedule Trigger、Make 的“Schedule”或 Zapier 的“Schedule by Zapier”启动。用 Google Sheets 的追加行来保存结果。如果你希望把数值放进电子表格而不是脚本的 CSV 文件,这就是每日拉取的表格去向。
定时触发器每天启动该流程;追加行会保存该次拉取的结果。请使时间与 UTC 保持一致,因为每日数值带有 00:00 UTC 的时间戳。定时流程与脚本遵循相同的每日时间安排,调度和存储都在流程中处理。
对于定时运行的脚本,其他调度方式还有 Windows 的任务计划程序、macOS 的 launchd 或云端调度器。每天的任务仍然是金价请求和 USD/IDR 请求。请选择与脚本运行位置相匹配的调度器;没有服务器时,则使用定时流程。
不同情况应选哪种方法
| 情况 | 最合适的方法 | 原因 |
|---|---|---|
| 始终开机的服务器或笔记本电脑 | cron | 在那台机器上运行每日脚本 |
| 没有服务器 | 按计划运行的 n8n、Make 或 Zapier | 启动每日流程并将结果追加到 Google Sheets |
| 数据随事件而非时间变化 | Webhook | 通过基于事件的方式接收数据 |
cron 使用哪个时区?
cron 使用服务器的时区。用 date 查看服务器时间,并使用 UTC 以便与数据一致。这条 crontab 条目假定服务器使用 UTC,其“午夜之后”的执行时间也取决于该时区。
外汇日汇率带有 00:00 UTC 的时间戳。该时间戳与脚本的 run_at_utc 列表示不同的时间:日汇率有其数据时间戳,而 CSV 记录的是拉取时间。商品和外汇价格为实时,因此每一行保存的是脚本运行那一刻的价格。
如果某天的运行失败了怎么办?
请求失败时,脚本以非零状态码退出,并且不会追加任何内容。只有两个请求都成功后,脚本才会打开 daily.csv 追加该行。因此请求失败的那次运行,不会在文件中留下记录。
cron 邮件或监控工具可以发现非零退出状态。请增加告警,或在失败后重新运行脚本;大宗商品价格提醒是相关的提醒教程。该 cron 条目还会把输出和错误写入命令中指定的日志文件。
对于请求限制类错误,请区分带有 Retry-After 的 429 rate_limit_exceeded 与需要等到你充值后才能解决的 402 insufficient_credits。定时拉取中的这部分处理,请参阅缓存与 429 处理。错误响应使用 application/problem+json,包含 status、code、detail 和 request_id。
计算示例:一个月的每日拉取
每次每日拉取都要计入金价请求和 USD/IDR 请求,再乘以当月的天数。每天 2 个请求、共 31 天,脚本一共调用 62 次,按每 1,000 次 $2 计算,约为 $0.12。
| 计算 | 结果 |
|---|---|
| 金价请求加 USD/IDR 请求 | 每天 2 个请求 |
| 2 个请求 × 31 天 | 62 个请求 |
| 62 × $2 ÷ 1,000 | 约 $0.12 |
2026 年 10 月 24 日,拉取时间为 2026-10-24T12:17:15Z 的一行中,金价为 3996.00 USD,USD/IDR 为 18107.8。在 CSV 中,拉取时间排在最前,随后按表头设定的顺序依次是金价和汇率。
run_at_utc,xau_usd,usd_idr
2026-10-24T12:17:15Z,3996.00,18107.8发布于。