0Pricing
AI Agents · 课时

GitHub REST API 概览

PyGitHub 库、个人访问令牌和 API 速率限制。

GitHub REST API 概览 是 CoddyKit 上的免费 AI Agents 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Agents 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Agents 课程共包含 4 节课。

PyGitHub — Python GitHub 客户端

PyGitHub 是最流行的 Python GitHub REST 接口库。它用表示仓库、问题、PR、提交和用户的 Python 对象封装了原始 HTTP 接口。几乎所有 GitHub 自动化任务都从 Github(token=) 和 g.get_repo() 开始。

# Install: pip install PyGitHub
from github import Github
import os

# Authenticate with a personal access token
g = Github(token=os.environ['GITHUB_TOKEN'])

# Get the authenticated user
user = g.get_user()
print(f'Logged in as: {user.login}')
print(f'Name: {user.name}')
print(f'Public repos: {user.public_repos}')

# Get a specific repository
repo = g.get_repo('octocat/Hello-World')
print(f'Repo: {repo.full_name}')
print(f'Stars: {repo.stargazers_count}')

身份验证:个人访问令牌

最简单的身份验证方式是个人访问令牌(PAT)——一种与您的 GitHub 账户关联的长期有效令牌。请在 github.com → 设置 → 开发者设置 → 个人访问令牌中创建令牌。请将其存储在环境变量中,绝不要直接写入代码。为了提高安全性,请使用细粒度 PAT,并将其限制到特定仓库。

from github import Github, Auth
import os

# Method 1: Classic token (works with PyGitHub)
token = os.environ['GITHUB_TOKEN']
g = Github(token=token)

# Method 2: Auth object (recommended for PyGitHub >= 1.59)
auth = Auth.Token(os.environ['GITHUB_TOKEN'])
g = Github(auth=auth)

# Test authentication
try:
    user = g.get_user()
    print(f'Authenticated as {user.login}')
except Exception as e:
    print(f'Auth failed: {e}')
    print('Check: Is GITHUB_TOKEN set? Has it expired?')

g.close()  # close the connection when done

GitHub 应用身份验证

对于生产环境中的代理,推荐使用GitHub 应用而不是 PAT。GitHub 应用具有细粒度权限,可以安装到指定仓库,并使用会自动轮换的短期安装令牌。请使用 github.GithubIntegration 生成安装令牌。

import os
import github

APP_ID = os.environ['GITHUB_APP_ID']
PRIVATE_KEY = os.environ['GITHUB_APP_PRIVATE_KEY']  # PEM content
INSTALLATION_ID = os.environ['GITHUB_INSTALLATION_ID']

# Create GitHub App client
auth = github.Auth.AppAuth(APP_ID, PRIVATE_KEY)
gi = github.GithubIntegration(auth=auth)

# Get installation access token (expires in 1 hour)
installation = gi.get_installation(int(INSTALLATION_ID))
access_token = gi.get_access_token(int(INSTALLATION_ID))

# Use the token with a standard Github client
g = github.Github(token=access_token.token)
print(f'App authenticated, token expires: {access_token.expires_at}')

速率限制:每小时 5,000 次请求

对于经过身份验证的用户,GitHub REST 接口允许每小时 5,000 次请求。每次接口调用(包括分页调用)都会计入限制。在运行批量操作前,请检查剩余配额——如果配额用尽,在速率限制重置前,所有请求都会返回 403 Forbidden。

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])

# Check current rate limit status
rate_limit = g.get_rate_limit()
core = rate_limit.core

print(f'Remaining: {core.remaining}/{core.limit} requests')
print(f'Resets at: {core.reset}')

# Calculate time until reset
import datetime
now = datetime.datetime.utcnow()
reset_in = (core.reset.replace(tzinfo=None) - now).seconds
print(f'Reset in: {reset_in // 60}m {reset_in % 60}s')

