🚀

用 Python + GitHub API 搭建自动监控仓库更新并推送通知的工具

不用每天手动刷 GitHub,写一个脚本自动监控你关注的仓库,有新提交、新 Release 或新 Issue 时立即推送到微信/邮件/Telegram。

👁️ - 次阅读

你有没有这种情况:关注了好几个 GitHub 项目,想跟踪它们的动态,但每天手动刷太麻烦,刷多了又怕漏掉重要的更新。

或者你维护了几个私有仓库,想第一时间知道有没有人提 Issue、有没有新 Release、有没有新 Commit。

手动盯 GitHub 太累了,让脚本帮你盯。

这个项目用 Python + GitHub API,实现一个轻量级的仓库更新监控工具。有新动态时,自动推送到你的微信、邮件或 Telegram。

项目背景

GitHub 官方有 Watch 功能,但通知太杂:每个 commit、每个 PR、每个 Issue 都会发邮件,三天不看邮箱就爆炸了。

我们需要的是:只推送真正重要的更新——新 Release、高星 PR、关键 Issue,而且推送到我们常用的渠道(微信/Telegram/飞书)。

用 GitHub REST API 查询最新状态,跟本地记录对比,有变化就推送。全程自动化,一行命令搞定。

技术选型

组件选型理由
语言Python 3.10+生态丰富,GitHub API 库成熟
APIGitHub REST API v3稳定、文档完善、无需 OAuth 即可读公开仓库
存储JSON 文件零依赖,记录每个仓库的最后状态
推送微信/邮件/Telegram按偏好配置,支持多选
调度cron / systemd timer每 30 分钟检查一次

不需要数据库,不需要服务器,一个 Python 脚本 + 一个定时任务就够了。

实现步骤

第一步:安装依赖

pip install pygithub requests

只装两个包。pygithub 操作 GitHub API,requests 做推送。

第二步:准备配置文件

在项目目录下创建 config.json:

{
  "repositories": [
    {
      "name": "facebook/react",
      "channels": ["wechat", "telegram"],
      "notify": {"release": true, "issue": true, "star": true}
    },
    {
      "name": "vercel/next.js",
      "channels": ["telegram"],
      "notify": {"release": true, "issue": false, "star": false}
    }
  ],
  "push": {
    "wechat_webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY",
    "telegram_bot_token": "YOUR_BOT_TOKEN",
    "telegram_chat_id": "YOUR_CHAT_ID",
    "email_smtp": "smtp.qq.com",
    "email_user": "your@qq.com",
    "email_password": "YOUR_APP_PASSWORD",
    "email_to": "your@qq.com"
  },
  "interval_minutes": 30
}

按需填写。公开仓库不需要 Token,私有仓库需要 GitHub Personal Access Token,加到配置里即可。

第三步:写监控脚本

创建 monitor.py:

#!/usr/bin/env python3
"""GitHub 仓库更新监控工具"""
import json
import time
import requests
from pathlib import Path
from datetime import datetime

# ============ 配置加载 ============
CONFIG_PATH = Path(__file__).parent / "config.json"
STATE_PATH = Path(__file__).parent / "state.json"

def load_config():
    with open(CONFIG_PATH) as f:
        return json.load(f)

def load_state():
    if STATE_PATH.exists():
        with open(STATE_PATH) as f:
            return json.load(f)
    return {}

def save_state(state):
    with open(STATE_PATH, "w") as f:
        json.dump(state, f, indent=2)

# ============ GitHub API 查询 ============
GITHUB_TOKEN = ""  # 私有仓库时填写 Personal Access Token
HEADERS = {"Authorization": f"token {GITHUB_TOKEN}"} if GITHUB_TOKEN else {}

def get_latest_release(repo_name):
    url = f"https://api.github.com/repos/{repo_name}/releases/latest"
    resp = requests.get(url, headers=HEADERS, timeout=10)
    if resp.status_code == 200:
        return resp.json()["tag_name"]
    return None

def get_open_issues_count(repo_name):
    url = f"https://api.github.com/search/issues?q=repo:{repo_name}+is:open+is:issue"
    resp = requests.get(url, headers=HEADERS, timeout=10)
    if resp.status_code == 200:
        return resp.json()["total_count"]
    return None

def get_stargazers_count(repo_name):
    url = f"https://api.github.com/repos/{repo_name}"
    resp = requests.get(url, headers=HEADERS, timeout=10)
    if resp.status_code == 200:
        return resp.json()["stargazers_count"]
    return None

# ============ 推送函数 ============
def push_wechat(webhook_url, text):
    payload = {
        "msgtype": "text",
        "text": {"content": text}
    }
    requests.post(webhook_url, json=payload, timeout=10)

def push_telegram(bot_token, chat_id, text):
    url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
    requests.post(url, json={"chat_id": chat_id, "text": text}, timeout=10)

def push_email(smtp_server, user, password, to, subject, body):
    import smtplib
    from email.mime.text import MIMEText
    msg = MIMEText(body, "plain", "utf-8")
    msg["Subject"] = subject
    msg["From"] = user
    msg["To"] = to
    with smtplib.SMTP(smtp_server, 587) as s:
        s.starttls()
        s.login(user, password)
        s.sendmail(user, [to], msg.as_string())

