Instagram'dan Veri Çekme: Residential Proxy ile Kapsamlı Rehber

Instagram'dan ölçeklenebilir şekilde veri çekmenin teknik detayları: rate limitleri aşma, residential proxy kullanımı, Python kod örnekleri ve etik kazıma kuralları.

How to Scrape Public Instagram Data with Residential Proxies

Instagram, dünyanın en büyük görsel platformlarından biri — ve aynı zamanda en zor kazınan sitelerden biri. Sosyal dinleme araçları geliştiren bir Python geliştiricisiyseniz, muhtemelen şu döngüyü yaşamışsınızdır: birkaç sayfa çektiniz, çalıştı, ölçeklendirdiniz ve anında IP engeli yediniz. Bu rehber, Instagram'ın koruma mekanizmalarını anlamak ve residential proxy ile veri çekme hattınızı kurmak için ihtiyacınız olan her şeyi sunuyor.

Önemli Uyarı: Bu rehber yalnızca herkese açık (public) verilere erişim için geçerlidir. Instagram'ın Hizmet Şartları'nı (Terms of Service), ABD'de CFAA'yı ve AB'de GDPR'yi ihlal eden herhangi bir yöntem önermiyoruz. Login automation, credential stuffing veya private içerik erişimi kesinlikle önerilmez. Resmi API mevcut olduğunda onu kullanın.

Instagram Neden Büyük Ölçekte Kazımak Zordur?

Instagram, 2018'den beri algoritmasını ve altyapısını agresif şekilde korumaya aldı. Milyarlarca kullanıcıyı barındıran bir platform olarak, bot trafiğini filtrelemek için çok katmanlı bir savunma hattı kurmuş durumda.

Rate Limitler

Instagram, IP bazında ve hesap bazında rate limit uygular. Kimliği doğrulanmamış (unauthenticated) isteklerde bu limit çok daha agresiftir — genellikle saatte birkaç yüz istekten sonra 429 Too Many Requests yanıtı alırsınız. Kimlik doğrulanmış isteklerde bile, tek bir oturumdan gelen anormal istek hacmi hızla flaglenir.

Login Wall

Instagram, giderek daha fazla içeriği login arkasına taşıyor. 2020 civarında hashtag sayfaları ve keşfet akını login gerektirir hale geldi. Bugün, birçok public profil bile cookie'ler olmadığında sınırlı veri gösteriyor. Bu, scraping stratejinizi login gerektirmeyen uç noktalarla sınırlamayı gerektiriyor.

Anti-Bot Sistemleri