# Check before heavy operations
if core.remaining < 100:
    print('WARNING: Rate limit nearly exhausted!')

获取仓库对象

repo 对象是几乎所有 GitHub 操作的起点。请使用 g.get_repo('owner/name') 获取它。它包含元数据(星标数、复刻数、描述和可见性),以及用于访问问题、PR、提交、发布版本等内容的方法。

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

# Repository metadata
print(f'Full name: {repo.full_name}')
print(f'Description: {repo.description}')
print(f'Default branch: {repo.default_branch}')
print(f'Stars: {repo.stargazers_count}')
print(f'Forks: {repo.forks_count}')
print(f'Open issues: {repo.open_issues_count}')
print(f'Private: {repo.private}')
print(f'Language: {repo.language}')
print(f'Created: {repo.created_at}')
print(f'Last push: {repo.pushed_at}')

接口分页 — PaginatedList

返回大量项目(问题、提交、PR)的 GitHub 接口调用会返回一个 PaginatedList。您可以像遍历普通列表一样遍历它——PyGitHub 会在遍历过程中自动获取后续页面。不过,对 PaginatedList 调用 len() 会获取所有页面,可能产生较高开销。

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

# PaginatedList: fetch pages lazily as you iterate
issues = repo.get_issues(state='open')  # returns PaginatedList

# Iterate — fetches pages 30 at a time automatically
for issue in issues:
    print(f'#{issue.number}: {issue.title}')

# Get first N items without fetching everything
first_10 = list(issues[:10])  # only fetches first page

# Count (WARNING: fetches ALL pages)
total_open = issues.totalCount  # uses the count from API metadata, not iteration

处理速率限制异常

超过速率限制时,PyGitHub 会引发 github.GithubException.RateLimitExceededException。请检查重置时间,并休眠到限制重置为止。您可以将此逻辑加入重试封装器,使任何 GitHub 调用都具备韧性。

from github import Github
from github.GithubException import RateLimitExceededException
import os
import time
import datetime

g = Github(token=os.environ['GITHUB_TOKEN'])

def github_call_with_rate_limit(func, *args, **kwargs):
    while True:
        try:
            return func(*args, **kwargs)
        except RateLimitExceededException:
            rate_limit = g.get_rate_limit()
            reset_time = rate_limit.core.reset.replace(tzinfo=None)
            now = datetime.datetime.utcnow()
            wait_seconds = (reset_time - now).total_seconds() + 10

            print(f'Rate limit exceeded. Sleeping {wait_seconds:.0f}s until reset...')
            time.sleep(max(wait_seconds, 1))

# Usage
repo = github_call_with_rate_limit(
    g.get_repo, 'myorg/myrepo'
)

跨 GitHub 搜索

使用 g.search_issues()、g.search_repositories() 和 g.search_code(),即可在所有公开仓库(以及您有权访问的私有仓库)中执行 GitHub 搜索。这些调用使用搜索接口,该接口单独施加每分钟 30 次请求的速率限制。

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])

# Search issues across all your repos
results = g.search_issues(
    query='is:open is:issue label:bug user:myorg',
    sort='created',
    order='desc'
)

print(f'Found {results.totalCount} open bugs')
for issue in results[:10]:
    print(f'{issue.repository.full_name}#{issue.number}: {issue.title}')

# Search for repos using a specific package
repos = g.search_repositories(
    query='topic:machine-learning language:python stars:>100'
)
for repo in repos[:5]:
    print(f'{repo.full_name}: {repo.stargazers_count} stars')

处理多个仓库

代理通常需要在组织中的多个仓库之间执行操作。请使用 g.get_organization() 列出组织中的所有仓库,然后在循环中逐一处理。您可以按语言、是否已归档或活跃日期进行筛选,以避免处理不活跃的仓库。

from github import Github
import os
import datetime

g = Github(token=os.environ['GITHUB_TOKEN'])
org = g.get_organization('myorg')

