Python tutorial · September 2026

How to Scrape Instagram with Python in 2026 (When Instaloader and Selenium Stop Working)

Why the old tutorials break, and a working 30-line script that vets influencers using public data.

· 8 minute read

You found a tutorial. It was clear, the code was short, and it worked.

For about twenty requests.

Then Instaloader started throwing 429 Too Many Requests. Or your Selenium script landed on a login wall. Or the JSON came back with "require_login": true and nothing else. You added a sleep(5). You tried a proxy. You logged in with a spare account, and a day later that account was asking you to confirm it's not a robot.

If that's how you got here, you didn't do anything wrong. The tutorials are just out of date. Most of the top-ranking "scrape Instagram with Python" guides were written in 2020–2022, and Instagram has changed a lot since.

This article covers what changed, what actually works now, and a small real project to prove it: a script that checks whether an influencer's audience is real.

Why your Instagram scraper keeps breaking

Instagram is one of the most aggressive sites on the internet when it comes to blocking automation. Here's what you're up against in 2026:

Datacenter IPs are blocked almost immediately. If your script runs on AWS, GCP, a VPS or a CI runner, Instagram knows it's not a phone in someone's hand. Many requests fail on the first try.

Your HTTP client is fingerprinted. Python's requests and httpx have a recognizable TLS signature. Instagram can tell it's not a real browser before it even reads your headers, so changing the User-Agent doesn't fool it.

Logged-out access is heavily limited. You used to be able to browse public profiles freely. Now you get a login prompt after a few pages, and logged-out rate limits are tight: roughly a couple of hundred requests per hour from a single clean IP.

Logging in makes it worse, not better. Scraping with a logged-in account triggers challenge_required and feedback_required errors, and eventually gets the account suspended. It also puts you squarely against Instagram's terms.

The internal endpoints move. Instagram's web app uses private GraphQL queries identified by doc_id values. Those rotate every few weeks. When they do, your scraper doesn't crash. It just quietly returns empty data, which is worse.

The official API won't help. Meta shut down the Instagram Basic Display API in December 2024. The Graph API that replaced it only returns data for Business and Creator accounts you own or manage. It can't look up a public profile you don't control.

The DIY fix is residential proxies (often $10+ per GB), sticky sessions, browser fingerprint spoofing, retry logic for four different error types, and someone to watch it all when Instagram ships a change. That's a real project, and for most people it's not the project they actually wanted to build.

What works instead: let an API deal with Instagram

The option that has quietly taken over is using an Instagram data API. You send one normal HTTPS request. The provider handles the proxies, sessions and breaking changes on their side, and you get clean JSON back.

Your code stops being a scraper and becomes a regular API client. That's the difference between maintaining something every week and forgetting it exists.

I'll use GramScraper in the examples because it's the one I know best (full disclosure: I work on it). The same pattern works with any similar provider. You get 100 free credits on signup, no credit card, and most lookups cost 1 credit.

Here's a public profile lookup:

Python
import requests

r = requests.get(
    "https://gramscraper.com/api/instagram/v1/user/by/username",
    headers={"Authorization": "Bearer gs_your_api_key"},
    params={"username": "natgeo"},
    timeout=30,
)
profile = r.json()
print(profile["username"], profile["follower_count"])

No browser, no proxy, no login, no doc_id. You get followers, following, post count, bio, verification status and the account's numeric ID. You'll need that ID to fetch posts.

A real project: is this influencer's audience real?

Profile data on its own is a bit boring. So let's build something useful with it.

Brands pay creators based on follower counts, and follower counts are easy to fake. The numbers that are much harder to fake are about engagement:

This script checks all three for a list of accounts:

vet.py
import statistics, requests

API = "https://gramscraper.com/api/instagram"
HEADERS = {"Authorization": "Bearer gs_your_api_key"}

def get(path, **params):
    r = requests.get(API + path, headers=HEADERS, params=params, timeout=30)
    r.raise_for_status()
    return r.json()

def vet(username):
    profile = get("/v1/user/by/username", username=username)
    followers = profile["follower_count"]

    page = get("/v1/user/medias/chunk", user_id=profile.get("pk") or profile.get("id"))
    posts = page if isinstance(page, list) else page.get("items", [])
    posts = [p for p in posts if isinstance(p, dict)][:12]
    if not posts or not followers:
        return print(f"@{username}: not enough public data")

    likes = [p.get("like_count", 0) for p in posts]
    comments = [p.get("comment_count", 0) for p in posts]

    er = (statistics.mean(likes) + statistics.mean(comments)) / followers * 100
    spread = statistics.mean(likes) / max(statistics.median(likes), 1)
    talk = sum(comments) / max(sum(likes), 1) * 100

    flag = "⚠️ check" if er < 0.3 or spread > 3 else "✅ looks real"
    print(f"@{username:<20} {followers:>11,} followers  "
          f"ER {er:5.2f}%  avg/median {spread:4.1f}x  "
          f"comments/likes {talk:4.1f}%  {flag}")

for name in ["natgeo", "nike", "creator_on_your_shortlist"]:
    vet(name)

Save it as vet.py, paste in your API key and run python vet.py. You get one line per account: follower count, engagement rate, how much the average post beats the median, how much people comment, and a flag.

Each account costs 2 credits (one for the profile, one for the posts), so the free tier covers about 50 creators.

A few notes:

Handling errors like a grown-up

An API removes most of the pain, but you still write normal, careful HTTP code:

Only retry the errors that can succeed on a second try. Scripts that retry everything in a tight loop are how people burn through credits overnight.

When DIY scraping still makes sense

To be fair: if you need a few profiles once, from your own laptop on a home connection, Instaloader might still get you there. If you're a researcher who enjoys the cat-and-mouse and has time to maintain it, building your own is a great way to learn.

But if you're building a product, a dashboard or anything that has to keep working next month, the maths usually favors an API. A single residential proxy bill can cost more than a pack of credits, before you count the hours spent debugging.

Doing this responsibly

Stick to public data: the same things anyone sees when they open a profile without logging in. Don't try to get into private accounts, don't build profiles of private individuals, and check that what you're doing fits the privacy laws where you and your users are. Vetting a creator before a brand pays them is about as legitimate a use as it gets.

Wrapping up

The old tutorials aren't wrong so much as expired. Instagram closed the doors they walked through.

What works in 2026 is simpler: skip the browser, skip the proxies, call a data API, and spend your time on the part you actually care about. In this case, that's catching fake influencers in about thirty lines of Python.

Want to run the script? GramScraper gives you 100 free credits, with no credit card. The quickstart takes you from signup to your first request in a few minutes.

Stuck on a specific error? These go deeper:

Vet your first creators free

100 free credits covers about 50 accounts. No credit card.

Get your API key →