Instagram, Meta'nın daha geniş anti-bot altyapısını kullanıyor. Bu sistemler şunları izler:

  • İstek hızı ve paternleri (insan davranışından sapma)
  • IP türü (datacenter IP'ler anında flaglenir)
  • Tarayıcı parmak izi (Canvas, WebGL, font fingerprint)
  • TLS parmak izi (JA3/JA4 hash'leri)
  • Header sıralaması ve eksik header'lar

Device Fingerprinting

Instagram'ın mobil API'si, istemciyi doğrulamak için cihaz kimliği (device_id), reklam kimliği ve uygulama sürümü gibi parametreler bekler. Web istemcisi ise tarayıcı parmak izi verileri toplar. Bu, basit bir requests.get() çağrısının fingerprint açısından bir gerçek tarayıcıya hiç benzemediği anlamına gelir.

Loginsiz Erişilebilir Veriler

Login yapmadan erişebileceğiniz veriler zamanla daraldı, ancak hâlâ anlamlı miktarda public veri mevcut:

  • Public profil sayfaları: Kullanıcı adı, biyografi, takipçi/takip edilen sayısı, gönderi sayısı, son gönderilerin küçük önizlemeleri
  • Hashtag sayfaları: Sınırlı sayıda popüler gönderi (login gerekebilir, değişken)
  • Konum sayfaları: Coğrafi etiketli public gönderiler
  • Reels akışları: Public Reels içerikleri
  • Gönderi sayfaları: Tek bir gönderinin likes, yorum sayısı ve medya URL'si (sınırlı)

Önemli nokta: login arkasındaki verilere asla erişmeye çalışmayın. DM'ler, private hesaplar, stories ve kaydedilen gönderiler bu kategoriye girer. Bu verilere erişmek hem ToS ihlali hem de potansiyel olarak yasadışıdır.

Neden Residential Proxy Instagram İçin Zorunludur?

Instagram, datacenter IP'leri için özel bir filtreleme uygular. Bir AWS, DigitalOcean veya Hetzner IP'sinden gelen istekler, içerik gösterilmeden önce bile challenge sayfalarına yönlendirilir. Bu, Instagram'ın ISP ve ASN veritabanını kullanarak IP türünü sınıflandırdığını gösteriyor.

Residential proxy'ler ise gerçek İSS'lerden (ISP) gelen IP'ler sunar. Instagram'ın perspektifinden, trafiğiniz normal bir ev kullanıcısından geliyordur — çünkü öyle.

ÖzellikResidential ProxyDatacenter ProxyMobile Proxy
Instagram flaglenme riskiDüşükÇok YüksekÇok Düşük
IP havuzu boyutuGeniş (milyonlarca)Sınırlı (binlerce)
MaliyetOrtaDüşükYüksek
Hız / LatencyOrtaDüşük (hızlı)Yüksek (yavaş)
Coğrafi hedeflemeÜlke / ŞehirGenelde yokÜlke / Operatör
Oturum tutarlılığıSticky session mümkünIP sabitIP değişken

Instagram scraping için residential proxy, maliyet ve güvenilirlik arasında en iyi dengeyi sunar. Mobile proxy'ler en güvenli seçenek olsa da maliyetleri yüksektir ve hızı düşüktür. Datacenter proxy'ler ise Instagram'da pratik olarak kullanılamaz.

ProxyHat residential proxy fiyatları ile ölçeklenebilir bir veri çekme hattı kurabilirsiniz.

Python ile Instagram Veri Çekme: Kod Örnekleri

Aşağıdaki örnekler, ProxyHat residential proxy havuzu kullanarak Instagram'dan public veri çekmek için gerçekçi bir yaklaşım gösteriyor. Temel prensipler:

  • Her istekte IP rotasyonu
  • Gerçekçi tarayıcı header'ları
  • User-agent rotasyonu
  • Oturum izolasyonu (her proxy kendi session'ını kullanır)

Temel Yapı: requests + Rotating Residential Proxy

import requests
import random
import time
from urllib.parse import quote

# ProxyHat residential proxy - her istekte farklı IP
PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"

# Gerçekçi user-agent havuzu
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 "
    "(KHTML, like Gecko) Version/17.4 Safari/605.1.15",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) "
    "Gecko/20100101 Firefox/126.0",
]

def get_session():
    """Her session yeni bir proxy IP ve user-agent kullanır."""
    session = requests.Session()
    session.proxies = {
        "http": PROXY_URL,
        "https": PROXY_URL,
    }
    ua = random.choice(USER_AGENTS)
    session.headers.update({
        "User-Agent": ua,
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9," 
                   "image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept-Encoding": "gzip, deflate, br",
        "Connection": "keep-alive",
        "Upgrade-Insecure-Requests": "1",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-User": "?1",
    })
    return session

def scrape_profile(username: str) -> dict:
    """Public bir Instagram profil sayfasını çeker."""
    url = f"https://www.instagram.com/{username}/"
    session = get_session()

    # İlk istek: CSRF token ve cookie'leri al
    resp = session.get(url, timeout=30)
    if resp.status_code == 429:
        print(f"Rate limited. Bekleniyor...")
        time.sleep(60)
        return scrape_profile(username)
    if resp.status_code != 200:
        print(f"HTTP {resp.status_code} for {username}")
        return {}

    # Sayfa içinden sharedData'yı ayrıştır
    # (Instagram yapısı sık değişir, bu temel bir yaklaşımdır)
    text = resp.text
    if "_sharedData" in text:
        import json, re
        match = re.search(r"window\._sharedData\s*=\s*({.+?});</script>", text)
        if match:
            data = json.loads(match.group(1))
            user_data = (
                data.get("entry_data", {})
                .get("ProfilePage", [{}])[0]
                .get("graphql", {})
                .get("user", {})
            )
            return {
                "username": user_data.get("username"),
                "full_name": user_data.get("full_name"),
                "biography": user_data.get("biography"),
                "followers": user_data.get("edge_followed_by", {}).get("count"),
                "following": user_data.get("edge_follow", {}).get("count"),
                "posts": user_data.get("edge_owner_to_timeline_media", {}).get("count"),
                "is_private": user_data.get("is_private"),
            }
    return {"raw_length": len(text), "note": "Yapış değişmiş olabilir"}

# Örnek kullanım
result = scrape_profile("nasa")
print(result)

Rate-Limit Yönetimi ile Toplu Profil Çekme

import time
import logging
from typing import List, Dict, Optional

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class InstagramScraper:
    """Rate-limit aware Instagram profile scraper."""

    # ProxyHat sticky session: aynı IP'yi 10 dakika tut
    STICKY_PROXY = "http://user-country-US-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"

    RATE_LIMIT_DELAY = 3   # istekler arası saniye
    COOLDOWN_429 = 120      # 429 sonrası bekleme süresi
    MAX_RETRIES = 3

    def __init__(self):
        self.session_counter = 0

    def _get_sticky_session(self, session_id: str) -> requests.Session:
        """Sticky session: aynı IP'yi belirli bir süre korur."""
        proxy_url = self.STICKY_PROXY.format(session_id=session_id)
        session = requests.Session()
        session.proxies = {"http": proxy_url, "https": proxy_url}
        ua = random.choice(USER_AGENTS)
        session.headers.update({
            "User-Agent": ua,
            "Accept-Language": "en-US,en;q=0.9",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        })
        return session

    def scrape_profiles(self, usernames: List[str]) -> List[Dict]:
        results = []
        for i, username in enumerate(usernames):
            # Her 50 istekte yeni bir sticky session (yeni IP)
            if i % 50 == 0:
                self.session_counter += 1
                session_id = f"batch{self.session_counter}"
                session = self._get_sticky_session(session_id)
                logger.info(f"Yeni sticky session: {session_id}")

            result = self._scrape_with_retry(session, username)
            if result:
                results.append(result)
                logger.info(f"[{i+1}/{len(usernames)}] {username}: OK")
            else:
                logger.warning(f"[{i+1}/{len(usernames)}] {username}: FAILED")

            # Rate-limit: istekler arası bekleme
            time.sleep(self.RATE_LIMIT_DELAY + random.uniform(0.5, 2.0))

        return results

    def _scrape_with_retry(self, session, username: str) -> Optional[dict]:
        for attempt in range(self.MAX_RETRIES):
            try:
                resp = session.get(
                    f"https://www.instagram.com/{username}/",
                    timeout=30
                )
                if resp.status_code == 429:
                    logger.warning(f"429 rate limit for {username}, attempt {attempt+1}")
                    time.sleep(self.COOLDOWN_429)
                    continue
                if resp.status_code == 200:
                    return self._parse_profile(resp.text, username)
                logger.warning(f"HTTP {resp.status_code} for {username}")
            except requests.RequestException as e:
                logger.error(f"Request error for {username}: {e}")
                time.sleep(10)
        return None

    def _parse_profile(self, html: str, username: str) -> dict:
        import re, json
        # Instagram sayfa yapısı sık değişir — bu temel bir ayrıştırıcıdır
        match = re.search(
            r'window\._sharedData\s*=\s*({.+?});</script>', html
        )
        if match:
            try:
                data = json.loads(match.group(1))
                user = (data.get("entry_data", {})
                        .get("ProfilePage", [{}])[0]
                        .get("graphql", {}).get("user", {}))
                return {
                    "username": user.get("username", username),
                    "full_name": user.get("full_name"),
                    "followers": user.get("edge_followed_by", {}).get("count"),
                    "posts_count": user.get("edge_owner_to_timeline_media", {}).get("count"),
                    "is_private": user.get("is_private", False),
                }
            except (json.JSONDecodeError, KeyError, IndexError):
                pass
        return {"username": username, "note": "parse edilemedi"}

# Kullanım
scraper = InstagramScraper()
profiles = scraper.scrape_profiles(["nasa", "natgeo", "bbc"])
for p in profiles:
    print(p)

Instagram'a Özel Teknik Zorluklar

Instagram'ın yapısı, sıradan bir web sitesinden çok farklıdır. Aşağıdaki konuları anlamak, veri çekme hattınızın dayanıklılığı için kritiktir.

?__a=1 JSON Uç Noktası

Eskiden https://www.instagram.com/username/?__a=1 adresi, profil verilerini JSON olarak döndürüyordu — scraping için mükemmel bir uç noktaydı. Ancak Instagram bu uç noktayı 2020 civarında kısıtladı ve sonrasında tamamen kaldırdı. Bugün bu URL'ye erişim login gerektiriyor veya boş yanıt dönüyor.

Ders: Instagram'ın herhangi bir JSON uç noktası kalıcı değildir. Her an değişebilir veya kaldırılabilir. Kodunuzu bu belirsizliğe dayanıklı yazın.

GraphQL Sorguları

Instagram'ın web istemcisi, verileri GraphQL üzerinden çeker. Bu sorgular graphql/query/ uç noktasına gider ve query_hash veya doc_id parametreleri içerir. Bu hash'ler Instagram'ın her deployment'ında değişebilir, bu yüzden sabit kodlamak güvenilmezdir.

GraphQL sorguları ayrıca şu header'ları gerektirir:

  • x-ig-app-id: Instagram web uygulamasının tanımlayıcısı (sabit bir değer, ancak değişebilir)
  • x-csrftoken: CSRF koruması için token (cookie'lerden alınır)
# GraphQL sorgu örneği — hash değerleri değişkendir
GRAPHQL_URL = "https://www.instagram.com/graphql/query/"

params = {
    "doc_id": "123456789",  # Bu değer sık değişir
    "variables": json.dumps({"user_id": "12345", "count": 12})
}

headers = {
    "x-ig-app-id": "936619743392459",
    "x-csrftoken": csrf_token,
    "x-requested-with": "XMLHttpRequest",
    "Referer": "https://www.instagram.com/",
}

# Not: Bu uç nokta authentication gerektirebilir
# ve doc_id değerleri Instagram güncellemelerinde değişir

HTTPS Pinning ve Mobile API

Instagram'ın mobil uygulaması, SSL certificate pinning uygular. Bu, man-in-the-middle yakalamalarını engeller ve mobil API'yi reverse engineer etmeyi zorlaştırır. Certificate pinning'i aşmak için araçlar (Frida, mitmproxy) mevcuttur, ancak bu yöntemler ToS ihlali olabilir ve bu rehberde önerilmez.

HTML Scraping'ten Mobile API Reverse Engineering'e Geçiş

Instagram'ın web arayüzü giderek daha fazla client-side rendering kullanıyor. Sunucu tarafında render edilen HTML'den çıkartabileceğiniz veri miktarı azalıyor. Bu durumda iki seçenek var:

  1. Headless browser yaklaşımı: Playwright veya Puppeteer ile sayfayı gerçekten render edin. Yavaş ama güvenilir.
  2. Mobile API reverse engineering: Instagram'ın mobil uygulamasının API çağrılarını taklit edin. Hızlı ama kırılgan — API değişiklikleri kodunuzu bozar.

Her iki yaklaşım da residential proxy gerektirir. Headless browser kullanırken fingerprint riskini azaltmak için tarayıcı automation karşıtı önlemler rehberimize bakın.

Node.js ile Instagram Veri Çekme

Python ekosistemine ek olarak, Node.js ile de benzer bir yaklaşım izleyebilirsiniz:

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

// ProxyHat residential proxy
const proxyAgent = new HttpsProxyAgent(
  'http://user-country-US:PASSWORD@gate.proxyhat.com:8080'
);

const USER_AGENTS = [
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' +
  '(KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 ' +
  '(KHTML, like Gecko) Version/17.4 Safari/605.1.15',
];

async function scrapeInstagramProfile(username) {
  const ua = USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];

  try {
    const response = await axios.get(
      `https://www.instagram.com/${username}/`,
      {
        httpsAgent: proxyAgent,
        headers: {
          'User-Agent': ua,
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
          'Accept-Language': 'en-US,en;q=0.9',
          'Accept-Encoding': 'gzip, deflate, br',
          'Sec-Fetch-Dest': 'document',
          'Sec-Fetch-Mode': 'navigate',
          'Sec-Fetch-Site': 'none',
        },
        timeout: 30000,
      }
    );

    if (response.status === 200) {
      // HTML'den veri ayrıştırma
      const html = response.data;
      const sharedDataMatch = html.match(
        /window\._sharedData\s*=\s*({.+?});<\/script>/
      );
      if (sharedDataMatch) {
        const data = JSON.parse(sharedDataMatch[1]);
        const user = data?.entry_data?.ProfilePage?.[0]?.graphql?.user;
        return {
          username: user?.username,
          fullName: user?.full_name,
          followers: user?.edge_followed_by?.count,
          posts: user?.edge_owner_to_timeline_media?.count,
        };
      }
    }
    return null;
  } catch (error) {
    if (error.response?.status === 429) {
      console.error('Rate limited — 120 saniye bekleniyor...');
      await new Promise(r => setTimeout(r, 120000));
      return scrapeInstagramProfile(username); // retry
    }
    console.error(`Hata: ${error.message}`);
    return null;
  }
}

// Kullanım
scrapeInstagramProfile('nasa').then(console.log);

Etik Veri Çekme: Kurallar ve Sınırlar

Teknik olarak veri çekebilmek, çekeceğiniz anlamına gelmez. Instagram scraping yaparken etik ve yasal sınırlara dikkat etmek uzun vadeli projeler için zorunludur.

robots.txt'e Saygı

Instagram'ın robots.txt dosyası, birçok uç noktayı bot'lara kapattığını belirtir. robots.txt yasal olarak bağlayıcı olmasa da, CFAA kapsamında "yetkisiz erişim" argümanı güçlendirir. robots.txt ile kapatılmış uç noktalara erişmekten kaçının.

Kendi Rate-Limitinizi Uygulayın

Instagram'ın sizi engellemesini beklemeyin — kendinizi sınırlayın:

  • Her IP'den saatte en fazla 200 istek
  • İstekler arası 2-5 saniye rastgele gecikme
  • İnsan davranışını taklit eden istek paternleri (sabit aralıklar değil)
  • 429 yanıtı aldığınızda en az 2 dakika bekleme

Login Automation Asla Yapmayın

Otomatik login, Instagram'ın en agresif koruma mekanizmasını tetikler. Bot hesabı oluşturmak, credential stuffing yapmak veya otomatik login scriptleri çalıştırmak:

  • ToS'nin açık ihlalidir
  • Hesabınızın kalıcı olarak banlanmasına neden olur
  • IP'nizin karalisteye alınmasına yol açar
  • CFAA kapsamında suç teşkil edebilir

Veri çekme hattınızı her zaman unauthenticated (loginsiz) tutun.

Kişisel Verileri İşlemeyin (GDPR Uyumu)

AB'den bir kullanıcıya ait veri çekiyorsanız, GDPR geçerlidir. Profil adı, biyografi ve medya URL'leri kişisel veri olabilir. Şunları yapın:

  • Sadece gerçekten ihtiyacınız olan veriyi çekin
  • Veriyi minimum süre saklayın
  • Kullanıcı silme talep ederse derhal silin
  • Veri işleme amaçlarınızı belgeleyin

Resmi API'yi Kullanın: Ne Zaman?

Instagram Graph API, iş hesapları ve creator hesapları için resmi bir API sunar. Eğer:

  • Kendi hesabınızın verisini çekiyorsanız
  • Bir business/creator hesabının sahibinden izin aldıysanız
  • Uzun vadeli, stabil bir entegrasyon inşa ediyorsanız

O zaman resmi API'yi kullanın. Scraping, resmi API'nin kapsamadığı public veri toplama senaryoları için bir son çarektir.

Temel İlke: Bir veriye resmi API ile erişebiliyorsanız, scraping yapmayın. API'ler stabil, belgelenmiş ve yasal olarak güvenlidir. Scraping ise kırılgan, bakım yoğun ve yasal gri alanda kalır.

Web scraping kullanım senaryoları sayfamızda farklı veri çekme yaklaşımlarını karşılaştırabilirsiniz.

Temel Çıkarımlar

Instagram'dan veri çekmenin altın kuralları:

  • Sadece public, login gerektirmeyen verilere erişin
  • Datacenter proxy yerine residential proxy kullanın — Instagram DC IP'leri anında flagler
  • Her istekte IP rotasyonu + user-agent rotasyonu uygulayın
  • Kendi rate-limitinizi kendiniz uygulayın (saatte ~200 istek/IP)
  • Login automation kesinlikle yapmayın
  • Instagram'ın sayfa yapısı sık değişir — kodunuzu modüler ve dayanıklı yazın
  • Resmi API mevcut olduğunda onu tercih edin
  • GDPR ve CFAA uyumluluğunu her zaman göz önünde bulundurun

Instagram scraping, doğru proxy altyapısı ve disiplinli rate-limit yönetimi ile mümkündür. ProxyHat'ın residential proxy ağı, 70+ ülkede konut IP'leri sunarak Instagram'ın datacenter filtrelerinden geçmenizi sağlar. Fiyatlandırma sayfamızdan ihtiyacınıza uygun planı seçerek veri çekme hattınızı bugün kurabilirsiniz.

Başlamaya hazır mısınız?

148+ ülkede 50M+ konut IP'sine AI destekli filtreleme ile erişin.

Fiyatlandırmayı GörüntüleKonut Proxy'leri
← Bloga Dön