# Get all active Python repos
cutoff = datetime.datetime.now() - datetime.timedelta(days=180)

active_repos = [
    repo
    for repo in org.get_repos(type='all')
    if (
        not repo.archived
        and repo.language == 'Python'
        and repo.pushed_at
        and repo.pushed_at.replace(tzinfo=None) > cutoff
    )
]

print(f'Active Python repos: {len(active_repos)}')
for repo in active_repos[:5]:
    print(f'  {repo.name}: last push {repo.pushed_at.date()}')

从仓库读取文件内容

使用 repo.get_contents(path) 可以读取仓库中的任意文件。内容采用 base64 编码,但 PyGitHub 会通过 .decoded_content 属性自动解码。请通过 ref 参数指定分支或提交 SHA。

from github import Github
import os

g = Github(token=os.environ['GITHUB_TOKEN'])
repo = g.get_repo('myorg/myrepo')

# Read a file from the default branch
contents = repo.get_contents('README.md')
readme_text = contents.decoded_content.decode('utf-8')
print(f'README ({len(readme_text)} chars):')
print(readme_text[:200])

# Read from a specific branch
requirements = repo.get_contents(
    'requirements.txt',
    ref='feature/new-deps'
)
deps = requirements.decoded_content.decode('utf-8')
print('Dependencies:', deps[:300])

常见 GitHub 异常的错误处理

PyGitHub 会针对所有接口错误引发 GithubException。常见子类包括:UnknownObjectException(404——找不到仓库或问题)、BadCredentialsException(401——令牌无效)和 RateLimitExceededException(403——超出速率限制)。请始终针对性地捕获这些异常。

from github import Github
from github.GithubException import (
    GithubException, UnknownObjectException,
    BadCredentialsException, RateLimitExceededException
)
import os

g = Github(token=os.environ['GITHUB_TOKEN'])

def get_repo_safely(repo_full_name):
    try:
        return g.get_repo(repo_full_name)
    except BadCredentialsException:
        print('ERROR: GitHub token is invalid or expired')
        return None
    except UnknownObjectException:
        print(f'ERROR: Repo not found: {repo_full_name}')
        print('Check: typo in name? Private repo you can\'t access?')
        return None
    except RateLimitExceededException:
        print('ERROR: GitHub rate limit exceeded, retry later')
        return None
    except GithubException as e:
        print(f'GitHub API error {e.status}: {e.data}')
        return None

快速检查:速率限制

测试您对 GitHub 接口速率限制的理解。

GitHub REST 接口回顾

现在您可以使用 PyGitHub 连接到 GitHub:

  • 使用 Github(token=) 或 Github(auth=Auth.Token(...)) 进行 PAT 身份验证
  • 对于具有细粒度权限的生产环境代理,使用带有 GithubIntegration 的 GitHub 应用
  • 速率限制:每小时 5,000 次请求;使用 g.get_rate_limit() 检查;处理 RateLimitExceededException
  • PaginatedList:延迟遍历;使用 .totalCount 获取数量而无需获取所有页面
  • g.get_repo('owner/name')——仓库级操作的入口点
  • 明确捕获 UnknownObjectException(404)和 BadCredentialsException(401)

常见问题解答

「GitHub REST API 概览」课时是免费的吗?

是的 — 「GitHub REST API 概览」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Agents 课程的其余内容,请升级到 CoddyKit PRO。 AI Agents 课程共包含 4 节课。

「GitHub REST API 概览」这节课中我会学到什么?

PyGitHub 库、个人访问令牌和 API 速率限制。 你通过在浏览器中直接运行的动手代码来练习 AI Agents,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Agents 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Agents 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「GitHub REST API 概览」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Agents 课中编写并运行代码吗?

能。每节 AI Agents 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. GitHub REST API 概览
  2. 列出与管理问题
  3. 自动化 PR 审查评论
  4. 提交历史与差异分析
← 返回 AI Agents