Instagram veri kazıma, sosyal medya dinleme araçları, pazar araştırması ve trend analizi yapan geliştiriciler için değerli bir yetenktir. Ancak platform, ölçekli veri çekmeyi zorlaştıran çok katmanlı korumalar uygulamıştır. Bu rehber, yalnızca halka açık verilere odaklanarak, residential proxy'lerin neden vazgeçilmez olduğunu ve Python ile güvenli, etik bir veri hattı kurmayı anlatır.
Önemli Uyarı: Bu rehber yalnızca herkesin erişebildiği açık verileri çekmeyi kapsar. Instagram'ın Hizmet Koşulları'nı (ToS), ABD'de CFAA'yı ve AB'de GDPR'yi ihlal edecek otomatik giriş (login automation), özel profil verisi çekme veya spam faaliyetleri teşvik etmez. Her zaman robots.txt'ye saygı gösterin ve kendi hız sınırlarınızı uygulayın.
Instagram Neden Kazıma İçin Zor Bir Hedef?
Instagram, 2018'den beri agresif anti-bot önlemleri uyguluyor. Ölçekli veri çekerken karşılaşacağınız başlıca engeller şunlardır:
Rate Limit ve 429 Hataları
Instagram, IP başına saatlik istek sayısını sıkı şekilde sınırlar. Anonim oturumlar için bu limit çok düşüktür — genellikle 100-200 istek/saat civarında. Bu sınırı aştığınızda HTTP 429 Too Many Requests alırsınız ve IP geçici olarak banlanır.
Login Wall (Giriş Duvarı)
Profil sayfalarının çoğu, yorumlar ve bazı medya içerikleri artık giriş yapmadan görüntülenemiyor. Ancak public profiller, hashtag sayfaları, location sayfaları ve Reels feed'leri hala giriş olmadan erişilebilir durumda.
Device Fingerprinting
Instagram, sadece IP'yi değil, tarayıcı parmak izinizi de analiz eder: User-Agent, ekran çözünürlüğü, font listesi, canvas fingerprint, WebGL render bilgisi ve JavaScript davranışları. Şüpheli desenler algıladığında CAPTCHA veya challenge sayfasına yönlendirir.
HTTPS Pinning ve API Erişimi
Instagram mobil uygulaması, sunucu sertifikasını doğrulayan certificate pinning kullanır. Bu, man-in-the-middle proxy'lerle trafiği yakalamayı zorlaştırır. Web arayüzü ise GraphQL endpoint'lerini kullanır ve bu endpoint'ler belirli header'lar olmadan çalışmaz.
Giriş Olmadan Erişilebilir Veriler
Instagram'da giriş yapmadan erişebileceğiniz veriler sınırlı ama değerlidir:
| Veri Türü | Erişim | Notlar |
|---|---|---|
| Public Profil Sayfaları | ✅ Açık | Kullanıcı adı, biyografi, takipçi sayısı, gönderi sayısı |
| Hashtag Sayfaları | ✅ Açık | Son gönderiler, toplam gönderi sayısı |
| Location (Konum) Sayfaları | ✅ Açık | Mekâna ait gönderiler |
| Reels Feed | ✅ Kısmen | Sınırlı sayıda görüntüleme |
| Yorumlar | ❌ Giriş Gerekli | Artık login wall arkasında |
| Story'ler | ❌ Giriş Gerekli | Sadece giriş yapan kullanıcılar görebilir |
| Private Profiller | ❌ Asla | Etik ve yasal olarak erişilmemeli |
Neden Residential Proxy'ler Zorunludur?
Instagram, datacenter IP'leri agresif şekilde işaretler. AWS, Google Cloud, DigitalOcean gibi bilinen datacenter bloklarından gelen istekler anında şüpheyle karşılanır. Bunu nedeni basit: gerçek kullanıcılar datacenter'dan değil, ev internetinden veya mobil bağlantılardan gelir.
Datacenter vs Residential Karşılaştırması
| Özellik | Datacenter Proxy | Residential Proxy |
|---|---|---|
| IP Kaynağı | Sunucu blokları | Gerçek ISP'ler (ev/mobil) |
| Instagram Algısı | Hemen tespit edilir | Gerçek kullanıcı gibi görünür |
| Ban Riski | Çok Yüksek | Düşük-Orta |
| Maliyet | Düşük | Orta-Yüksek |
| Hız | Çok Hızlı | Değişken |
| Uzun Vadeli Kullanım | Önerilmez | Önerilir |
Residential proxy'ler, gerçek İSS'lerden (ISP) tahsis edilmiş IP'ler kullanır. Instagram bu IP'leri normal kullanıcı trafiği olarak görür. Web kazıma projelerinde residential proxy kullanımı, başarı oranını dramatik şekilde artırır.
Python ile Instagram Veri Çekme
Aşağıda, ProxyHat residential proxy havuzu kullanarak Instagram public profil verisi çeken bir Python örneği var. Bu kod gerçekçi header'lar, User-Agent rotasyonu ve oturum izolasyonu kullanır.
Temel Yapı: Proxy ile İstek
import requests
import random
import time
from fake_useragent import UserAgent
# ProxyHat residential proxy konfigürasyonu
PROXY_GATEWAY = "gate.proxyhat.com"
PROXY_PORT = 8080
PROXY_USER = "your_username"
PROXY_PASS = "your_password"
# Ülke bazlı geo-targeting örneği
# user-country-US, user-country-DE, user-country-TR gibi
PROXY_URL = f"http://{PROXY_USER}-country-US:{PROXY_PASS}@{PROXY_GATEWAY}:{PROXY_PORT}"
PROXIES = {
"http": PROXY_URL,
"https": PROXY_URL
}
# Gerçekçi User-Agent havuzu
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0"
]
def get_realistic_headers():
"""Instagram'ın beklediği gerçekçi header'lar"""
return {
"User-Agent": random.choice(USER_AGENTS),
"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",
"DNT": "1",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
}
def fetch_profile_page(username: str, session: requests.Session) -> dict:
"""Instagram public profil sayfasını çeker"""
url = f"https://www.instagram.com/{username}/"
headers = get_realistic_headers()
headers["Referer"] = "https://www.google.com/"
try:
response = session.get(
url,
headers=headers,
proxies=PROXIES,
timeout=30
)
if response.status_code == 200:
return parse_profile_html(response.text, username)
elif response.status_code == 429:
print(f"Rate limit hit. Waiting before retry...")
time.sleep(60)
return None
else:
print(f"Unexpected status: {response.status_code}")
return None
except requests.RequestException as e:
print(f"Request failed: {e}")
return None
def parse_profile_html(html: str, username: str) -> dict:
"""HTML'den profil verisini ayrıştırır"""
import re
# Instagram profil verisi <script type="text/javascript"> içinde JSON olarak gömülü
pattern = r'window\.__additionalDataLoaded\(\[\],\s*({.*?})\)\s*;\s*</script>'
match = re.search(pattern, html, re.DOTALL)
if match:
import json
try:
data = json.loads(match.group(1))
user_data = data.get("graphql", {}).get("user", {})
return {
"username": 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_count": user_data.get("edge_owner_to_timeline_media", {}).get("count"),
"is_private": user_data.get("is_private"),
"is_verified": user_data.get("is_verified"),
}
except json.JSONDecodeError:
pass
return {"username": username, "error": "Could not parse profile data"}
# Kullanım
if __name__ == "__main__":
session = requests.Session()
profile = fetch_profile_page("instagram", session)
print(profile)
Oturum İzolasyonu ve IP Rotasyonu
Her istek için yeni bir IP kullanmak, ban riskini azaltır. ProxyHat'te her istekte farklı bir residential IP almak için username'de -session- parametresini kullanabilirsiniz:
import uuid
def get_rotating_proxy_url(country: str = "US") -> str:
"""Her istekte yeni IP için rastgele session ID kullan"""
session_id = str(uuid.uuid4())[:8]
return f"http://{PROXY_USER}-country-{country}-session-{session_id}:{PROXY_PASS}@{PROXY_GATEWAY}:{PROXY_PORT}"
def fetch_with_rotation(url: str) -> requests.Response:
"""Her istekte yeni IP ile fetch"""
proxy_url = get_rotating_proxy_url()
proxies = {"http": proxy_url, "https": proxy_url}
session = requests.Session()
return session.get(url, headers=get_realistic_headers(), proxies=proxies, timeout=30)
Instagram'a Özgü Teknik Zorluklar
?__a=1 JSON Endpoint
Eskiden https://www.instagram.com/username/?__a=1 URL'si doğrudan JSON döndürürdü. Instagram bu endpoint'i 2021'de kısıtladı. Artık çalışmıyor veya login gerektiriyor. Bunun yerine HTML kaynağından gömülü JSON'u ayrıştırmak gerekiyor.
GraphQL Sorguları
Instagram web arayüzü, dahili GraphQL API kullanır. Bu API'ye erişmek için:
# Instagram GraphQL query örneği (sürekli değişir, reverse engineering gerekir)
GRAPHQL_URL = "https://www.instagram.com/graphql/query/"
headers = {
**get_realistic_headers(),
"x-ig-app-id": "936619743392459", # Instagram web app ID
"x-csrftoken": get_csrf_token(), # Cookie'den alınmalı
"x-requested-with": "XMLHttpRequest",
}
# Query hash'leri zamanla değişir
query_hash = "1c91b5bb5e9b5d6c7c7e5d5d5d5d5d5d"
params = {
"query_hash": query_hash,
"variables": f'{{"username":"instagram"}}'
}
Uyarı: GraphQL query hash'leri ve x-ig-app-id değeri Instagram tarafından düzenli olarak değiştirilir. Reverse engineering sürekli bakım gerektirir.
x-ig-app-id ve x-csrftoken Header'ları
Instagram API istekleri için gerekli header'lar:
- x-ig-app-id: Instagram web uygulamasının sabit ID'si (936619743392459)
- x-csrftoken: İlk sayfa ziyaretinden alınan CSRF token
- x-requested-with: XMLHttpRequest olmalı
HTML'den JSON Ayrıştırma
En güvenilir yöntem, profil sayfasının HTML'ini çekip içinde gömülü JavaScript verisini ayrıştırmaktır:
import re
import json
def extract_embedded_json(html: str) -> dict:
"""HTML içindeki __additionalDataLoaded veya __bbox verisini bul"""
# Yöntem 1: additionalDataLoaded
pattern1 = r'window\.__additionalDataLoaded\(\[\],\s*({.*?})\)\s*;'
match = re.search(pattern1, html, re.DOTALL)
if match:
try:
return json.loads(match.group(1))
except:
pass
# Yöntem 2: _sharedData
pattern2 = r'window\._sharedData\s*=\s*({.*?});\s*</script>'
match = re.search(pattern2, html, re.DOTALL)
if match:
try:
return json.loads(match.group(1))
except:
pass
return {}
Hız Sınırlama ve Rate Limit Yönetimi
Instagram'ın rate limit'lerini aşmamak için kendi hız sınırlarınızı uygulayın:
import time
from collections import deque
class RateLimiter:
def __init__(self, requests_per_hour: int = 100, min_interval: float = 3.0):
self.requests_per_hour = requests_per_hour
self.min_interval = min_interval
self.request_times = deque()
def wait_if_needed(self):
"""Gerekirse bekle"""
now = time.time()
# Minimum interval bekle
if self.request_times:
elapsed = now - self.request_times[-1]
if elapsed < self.min_interval:
time.sleep(self.min_interval - elapsed)
# Saatlik limit kontrolü
hour_ago = now - 3600
while self.request_times and self.request_times[0] < hour_ago:
self.request_times.popleft()
if len(self.request_times) >= self.requests_per_hour:
wait_time = 3600 - (now - self.request_times[0])
print(f"Hourly limit reached. Waiting {wait_time:.0f} seconds...")
time.sleep(wait_time)
self.request_times.append(time.time())
# Kullanım
limiter = RateLimiter(requests_per_hour=80, min_interval=4.0)
for username in target_usernames:
limiter.wait_if_needed()
profile = fetch_profile_page(username, session)
# process profile...
Node.js Örneği
JavaScript/TypeScript ortamında da benzer bir yaklaşım kullanılabilir:
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
const PROXY_HOST = 'gate.proxyhat.com';
const PROXY_PORT = 8080;
const PROXY_USER = 'your_username';
const PROXY_PASS = 'your_password';
// ProxyHat ile residential proxy
const proxyUrl = `http://${PROXY_USER}-country-US:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}`;
const httpsAgent = new HttpsProxyAgent(proxyUrl);
const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15',
];
async function fetchInstagramProfile(username) {
const url = `https://www.instagram.com/${username}/`;
const headers = {
'User-Agent': userAgents[Math.floor(Math.random() * userAgents.length)],
'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',
};
try {
const response = await axios.get(url, {
headers,
httpsAgent,
timeout: 30000,
});
if (response.status === 200) {
return parseProfileFromHtml(response.data, username);
}
} catch (error) {
if (error.response?.status === 429) {
console.log('Rate limited. Waiting...');
await new Promise(r => setTimeout(r, 60000));
}
throw error;
}
}
function parseProfileFromHtml(html, username) {
const regex = /window\.__additionalDataLoaded\(\[\],\s*({.*?})\)\s*;/s;
const match = html.match(regex);
if (match) {
const data = JSON.parse(match[1]);
const user = data.graphql?.user;
return {
username,
fullName: user?.full_name,
followers: user?.edge_followed_by?.count,
posts: user?.edge_owner_to_timeline_media?.count,
isPrivate: user?.is_private,
};
}
return { username, error: 'Parse failed' };
}
module.exports = { fetchInstagramProfile };
Etik Veri Kazıma İlkeleri
Instagram'dan veri çekerken etik sınırları aşmamak kritiktir:
Robots.txt'ye Saygı
Instagram'ın robots.txt'si birçok endpoint'i engeller. Buna saygı gösterin:
# instagram.com/robots.txt (özet)
User-agent: *
Disallow: /accounts/
Disallow: /p/
Disallow: /explore/
Allow: /$
Allow: /$username/$
Kendi Hız Sınırlarınızı Uygulayın
Instagram'ın izin verdiğinden daha yavaş istek atın. Saatte 50-80 istek güvenli bir aralıktır. ProxyHat pricing sayfasında farklı kullanım senaryoları için uygun planları bulabilirsiniz.
Asla Otomatik Giriş Yapmayın
Otomatik login denemeleri:
- Instagram ToS'yi ihlal eder
- Hesabınızın kalıcı olarak banlanmasına neden olur
- ABD'de CFAA kapsamında yasal risk oluşturabilir
- GDPR kapsamında veri gizliliği ihlali sayılabilir
Resmi API'yi Tercih Edin
Uzun vadeli projeler için Instagram Graph API'yi kullanmayı düşünün:
- Onaylı iş ortakları için resmi erişim
- Rate limit'ler belirli ve öngörülebilir
- ToS uyumlu
- Değişen API'ler için bakım gerektirmez
Resmi API erişimi alınamıyorsa, yalnızca halka açık verileri çekin ve bunu düşük hacimle yapın.
Sık Karşılaşılan Sorunlar ve Çözümleri
| Sorun | Olası Neden | Çözüm |
|---|---|---|
| 429 Too Many Requests | IP başına limit aşıldı | Residential proxy rotasyonu, istek hızını düşür |
| 403 Forbidden | Bot tespiti | Header'ları iyileştir, fingerprint'i değiştir |
| Boş JSON | Endpoint değişmiş | HTML ayrıştırma yöntemini güncelle |
| CAPTCHA | Şüpheli davranış | Proxy kalitesini artır, hızını düşür |
| Timeout | Proxy yavaş | Timeout süresini artır, farklı proxy dene |
Key Takeaways
- Residential proxy kullanın: Datacenter IP'ler Instagram'da anında tespit edilir. ProxyHat'ın global residential ağı gerçek ISP IP'leri sağlar.
- Sadece halka açık verilere odaklanın: Private profiller, story'ler ve yorumlar etik ve yasal olarak erişilmemeli.
- Hız sınırlayın: Saatte 50-80 istek, istekler arası 3-5 saniye güvenli bir aralıktır.
- HTML ayrıştırma kullanın:
?__a=1artık güvenilir değil, gömülü JSON'u ayrıştırın. - Otomatik login yapmayın: Bu ToS ihlali ve yasal risk oluşturur.
- Bakım yapın: Instagram HTML yapısı ve GraphQL endpoint'leri düzenli değişir.
- Resmi API'yi değerlendirin: Uzun vadeli projeler için Instagram Graph API en güvenli yoldur.
Instagram veri kazıma, doğru araçlar ve etik yaklaşımla mümkündür. Residential proxy'ler, gerçekçi header'lar ve akıllı hız sınırlama ile güvenilir bir veri hattı kurabilirsiniz. ProxyHat, SERP tracking ve sosyal medya dinleme projeleri için yüksek kaliteli residential proxy'ler sunar.






