@daikikatsuragawa

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

GitHubのリポジトリの40,000件を超えるStarの付与履歴を全て取得したい

解決したいこと

GitHubの特定のリポジトリのStarの付与履歴を全て取得したいと考えています。そこで、GitHubのREST APIを使い、以下のドキュメントを参考に取得を試みました。

ドキュメントからは把握できず、挙動からの推測ではありますが、取得可能なStarの付与履歴は40,000件までのようです。そこで、40,000件を超えるStarの付与履歴を全て取得する方法について相談させていただきたいです。また、GitHubのREST APIによって、取得可能なStarの付与履歴が40,000件までという説明があれば、教えていただきたいです。

発生している問題・エラー

Starの付与履歴の取得スクリプト

import requests

# 対象リポジトリとREST API エンドポイント
# 参考:https://docs.github.com/ja/rest/activity/starring
owner = "pandas-dev"
repo = "pandas"
url = f"https://api.github.com/repos/{owner}/{repo}/stargazers"

# personal access token
# 参考:https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
token = "XXXXXXXXXX"

headers = {
    "Accept": "application/vnd.github.v3.star+json",
    "Authorization": f"token {token}",
}

params = {"per_page": 100, "page": 1}

stargazers = []

while True:
    response = requests.get(url, params=params, headers=headers)
    stargazers += response.json()

    # 次のページが存在する場合、パラメータを更新
    if "next" in response.links.keys():
        params["page"] += 1
    else:
        break

len(stargazers)
取得可能なStarの付与履歴の件数
40000

上記は以下のリポジトリについてのStarの付与履歴ですが、この件数に対して実際のStar数は42k(約42,000)件であり、不足していることが推測されます。

0 likes

1Answer

(1年以上前の質問なので、すでに解決済、あるいは不要になっているかもしれませんが…。1回目ミスったので再投稿でごめんなさい)

REST API ではなく、GraphQL を使うのはいかがでしょうか?
実際に 40,000 件以上の取得を試したわけではありませんが、以下のお試しページ(初回はGitHubのアカウントでサインインが必要。右上の Sign In から)で以下のようなクエリを投げてみました。

ちなみに first: 10 は指定された位置(今回は未指定なので、先頭)から10件の意味で、ソート順( orderBy )はスターを付けた日時( STARRED_AT )の昇順( ASC )です。

その後の項目は取得したい項目だけを記載しています(今回は starredAtnode.login 。また次ページ情報取得のための pageInfo )。必要な情報が他にもあれば、追記する必要があります。

query {
  repository(owner: "pandas-dev", name: "pandas") {
    stargazers(first: 10, orderBy: {field: STARRED_AT, direction: ASC}) {
      edges {
        starredAt
        node {
          login
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

結果(JSON)は以下のような感じ。

{
  "data": {
    "repository": {
      "stargazers": {
        "edges": [
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "sbusso"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "auser"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "pfig"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "ludwig"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "bryanveloso"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "eyecat"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "cosmin"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "mcroydon"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "Rickasaurus"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "babo"
            }
          }
        ],
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "Y3Vyc29yOnYyOpK5MjAxMC0wOC0yNFQxMDozNzozMyswOTowMM4AAvgA"
        }
      }
    }
  }
}

次ページの有無は hasNextPage でわかります。
次ページを取得するには endCursor の値を使って以下のように after に指定します。

query {
  repository(owner: "pandas-dev", name: "pandas") {
    stargazers(first: 10, after: "Y3Vyc29yOnYyOpK5MjAxMC0wOC0yNFQxMDozNzozMyswOTowMM4AAvgA", orderBy: {field: STARRED_AT, direction: ASC}) {
      edges {
        starredAt
        node {
          login
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

結果:

{
  "data": {
    "repository": {
      "stargazers": {
        "edges": [
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "ask"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "bmabey"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "abisani"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "jonpierce"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "mikong"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "cartazio"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "olifante"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "brunojm"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "jackscott"
            }
          },
          {
            "starredAt": "2010-08-24T01:37:33Z",
            "node": {
              "login": "mrflip"
            }
          }
        ],
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "Y3Vyc29yOnYyOpK5MjAxMC0wOC0yNFQxMDozNzozMyswOTowMM4ACDbB"
        }
      }
    }
  }
}

first に指定可能な値は 100 が上限なので、何ページも取得する必要があります。

ちなみに directionDESC を指定すれば、直近のスターを付けた情報も取得可能です。

query {
  repository(owner: "pandas-dev", name: "pandas") {
    stargazers(first: 10, orderBy: {field: STARRED_AT, direction: DESC}) {
      edges {
        starredAt
        node {
          login
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

結果:

{
  "data": {
    "repository": {
      "stargazers": {
        "edges": [
          {
            "starredAt": "2025-07-29T18:04:10Z",
            "node": {
              "login": "TommyLemon"
            }
          },
          {
            "starredAt": "2025-07-29T15:17:13Z",
            "node": {
              "login": "maeno14"
            }
          },
          {
            "starredAt": "2025-07-29T13:11:08Z",
            "node": {
              "login": "MadelineColbert"
            }
          },
          {
            "starredAt": "2025-07-29T12:51:45Z",
            "node": {
              "login": "nikasrmz"
            }
          },
          {
            "starredAt": "2025-07-29T11:38:53Z",
            "node": {
              "login": "ArinaChi"
            }
          },
          {
            "starredAt": "2025-07-29T08:16:57Z",
            "node": {
              "login": "Slav-VL"
            }
          },
          {
            "starredAt": "2025-07-29T07:41:28Z",
            "node": {
              "login": "BaptisteBlouin"
            }
          },
          {
            "starredAt": "2025-07-29T07:31:04Z",
            "node": {
              "login": "KGSbzv"
            }
          },
          {
            "starredAt": "2025-07-29T06:05:45Z",
            "node": {
              "login": "TaeKyungg2"
            }
          },
          {
            "starredAt": "2025-07-29T05:31:02Z",
            "node": {
              "login": "sooolji"
            }
          }
        ],
        "pageInfo": {
          "hasNextPage": true,
          "endCursor": "Y3Vyc29yOnYyOpK5MjAyNS0wNy0yOVQxNDozMTowMiswOTowMM4kRPRb"
        }
      }
    }
  }
}

最初にも言った通り、実際に 40,000 件以上を取得したわけではありませんが、最新の情報も取得できるので、期待はできるかと。

クエリやレスポンスの詳細は GitHub Docs を見るとわかると思います。

import requests

owner = "pandas-dev"
repo = "pandas"

token = "XXXXXXXXXXX"
query = """
query($owner: String!, $repo: String!, $after: String) {
  repository(owner: $owner, name: $repo) {
    stargazers(first: 10, after: $after, orderBy: { field: STARRED_AT, direction: ASC }) {
      edges { starredAt node { login } }
      pageInfo { hasNextPage endCursor }
    }
  }
}
"""
after = None
for i in range(3): # or while True:
    variables = {
        "owner": owner,
        "repo": repo,
        "after": after
    }
    response = requests.post(
        "https://api.github.com/graphql",
        headers={ "Authorization": f"bearer {token}" },
        json={ "query": query, "variables": variables }
    )
    data = response.json()
    # print(data)
    stargazers = data["data"]["repository"]["stargazers"]
    edges = stargazers["edges"]
    for edge in edges:
        print(edge["starredAt"], edge["node"]["login"])

    page_info = stargazers["pageInfo"]
    if not page_info["hasNextPage"]:
        break
    after = page_info["endCursor"]
0Like

Your answer might help someone💌