:用 TaoToken 統(tǒng)一 Key 跑通數(shù)據(jù)抓取與趨勢腳本)
1. 從一份榜單到一套可復(fù)現(xiàn)的抓取腳本GitHub Trending 頁面每天更新但很多人只停留在“刷一眼榜單”的層面。真正有價值的是把榜單變成結(jié)構(gòu)化數(shù)據(jù)再疊加趨勢指標(biāo)比如單日星標(biāo)增量、增長率、語言分布、連續(xù)上榜天數(shù)。這樣你才能回答“哪個項目是真的在漲哪個只是歷史存量高”這類問題。這篇內(nèi)容面向想復(fù)現(xiàn) 2026 年 2 月 2 日那份熱門項目趨勢報告的開發(fā)者。我會把整條鏈路拆開用 Python 抓取 GitHub Trending 的當(dāng)日、本周、本月三個榜單解析出項目名、描述、語言、總星標(biāo)、當(dāng)日新增星標(biāo)再算增長率和排名變化最后輸出一份可讀的 Markdown 報告。抓取腳本本身不復(fù)雜麻煩的是解析規(guī)則會隨頁面結(jié)構(gòu)變化以及多個腳本、多個模型調(diào)用之間 Key 管理混亂。所以我會把 TaoToken 作為統(tǒng)一的 Key/API 通道接進(jìn)來讓抓取、摘要、趨勢解讀走同一個入口配置只維護(hù)一份。你需要的環(huán)境很輕Python 3.10 以上、requests、beautifulsoup4再加一個能發(fā) HTTP 請求的 Key 通道。下面所有配置和命令都可以直接復(fù)制跑完你能得到一份和當(dāng)日榜單對齊的 JSON 加 Markdown 輸出。2. TaoToken 前置統(tǒng)一 Key 與 API 通道TaoToken 在這里扮演的角色是“統(tǒng)一入口”。抓取腳本負(fù)責(zé)拿原始 HTML解析出結(jié)構(gòu)化字段而項目描述摘要、趨勢歸因、報告文案生成這些需要模型能力的部分統(tǒng)一走 TaoToken 的 API。這樣你不需要在腳本里散落多個廠商的 Key也不用為每個模型單獨寫一套鑒權(quán)邏輯。接入前先確認(rèn)兩件事。第一你已經(jīng)在控制臺創(chuàng)建了 API Key入口在 console 頁面創(chuàng)建后復(fù)制保存后面寫進(jìn)配置文件。第二確認(rèn)你要調(diào)用的模型名模型列表和對話調(diào)試可以在模型對話頁面直接試。如果你后面要做長期的編碼或 Agent 任務(wù)比如讓腳本自動迭代解析規(guī)則可以看 Coding Plan它更適合持續(xù)性的開發(fā)場景。配置上我建議分兩個文件config.toml放通道和模型參數(shù)settings.json放抓取目標(biāo)和輸出選項。這樣換模型只改一處抓取邏輯不動。下面給出骨架。2.1 config.toml 骨架# config.toml [channel] # 統(tǒng)一 Key 通道所有模型調(diào)用走這里 base_url https://taotoken.net/api api_key sk-你的Key timeout 60 [model] # 用于摘要和趨勢解讀的模型 name claude-sonnet-4-5 max_tokens 2048 temperature 0.3 [report] language zh top_n 10 include_weekly true include_monthly truebase_url用 API 地址不要帶多余路徑。api_key從控制臺復(fù)制別提交到 Git。temperature設(shè)低一點趨勢解讀要穩(wěn)定不要每次措辭差異太大。2.2 settings.json 骨架{ targets: { daily: https://github.com/trending?sincedaily, weekly: https://github.com/trending?sinceweekly, monthly: https://github.com/trending?sincemonthly }, headers: { User-Agent: Mozilla/5.0 (compatible; TrendingBot/1.0), Accept-Language: en-US,en;q0.9 }, output: { json_path: ./out/trending_20260202.json, markdown_path: ./out/report_20260202.md }, rate_limit: { sleep_seconds: 2, retry: 3 } }User-Agent必須帶否則 GitHub 可能返回空內(nèi)容。sleep_seconds是禮貌抓取三個榜單之間隔 2 秒避免觸發(fā)限流。retry設(shè) 3 次網(wǎng)絡(luò)抖動時自動重試。3. 可復(fù)制配置抓取與解析腳本抓取部分的核心是解析 Trending 頁面的文章卡片。每個項目是一個article.Box-row里面包含倉庫名、描述、語言、總星標(biāo)、當(dāng)日新增星標(biāo)。下面這段腳本把三個榜單都抓下來輸出統(tǒng)一結(jié)構(gòu)。# fetch_trending.py import json import time import tomllib import requests from bs4 import BeautifulSoup def load_config(): with open(config.toml, rb) as f: return tomllib.load(f) def load_settings(): with open(settings.json, r, encodingutf-8) as f: return json.load(f) def parse_stars(text): # 10,794 - 10794 if not text: return 0 text text.strip().replace(,, ) return int(text) if text.isdigit() else 0 def parse_repo(card): repo_el card.select_one(h2 a) if not repo_el: return None repo repo_el.get(href, ).strip(/) desc_el card.select_one(p) desc desc_el.get_text(stripTrue) if desc_el else lang_el card.select_one([itempropprogrammingLanguage]) lang lang_el.get_text(stripTrue) if lang_el else Unknown star_el card.select_one(a[href$/stargazers]) total_stars parse_stars(star_el.get_text(stripTrue)) if star_el else 0 today_el card.select_one(span.d-inline-block.float-sm-right) today_stars parse_stars(today_el.get_text(stripTrue).split(stars)[0]) if today_el else 0 return { repo: repo, description: desc, language: lang, total_stars: total_stars, today_stars: today_stars, growth_rate: round(today_stars / total_stars * 100, 2) if total_stars else 0.0 } def fetch(url, headers, retry3, sleep2): for i in range(retry): try: resp requests.get(url, headersheaders, timeout30) if resp.status_code 200: return resp.text except requests.RequestException: pass time.sleep(sleep) raise RuntimeError(f抓取失敗: {url}) def main(): cfg load_config() st load_settings() result {} for name, url in st[targets].items(): html fetch(url, st[headers], st[rate_limit][retry], st[rate_limit][sleep_seconds]) soup BeautifulSoup(html, html.parser) cards soup.select(article.Box-row) items [parse_repo(c) for c in cards] items [x for x in items if x] result[name] items[: st[output].get(top_n, 10)] if name daily else items time.sleep(st[rate_limit][sleep_seconds]) with open(st[output][json_path], w, encodingutf-8) as f: json.dump(result, f, ensure_asciiFalse, indent2) print(f已寫入 {st[output][json_path]}) if __name__ __main__: main()運行命令python fetch_trending.py跑完你會得到out/trending_20260202.json里面 daily、weekly、monthly 三個數(shù)組。daily 只保留前 10weekly 和 monthly 保留全部方便后面做交叉分析。3.1 用 TaoToken 生成趨勢解讀抓取是純解析不需要模型。但“為什么這個項目漲得快”“語言分布說明了什么”這類歸因交給模型更省事。下面這段把 JSON 里的 daily 榜單喂給 TaoToken讓它輸出一段趨勢解讀再拼進(jìn)最終報告。# summarize.py import json import tomllib import requests def load_config(): with open(config.toml, rb) as f: return tomllib.load(f) def call_model(cfg, prompt): url f{cfg[channel][base_url]}/v1/messages headers { x-api-key: cfg[channel][api_key], anthropic-version: 2023-06-01, content-type: application/json } payload { model: cfg[model][name], max_tokens: cfg[model][max_tokens], temperature: cfg[model][temperature], messages: [{role: user, content: prompt}] } resp requests.post(url, headersheaders, jsonpayload, timeoutcfg[channel][timeout]) resp.raise_for_status() data resp.json() return data[content][0][text] def main(): cfg load_config() with open(./out/trending_20260202.json, r, encodingutf-8) as f: data json.load(f) daily data[daily] lines [f{i1}. {x[repo]} | {x[language]} | 總星標(biāo) {x[total_stars]} | 今日 {x[today_stars]} | 增長率 {x[growth_rate]}% for i, x in enumerate(daily)] prompt 以下是 GitHub Trending 當(dāng)日 Top 10請用中文寫一段 200 字以內(nèi)的趨勢解讀重點說增長最快的項目和語言分布\n \n.join(lines) text call_model(cfg, prompt) with open(./out/summary.md, w, encodingutf-8) as f: f.write(text) print(text) if __name__ __main__: main()運行python summarize.py如果返回 401檢查api_key是否復(fù)制完整如果返回 404檢查base_url是否寫成了帶路徑的地址。模型名要和你在模型對話里確認(rèn)的一致。4. 驗證請求與成功結(jié)果跑完兩步后先驗證 JSON 結(jié)構(gòu)。打開out/trending_20260202.jsondaily 數(shù)組第一條應(yīng)該包含repo、total_stars、today_stars、growth_rate四個關(guān)鍵字段。以 2026 年 2 月 2 日的數(shù)據(jù)為例第一條是openclaw/openclaw總星標(biāo) 145670今日新增 10794增長率約 7.41%。如果你抓到的數(shù)字和這個量級接近說明解析規(guī)則是對的。再驗證模型調(diào)用。out/summary.md應(yīng)該有一段中文解讀提到增長最快的項目和語言分布。如果文件為空看終端有沒有拋異常。常見的是KeyError: content說明返回結(jié)構(gòu)和你預(yù)期的不一樣打印resp.text看原始返回。最后做一次端到端校驗把 JSON 里的 daily 和 weekly 做交集找出同時出現(xiàn)在兩個榜單的項目。這類項目通常不是短期爆發(fā)而是有持續(xù)熱度。你可以用下面這段快速驗證。import json with open(./out/trending_20260202.json, r, encodingutf-8) as f: data json.load(f) daily {x[repo] for x in data[daily]} weekly {x[repo] for x in data[weekly]} print(日榜與周榜交集:, daily weekly)如果交集里有openclaw/openclaw這類項目說明你的數(shù)據(jù)抓取和榜單對齊沒問題。5. 本篇常見錯排查抓取腳本最容易踩的坑是頁面結(jié)構(gòu)變化。GitHub Trending 的卡片類名偶爾會調(diào)整如果article.Box-row選不到先打印len(soup.select(article))看有沒有內(nèi)容。如果返回 0說明頁面沒抓到檢查User-Agent和網(wǎng)絡(luò)。第二個坑是星標(biāo)解析。總星標(biāo)和今日新增星標(biāo)在頁面上的位置不同今日新增有時帶 “stars today” 后綴直接int()會報錯。上面的parse_stars已經(jīng)做了清洗但如果你改了選擇器記得同步改清洗邏輯。第三個坑是模型調(diào)用超時。timeout設(shè) 60 秒如果網(wǎng)絡(luò)慢可以調(diào)到 120。如果頻繁超時檢查base_url是否可達(dá)以及 Key 是否有余額。控制臺里能看到用量接入文檔里有完整的錯誤碼說明。第四個坑是編碼。Windows 下寫文件如果不指定encodingutf-8中文會亂碼。上面所有open都帶了編碼參數(shù)別刪。6. 把腳本變成日常工具這套東西跑通一次不難難的是每天穩(wěn)定跑。我的做法是把fetch_trending.py和summarize.py串成一個 shell 腳本用 cron 定時執(zhí)行輸出文件按日期命名。Key 放在環(huán)境變量里config.toml只留占位符避免泄露。如果你要長期維護(hù)解析規(guī)則或者讓腳本自動適配頁面變化可以走 Coding Plan把迭代任務(wù)交給持續(xù)的編碼通道。模型調(diào)用和 Key 管理統(tǒng)一在 TaoToken 控制臺接入文檔里有完整的參數(shù)說明。需要調(diào)試模型時模型對話頁面可以直接試 prompt確認(rèn)效果再寫進(jìn)腳本。最后提醒一句抓取頻率別太高三個榜單之間隔 2 秒是底線。GitHub 對高頻請求會限流一旦被限重試也拿不到數(shù)據(jù)。穩(wěn)定比快更重要。