(1年以上前の質問なので、すでに解決済、あるいは不要になっているかもしれませんが…。1回目ミスったので再投稿でごめんなさい)
REST API ではなく、GraphQL を使うのはいかがでしょうか?
実際に 40,000 件以上の取得を試したわけではありませんが、以下のお試しページ(初回はGitHubのアカウントでサインインが必要。右上の Sign In から)で以下のようなクエリを投げてみました。
ちなみに first: 10
は指定された位置(今回は未指定なので、先頭)から10件の意味で、ソート順( orderBy
)はスターを付けた日時( STARRED_AT
)の昇順( ASC
)です。
その後の項目は取得したい項目だけを記載しています(今回は starredAt
と node.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 が上限なので、何ページも取得する必要があります。
ちなみに direction
に DESC
を指定すれば、直近のスターを付けた情報も取得可能です。
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"]