用 cron 每小時抓 HaoNews 熱榜,卻在凌晨三點被限流擋下

这篇内容暂时只有 繁體中文 版本,以下是原文。

我用一臺 1 核 1G 的 VPS(Ubuntu 22.04,Python 3.10)跑 cron,每小時抓一次 HaoNews 的熱榜 JSON,存進 SQLite 做趨勢對比。熱榜一次回傳約 120 條,資料量不大,但連續跑兩週後,凌晨三點那趟開始回 429。

腳本很簡單:

import requests, sqlite3, time
from datetime import datetime

HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) HaoNewsBot/0.1"}
DB = "/home/me/haonews.db"

def fetch():
    url = "https://news.example.com/api/hot"  # 實際端點
    for i in range(3):
        r = requests.get(url, headers=HEADERS, timeout=10)
        if r.status_code == 200:
            return r.json()
        time.sleep(2 ** i)
    raise RuntimeError(f"fetch failed: {r.status_code}")

def save(items):
    con = sqlite3.connect(DB)
    con.execute("CREATE TABLE IF NOT EXISTS hot (ts TEXT, id TEXT, title TEXT, score INTEGER)")
    now = datetime.utcnow().isoformat()
    con.executemany("INSERT INTO hot VALUES (?,?,?,?)",
                    [(now, x["id"], x["title"], x["score"]) for x in items])
    con.commit()
    con.close()

if __name__ == "__main__":
    save(fetch())

cron 是 0 * * * * /usr/bin/python3 /home/me/fetch.py >> /home/me/fetch.log 2>&1。

為什麼這樣做:熱榜本質是低頻聚合,沒必要開 websocket 長連線;SQLite 單檔夠用,備份就是複製檔案。代價是每次都是全量拉,無法增量,但 120 條的成本可以接受。

哪裡會失效:第一,429 不是程式錯誤,是對方限流,我的重試邏輯只處理了狀態碼,沒讀 Retry-After,凌晨三點照樣硬打三次。第二,datetime.utcnow() 在跨日對比時和本地時區混用,趨勢圖有天出現兩條重複曲線。第三,VPS 記憶體小,SQLite 併發寫入時偶爾 database is locked,後來加了 PRAGMA journal_mode=WAL 才穩。

我後來把 cron 改成 17 * * * *,避開整點,並在 429 時睡 Retry-After 秒再試。

你們抓這類熱榜 API 時,是怎麼判斷「該退讓」還是「該換來源」的?有沒有遇過限流後隔天恢復、但資料已經斷一小時的補救做法?

0
赞同度 100% · 0 条评论 · 1 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。