1. 从一份榜单到一套可复现的抓取脚本GitHub Trending 页面每天更新但很多人只停留在“刷一眼榜单”的层面。真正有价值的是把榜单变成结构化数据再叠加趋势指标比如单日星标增量、增长率、语言分布、连续上榜天数。这样你才能回答“哪个项目是真的在涨哪个只是历史存量高”这类问题。这篇内容面向想复现 2026 年 2 月 2 日那份热门项目趋势报告的开发者。我会把整条链路拆开用 Python 抓取 GitHub Trending 的当日、本周、本月三个榜单解析出项目名、描述、语言、总星标、当日新增星标再算增长率和排名变化最后输出一份可读的 Markdown 报告。抓取脚本本身不复杂麻烦的是解析规则会随页面结构变化以及多个脚本、多个模型调用之间 Key 管理混乱。所以我会把 TaoToken 作为统一的 Key/API 通道接进来让抓取、摘要、趋势解读走同一个入口配置只维护一份。你需要的环境很轻Python 3.10 以上、requests、beautifulsoup4再加一个能发 HTTP 请求的 Key 通道。下面所有配置和命令都可以直接复制跑完你能得到一份和当日榜单对齐的 JSON 加 Markdown 输出。2. TaoToken 前置统一 Key 与 API 通道TaoToken 在这里扮演的角色是“统一入口”。抓取脚本负责拿原始 HTML解析出结构化字段而项目描述摘要、趋势归因、报告文案生成这些需要模型能力的部分统一走 TaoToken 的 API。这样你不需要在脚本里散落多个厂商的 Key也不用为每个模型单独写一套鉴权逻辑。接入前先确认两件事。第一你已经在控制台创建了 API Key入口在 console 页面创建后复制保存后面写进配置文件。第二确认你要调用的模型名模型列表和对话调试可以在模型对话页面直接试。如果你后面要做长期的编码或 Agent 任务比如让脚本自动迭代解析规则可以看 Coding Plan它更适合持续性的开发场景。配置上我建议分两个文件config.toml放通道和模型参数settings.json放抓取目标和输出选项。这样换模型只改一处抓取逻辑不动。下面给出骨架。2.1 config.toml 骨架# config.toml [channel] # 统一 Key 通道所有模型调用走这里 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从控制台复制别提交到 Git。temperature设低一点趋势解读要稳定不要每次措辞差异太大。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 可能返回空内容。sleep_seconds是礼貌抓取三个榜单之间隔 2 秒避免触发限流。retry设 3 次网络抖动时自动重试。3. 可复制配置抓取与解析脚本抓取部分的核心是解析 Trending 页面的文章卡片。每个项目是一个article.Box-row里面包含仓库名、描述、语言、总星标、当日新增星标。下面这段脚本把三个榜单都抓下来输出统一结构。# 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 三个数组。daily 只保留前 10weekly 和 monthly 保留全部方便后面做交叉分析。3.1 用 TaoToken 生成趋势解读抓取是纯解析不需要模型。但“为什么这个项目涨得快”“语言分布说明了什么”这类归因交给模型更省事。下面这段把 JSON 里的 daily 榜单喂给 TaoToken让它输出一段趋势解读再拼进最终报告。# 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]} | 总星标 {x[total_stars]} | 今日 {x[today_stars]} | 增长率 {x[growth_rate]}% for i, x in enumerate(daily)] prompt 以下是 GitHub Trending 当日 Top 10请用中文写一段 200 字以内的趋势解读重点说增长最快的项目和语言分布\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是否复制完整如果返回 404检查base_url是否写成了带路径的地址。模型名要和你在模型对话里确认的一致。4. 验证请求与成功结果跑完两步后先验证 JSON 结构。打开out/trending_20260202.jsondaily 数组第一条应该包含repo、total_stars、today_stars、growth_rate四个关键字段。以 2026 年 2 月 2 日的数据为例第一条是openclaw/openclaw总星标 145670今日新增 10794增长率约 7.41%。如果你抓到的数字和这个量级接近说明解析规则是对的。再验证模型调用。out/summary.md应该有一段中文解读提到增长最快的项目和语言分布。如果文件为空看终端有没有抛异常。常见的是KeyError: content说明返回结构和你预期的不一样打印resp.text看原始返回。最后做一次端到端校验把 JSON 里的 daily 和 weekly 做交集找出同时出现在两个榜单的项目。这类项目通常不是短期爆发而是有持续热度。你可以用下面这段快速验证。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这类项目说明你的数据抓取和榜单对齐没问题。5. 本篇常见错排查抓取脚本最容易踩的坑是页面结构变化。GitHub Trending 的卡片类名偶尔会调整如果article.Box-row选不到先打印len(soup.select(article))看有没有内容。如果返回 0说明页面没抓到检查User-Agent和网络。第二个坑是星标解析。总星标和今日新增星标在页面上的位置不同今日新增有时带 “stars today” 后缀直接int()会报错。上面的parse_stars已经做了清洗但如果你改了选择器记得同步改清洗逻辑。第三个坑是模型调用超时。timeout设 60 秒如果网络慢可以调到 120。如果频繁超时检查base_url是否可达以及 Key 是否有余额。控制台里能看到用量接入文档里有完整的错误码说明。第四个坑是编码。Windows 下写文件如果不指定encodingutf-8中文会乱码。上面所有open都带了编码参数别删。6. 把脚本变成日常工具这套东西跑通一次不难难的是每天稳定跑。我的做法是把fetch_trending.py和summarize.py串成一个 shell 脚本用 cron 定时执行输出文件按日期命名。Key 放在环境变量里config.toml只留占位符避免泄露。如果你要长期维护解析规则或者让脚本自动适配页面变化可以走 Coding Plan把迭代任务交给持续的编码通道。模型调用和 Key 管理统一在 TaoToken 控制台接入文档里有完整的参数说明。需要调试模型时模型对话页面可以直接试 prompt确认效果再写进脚本。最后提醒一句抓取频率别太高三个榜单之间隔 2 秒是底线。GitHub 对高频请求会限流一旦被限重试也拿不到数据。稳定比快更重要。