每天定时拉取数据

将该请求放入一个追加写入文件的小脚本,并用 cron 每天运行一次:每天拉取黄金和 USD/IDR 共 2 次请求,每月约 62 次。每日数值带有 00:00 UTC 的时间戳,因此请在 UTC 午夜之后运行。

用 API 定时拉取数据

金价请求和汇率请求使用同一个 Narwhal API 密钥。脚本带着 Authorization: Bearer YOUR_KEY 请求头把每个请求发送到 https://api.narwhalapi.com,然后将返回的值追加到 daily.csv。该文件会同时保留拉取时间、以美元计的金价和 USD/IDR 汇率。

  1. 把密钥放进环境文件 获取一个免费密钥,把 export NARWHAL_API_KEY=... 写入 ~/.narwhal.env。将该文件的权限设为 600,这样只有你能读取;定时执行的命令会在启动 Python 之前先加载这个文件。
  2. 保存每日拉取脚本 将其保存为 /home/me/daily_pull.py。当 daily.csv 是新文件时,脚本会先写入列名;请求成功后,再追加一行包含 run_at_utc、xau_usd 和 usd_idr 的数据。
    Python:将金价和 USD/IDR 追加到 CSV
    #!/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"],
            ]
        )
  3. 添加每日 cron 条目 在 UTC 服务器上,用这条 crontab 条目把拉取安排在 UTC 午夜之后。它从环境文件读取密钥,并把脚本的输出和错误写入 /home/me/daily_pull.log。
    UTC 服务器上的每日 cron 条目
    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 中,拉取时间排在最前,随后按表头设定的顺序依次是金价和汇率。

2026 年 10 月 24 日的 CSV 行
run_at_utc,xau_usd,usd_idr
2026-10-24T12:17:15Z,3996.00,18107.8

发布于。

后续步骤