def send_notifications(repo_name, changes, push_config):
    lines = [f"🔔 GitHub 仓库更新: {repo_name}"]
    for change in changes:
        lines.append(f"  • {change}")
    text = "\n".join(lines)

    if "wechat" in push_config.get("channels", []):
        webhook = push_config.get("wechat_webhook")
        if webhook:
            push_wechat(webhook, text)

    if "telegram" in push_config.get("channels", []):
        token = push_config.get("telegram_bot_token")
        chat_id = push_config.get("telegram_chat_id")
        if token and chat_id:
            push_telegram(token, chat_id, text)

    if "email" in push_config.get("channels", []):
        smtp = push_config.get("email_smtp")
        user = push_config.get("email_user")
        pwd = push_config.get("email_password")
        to = push_config.get("email_to")
        if smtp and user:
            push_email(smtp, user, pwd, to, f"[GitHub] {repo_name} 有更新", text)

# ============ 主逻辑 ============
def check_repos():
    config = load_config()
    state = load_state()
    push_cfg = config["push"]

    for repo in config["repositories"]:
        repo_name = repo["name"]
        notify = repo.get("notify", {})
        changes = []

        # 初始化 state
        if repo_name not in state:
            state[repo_name] = {}

        # 检查 Release
        if notify.get("release", True):
            current_release = get_latest_release(repo_name)
            last_release = state[repo_name].get("release")
            if current_release and current_release != last_release:
                changes.append(f"🎉 新 Release: {current_release}")
                state[repo_name]["release"] = current_release

        # 检查 Issue
        if notify.get("issue", True):
            current_issues = get_open_issues_count(repo_name)
            last_issues = state[repo_name].get("issues", 0)
            if current_issues is not None and current_issues > last_issues:
                changes.append(f"📝 新增 {current_issues - last_issues} 个 Issue")
                state[repo_name]["issues"] = current_issues

        # 检查 Star
        if notify.get("star", False):
            current_stars = get_stargazers_count(repo_name)
            last_stars = state[repo_name].get("stars", 0)
            if current_stars is not None and current_stars > last_stars:
                changes.append(f"⭐ 新增 {current_stars - last_stars} 个 Star")
                state[repo_name]["stars"] = current_stars

        # 推送
        if changes:
            print(f"[{datetime.now()}] {repo_name}: {changes}")
            send_notifications(repo_name, changes, {**repo, **push_cfg})
        else:
            print(f"[{datetime.now()}] {repo_name}: 无更新")

    save_state(state)

if __name__ == "__main__":
    check_repos()

第四步:设置定时任务

用 cron 每 30 分钟运行一次:

# 编辑 crontab
crontab -e

# 添加这一行(每30分钟执行)
*/30 * * * * /usr/bin/python3 /home/youruser/github-monitor/monitor.py >> /home/youruser/github-monitor/monitor.log 2>&1

或者用 systemd timer(更优雅):

# /etc/systemd/system/github-monitor.service
[Unit]
Description=GitHub Repo Monitor
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /home/youruser/github-monitor/monitor.py
WorkingDirectory=/home/youruser/github-monitor
# /etc/systemd/system/github-monitor.timer
[Unit]
Description=Run GitHub Monitor every 30 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=30min
Unit=github-monitor.service
[Install]
WantedBy=timers.target
sudo systemctl enable --now github-monitor.timer

第五步:推送渠道配置

企业微信机器人:在企业微信群设置 → 群机器人 → 添加机器人 → 复制 Webhook 地址填入配置。

Telegram Bot:找 @BotFather 创建 bot,拿到 Token;创建群组把 bot 加进去,拿到 Chat ID(用 @userinfobot 查)。

邮件推送:QQ 邮箱开启 SMTP 服务,获取授权码作为 email_password。

运行效果

脚本启动后,每分钟检查一次配置的仓库:

[2026-08-21 10:00:01] facebook/react: 无更新
[2026-08-21 10:30:02] facebook/react: 无更新
[2026-08-21 11:00:01] vercel/next.js: 无更新
[2026-08-21 11:30:02] facebook/react: ['🎉 新 Release: v19.0.0', '⭐ 新增 1200 个 Star']

有新 Release 时,你的企业微信群会收到:

🔔 GitHub 仓库更新: facebook/react • 🎉 新 Release: v19.0.0 • ⭐ 新增 1200 个 Star

简洁明了,没有噪音。

优化方向

已经能用了,想继续加也可以:

  1. 支持 GitHub Event Webhook:主动接收推送,不用轮询,更实时
  2. 支持 PR 监控:有合并请求时推送,方便代码审查
  3. 支持 Fork 监控:有人 Fork 你的仓库时通知
  4. 加一个简单的 Web 仪表盘:用 Flask 搭个页面,查看所有监控仓库的状态
  5. 支持多语言通知:根据仓库语言自动选择通知文案
  6. 加入 AI 摘要:用大模型对 Release Note 生成中文摘要,更适合国内用户
  7. 支持 Discord/Slack/飞书:扩展更多推送渠道

一行 Python 脚本,半小时搞定,以后再也不用手动刷 GitHub 了。你关注哪些仓库?要不要加个监控?

这篇文章对你有帮助吗?