Tony Wang5 min readHow to Scrape GitHub Repos, Users & Trending in 2026 (API & Python)
Scrape GitHub repos, users, stars, contributors, and trending data in 2026 — DIY Python, the rate-limited official API, or a structured API returning JSON.
The fastest way to scrape GitHub in 2026 is to call a structured API that returns normalized JSON — repositories, users, organizations, contributors, stargazers, language breakdowns, releases, and trending — instead of burning through the official API's hourly quota or parsing github.com's client-rendered pages. GitHub is unusual in this series: it has a genuinely capable official API, so the real question is when the rate limits make scraping the better choice. This guide covers all three approaches, what each returns, where each breaks, and the legal basics.
Why scrape GitHub?
Public GitHub data drives a whole category of developer, recruiting, and market work:
- Developer sourcing & recruiting — find and rank users by language, location, and contribution history.
- Open-source dependency & competitor tracking — watch stars, forks, releases, and contributor churn on the projects you depend on or compete with.
- Tech-trend & market research — track trending repos and languages to see where the ecosystem is moving.
- Developer relations & outreach — build targeted lists of maintainers and stargazers of relevant projects.
- AI / LLM pipelines — feed repo metadata, READMEs, and release notes into retrieval and analysis workflows.
Is it legal to scrape GitHub?
Option 1: DIY in Python (and why it breaks)
Most DIY starts with the official REST API via requests (or PyGithub):
import requests
h = {"Authorization": "Bearer YOUR_GH_TOKEN", "Accept": "application/vnd.github+json"}
repo = requests.get("https://api.github.com/repos/torvalds/linux", headers=h).json()
contributors = requests.get("https://api.github.com/repos/torvalds/linux/contributors",
headers=h, params={"per_page": 100}).json()
It works for small pulls, then hits walls:
- The rate-limit quota. Unauthenticated requests are capped at 60/hour per IP; a token raises core to 5,000/hour. Analyzing 1,000 repos with ~5 calls each (detail, contributors, languages, releases, stargazers) burns the entire hourly quota in a single scan.
- Search is stricter and capped. The Search API runs at ~30 requests/minute and returns at most 1,000 results per query — so you can't page past the first 1,000 matches, no matter how many exist.
- Secondary rate limits. Bursty or concurrent requests trip abuse-detection limits with
403s andRetry-After, so you need backoff and careful concurrency. - HTML parsing is worse. Dropping to
requests+BeautifulSoupon github.com hits client-side rendering and frequent layout drift, and still trips the same anti-bot defenses.
Option 2: No-code tools
Visual extractors and marketplace "GitHub" actors export CSV/JSON and suit one-off pulls, but they're awkward in an in-product pipeline with predictable fields, and they inherit the same rate-limit and pagination caps.
Option 3: A structured GitHub API
For repeatable workflows, a structured GitHub API returns normalized JSON with no token juggling or backoff to manage. Search, then enrich:
curl "https://api.crawlora.net/api/v1/github/search/repositories?q=web+scraping&sort=stars" \
-H "x-api-key: $CRAWLORA_API_KEY"
In Python — repos are addressed by owner/repo, users by login:
import requests
h = {"x-api-key": "YOUR_API_KEY"}
base = "https://api.crawlora.net/api/v1"
# 1) Search repositories (paginated: page / per_page)
hits = requests.get(f"{base}/github/search/repositories", headers=h,
params={"q": "web scraping", "sort": "stars", "per_page": 50}).json()["data"]
# 2) Full detail for one repo
repo = requests.get(f"{base}/github/repo/torvalds/linux", headers=h).json()["data"]
Search returns a total count plus paginated items (fields are illustrative — check the docs):
{
"code": 200,
"msg": "OK",
"data": {
"total_count": 18742,
"items": [
{ "full_name": "torvalds/linux", "owner": "torvalds", "language": "C", "stars": 180000, "forks": 53000, "topics": ["kernel", "linux"], "license": "GPL-2.0" }
]
}
}
The same key reaches contributors, stargazers, languages, releases, users, and trending:
contributors = requests.get(f"{base}/github/repo/torvalds/linux/contributors", headers=h,
params={"per_page": 100}).json()["data"] # login, contributions
langs = requests.get(f"{base}/github/repo/torvalds/linux/languages", headers=h).json()["data"] # bytes per language
user = requests.get(f"{base}/github/user/torvalds", headers=h).json()["data"] # name, company, followers
trending = requests.get(f"{base}/github/trending", headers=h,
params={"language": "python", "since": "daily"}).json()["data"] # stars_today
Pass page/per_page to walk contributors and stargazers, language/since for trending, store one row per repo or user, and re-pull on a schedule to track stars, releases, and contributor churn over time.
What you can collect
- Repositories — name, full_name, owner, description, language, topics, stars, forks, watchers, open_issues, license, default_branch, pushed_at.
- Repo graph — contributors (login, contributions), stargazers, forks, language byte breakdown, and releases (tag_name, name, published_at, author).
- Search — repositories and users, each with total_count and paginated items.
- Users & orgs — profile (login, name, company, location, blog, followers, public_repos, social_accounts), a user's or org's public repos, and a user's recent public events and pinned repos.
- Trending — trending repositories (with stars_today) and trending developers, by language and time window.
Everything is public GitHub data — stick to public, factual fields.
Limitations and common challenges
- The official API rate limits are the real blocker. 60/hour unauthenticated, 5,000/hour with a token, and search at ~30/minute capped to 1,000 results — a structured API absorbs the throttling and token management behind one key.
- Search caps at 1,000 results. No endpoint pages past the first 1,000 matches for a query; narrow the query (by language, stars, or date) to shard large result sets.
- Some lists are truncated. GitHub caps contributor and similar lists, so very large repos won't return every contributor — plan around the cap.
- Profiles contain personal data. Names, companies, locations, and linked social accounts are personal under GDPR/CCPA — collect public, factual fields with a lawful basis.
Where this gets used
- Developer sourcing — rank users by language, location, and contribution history for recruiting or dev-rel.
- Company & tech enrichment — map an org's repos, languages, and release cadence. See the company data enrichment use case.
- OSS trend tracking — watch trending repos and languages to spot where the ecosystem is moving.
Sources
Start collecting
Try it first, free: run any public URL through the Free Web Scraper, or check whether a site blocks bots with the Anti-Bot Checker — no signup.
Test the endpoints in the Playground, check the schema in the API docs, and review pricing. Repos are only part of the story — how to scrape Product Hunt covers where those open-source projects launch and get discovered, and how to scrape job postings covers the developer hiring demand sitting next to the code itself. See also how to choose a web scraping API and is web scraping legal.
Part of our how-to-scrape guide series — every platform we cover, in one index.
Frequently asked questions
Can I scrape GitHub without getting blocked?
Public repos and profiles are scrapable, but GitHub's official API rate-limits hard — 60 requests/hour unauthenticated, 5,000/hour with a token — search caps at 1,000 results, and bursty requests trip secondary limits with 403s. A structured API absorbs the throttling, backoff, and token management behind one key. Collect only public, factual fields.
Does GitHub have an official API?
Yes — a capable REST and GraphQL API. But it's rate-limited (60/hour unauthenticated, 5,000/hour with a token), and the Search API runs at about 30 requests/minute and returns at most 1,000 results per query, so scanning thousands of repos or users exhausts the quota fast. That's when a structured scraping API is the better choice.
How are GitHub repos and users addressed?
Repositories by owner/repo (for example torvalds/linux), users by login, and organizations by name. Search returns matching items with a total_count, and every detail endpoint — contributors, stargazers, languages, releases — takes those identifiers.
What GitHub data can I collect?
Public data: repo metadata (stars, forks, language, topics, license, pushed_at), contributors, stargazers, a language byte breakdown, releases, user and org profiles, a user's or org's public repos, recent public events, pinned repos, and trending repositories and developers.
Can I paginate through all stargazers and contributors?
Yes — pass page and per_page to walk stargazers and contributors. Note GitHub caps some lists (very large repos won't return every contributor) and caps search at 1,000 results per query, so shard large result sets by language, stars, or date.
Is GitHub profile data personal data?
Public repo and star facts are factual, but a user's name, company, location, email, and linked social accounts are personal data under GDPR/CCPA. Collect public, factual fields with a lawful basis and don't scrape profiles for spam or resale.
How often can I refresh GitHub data?
Re-run on a schedule. Stars, forks, trending, releases, and contributor counts change continuously, so pull the endpoints you track (repo, trending, releases) on a cadence and store one row per snapshot to build a time series.