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.
| Özellik | Residential Proxy | Datacenter Proxy | Mobile Proxy |
|---|---|---|---|
| Instagram flaglenme riski | Düşük | Çok Yüksek | Çok Düşük |
| IP havuzu boyutu | Geniş (milyonlarca) | Sınırlı (binlerce) | |
| Maliyet | Orta | Düşük | Yüksek |
| Hız / Latency | Orta | Düşük (hızlı) | Yüksek (yavaş) |
| Coğrafi hedefleme | Ülke / Şehir | Genelde yok | Ülke / Operatör |
| Oturum tutarlılığı | Sticky session mümkün | IP sabit | IP 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şirHTTPS 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:
- Headless browser yaklaşımı: Playwright veya Puppeteer ile sayfayı gerçekten render edin. Yavaş ama güvenilir.
- 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.






