Proxy ile YouTube Veri Çekme Rehberi: API Sınırlarını Aşmak

YouTube Data API v3 kota sınırlamalarını aşarak yorum dizileri, trend verileri ve video metadatasını residential proxy ile nasıl çekeceğinizi adım adım öğrenin.

Proxy ile YouTube Veri Çekme Rehberi: API Sınırlarını Aşmak

Medya analitiği ekipleri ve içerik ekonomisi araştırmacıları için YouTube, paha biçilemez bir veri kaynağıdır. Ancak YouTube Data API v3 kotaları, ölçekli veri çekme ihtiyaçlarını karşılamada yetersiz kalır. Bir yorum dizisi çekimi bile kısa sürede günlük kotanızı tüketebilir. Bu rehberde, YouTube'dan residential proxy kullanarak nasıl veri çekeceğinizi, InnerTube API'sini nasıl kullanacağınızı ve etik sınırları nasıl koruyacağınızı detaylandıracağız.

Önemli Uyarı: Bu rehber yalnızca kamuya açık verilere erişim için geçerlidir. YouTube'un Hizmet Şartları scraping'i yasaklar; bu nedenle tüm işlemlerinizde ABD'de CFAA, AB'de GDPR ve ilgili yerel yasalara uyum sağlamaktan siz sorumlusunuz. Topladığınız transkriptleri veya video içeriklerini yeniden dağıtmayın; yaratıcıların mülkiyet haklarına saygı gösterin.

YouTube Data API v3 Ne Zaman Yeterli, Ne Zaman Yetersiz?

YouTube Data API v3, küçük ölçekli projeler için harika bir başlangıç noktasıdır. Ancak ölçek arttıkça ciddi darboğazlarla karşılaşırsınız.

Kota Sistemi ve Maliyet Yapısı

API v3, her isteğinizi kota birimi cinsinden ölçer. Günlük varsayılan kota 10.000 birimdir. İşte temel işlemlerin maliyeti:

İşlemKota Birimi MaliyetiGünlük 10K Kota ile Yaklaşık Kapasite
video.list (tek video)110.000 video
search.list (arama)100100 arama
commentThreads.list110.000 yorum
channels.list110.000 kanal

Bu tablo umut verici görünebilir, ancak arama işlemlerinin 100 birim tükettiğini fark edin. 100 arama ile günlük kotanız biter. Yorum çekimi 1 birim görünse de, bir popüler videoda 50.000+ yorum olabilir ve continuation token'ları ile sayfalama yapmanız gerekir — bu da hızlı bir şekilde binlerce birim tüketir.

API'nin Yetersiz Kaldığı Senaryolar

  • Yorum dizilerini ölçekli çekme: Binlerce video için yorum analizi yapıyorsanız API kotaları günlerce beklemenize neden olur.
  • Erken trend tespiti: Yeni yüklenen videoların anlık performans metriklerini dakikalar içinde izlemek istediğinizde API'nin güncelleme hızı yetersiz kalır.
  • Reklam izleme: API v3, videolarda hangi reklamların gösterildiğine dair hiçbir veri sunmaz; bu bilgi yalnızca sayfa scraping ile elde edilir.
  • Öneri algoritması haritalama: Bir videodan hangi önerilerin çıktığı, API'de mevcut değildir.

Giriş Yapmadan Erişilebilen Veriler

YouTube'da oturum açmadan, yalnızca sayfa istekleri ile erişebileceğiniz veriler şunlardır:

  • Video metadatası: Başlık, açıklama, yükleme tarihi, süre, kategori, etiketler
  • Etkileşim metrikleri: Görüntülenme sayısı, beğeni/beğenmeme, yorum sayısı
  • Kanal bilgileri: Kanal adı, abone sayısı, toplam video sayısı, açıklama
  • Yorum dizileri: Hem üst düzey yorumlar hem de yanıtlar
  • Transkriptler: Otomatik veya manuel altyazılar
  • Öneri videoları: Bir videonun yan panelinde listelenen öneriler

Giriş duvarlı veriler: Yaş doğrulaması gereken videolar, üyeliğe özel içerikler ve bazı özel playlist'ler erişilemez. Bu verileri çekmeye çalışmak hem etik değil hem de teknik olarak karmaşık CAPTCHA süreçleri gerektirir.

InnerTube API: YouTube'un Dahili Arayüzü

YouTube, web ve mobil istemcilerinde InnerTube adlı dahili bir JSON API kullanır. Bu endpoint'ler, YouTube'un kendi SPA'sı (Single Page Application) tarafından çağrılır ve standart HTTP istekleri ile erişilebilir.

Temel InnerTube Endpoint'leri

EndpointİşlevÖrnek Kullanım
/youtubei/v1/playerVideo oynatıcı detayları, akış bilgileriVideo metadatası, format listesi
/youtubei/v1/nextSonraki içerik, öneriler, yorumlarYorum dizisi çekimi, öneri haritalama
/youtubei/v1/browseKanal sayfası, playlist içerikleriKanal videolarını listeleme
/youtubei/v1/searchArama sonuçlarıAnahtar kelime bazlı video bulma

InnerTube İstek Yapısı

Her InnerTube isteği bir JSON body ve özel header'lar gerektirir. İşte temel bir /youtubei/v1/next isteğinin yapısı:

{
  "videoId": "dQw4w9WgXcQ",
  "context": {
    "client": {
      "clientName": "WEB",
      "clientVersion": "2.20240101"
    },
    "hl": "tr",
    "gl": "TR"
  },
  "continuation": "optional_continuation_token"
}

clientName alanını WEB, MWEB (mobil web) veya ANDROID olarak değiştirerek farklı yanıt yapıları elde edebilirsiniz. Mobil istemciler genellikle daha az CAPTCHA tetikler.

Continuation Token'lar ve Sayfalama

InnerTube, yorum ve öneri listelerini continuation token ile sayfalar. İlk yanıt bir continuationEndpoint veya continuationCommand içerir; bu token'ı sonraki isteğin continuation alanına koyarak bir sonraki sayfayı çekersiniz. Bu, API v3'ün pageToken mekanizmasına benzer, ancak kota maliyeti yoktur.

Neden Residential Proxy Zorunludur?

Google, datacenter IP aralıklarını çok iyi tanır. Bir veri merkezinden gelen yoğun istekler dakikalar içinde şu yanıtlarla karşılaşır:

  • HTTP 429 Too Many Requests
  • CAPTCHA sayfası (HTTP 200 ile dönen HTML)
  • Boş veya eksik JSON yanıtları

Residential proxy'ler, gerçek İnternet Servis Sağlayıcılarından (ISP) gelen IP adresleri kullanır. Google'ın bot filtreleri, bu IP'leri normal kullanıcı trafiği olarak değerlendirir. Bu nedenle YouTube residential proxies, ölçekli veri çekme işlemlerinde zorunludur.

IP Rotasyon Stratejileri

  • Per-request rotasyon: Her istek için yeni IP. Yorum çekimi ve arama gibi yüksek hacimli işlemler için ideal.
  • Sticky session: Aynı IP üzerinde 10-30 dakika oturum. Video metadatası çekimi gibi tutarlı oturum gerektiren işlemler için uygun.

ProxyHat ile her iki stratejiyi de kullanıcı adı parametreleri ile kontrol edebilirsiniz:

# Per-request rotasyon (her istekte yeni IP)
http://user-country-US:PASSWORD@gate.proxyhat.com:8080

# Sticky session (aynı IP üzerinde kalıcı oturum)
http://user-session-vid123-country-US:PASSWORD@gate.proxyhat.com:8080

Python ile YouTube Veri Çekme

Örnek 1: Video Metadatası ve Yorumlar (InnerTube + Proxy)

Aşağıdaki örnek, bir videonun temel metadatasını ve ilk yorum sayfasını InnerTube üzerinden çeker:

import requests
import json

PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY_URL, "https": PROXY_URL}

INNERBASE = "https://www.youtube.com/youtubei/v1/next"

HEADERS = {
    "Content-Type": "application/json",
    "User-Agent": (
        "Mozilla/5.0 (Linux; Android 12; Pixel 6) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/120.0.0.0 Mobile Safari/537.36"
    ),
    "X-YouTube-Client-Name": "2",
    "X-YouTube-Client-Version": "18.01.01",
}


def fetch_video_comments(video_id: str, max_pages: int = 5):
    """InnerTube /next endpoint ile yorum çeker."""
    all_comments = []
    continuation = None

    payload = {
        "videoId": video_id,
        "context": {
            "client": {
                "clientName": "MWEB",
                "clientVersion": "18.01.01",
            },
            "hl": "en",
            "gl": "US",
        },
    }

    for page in range(max_pages):
        if continuation:
            payload["continuation"] = continuation

        resp = requests.post(
            INNERBASE,
            json=payload,
            headers=HEADERS,
            proxies=PROXIES,
            timeout=30,
        )
        resp.raise_for_status()
        data = resp.json()

        # Yorumları çıkar (yapı değişebilir, hata yakalamalı)
        contents = data.get("contents", {})
        # MWEB yanıtı yapısı farklılık gösterebilir
        comment_section = _extract_comments(contents)
        all_comments.extend(comment_section)

        # Sonraki sayfa token'ını bul
        continuation = _find_continuation(contents)
        if not continuation:
            break

        # Rate-limit: sayfalar arası 2 saniye bekle
        import time
        time.sleep(2)

    return all_comments


def _extract_comments(contents: dict) -> list:
    """Yanıt ağacından yorum metinlerini çeker.
    YouTube sık sık yapıyı değiştirdiği için
    bu fonksiyonu güncel tutmanız gerekir."""
    comments = []
    # Basitleştirilmiş çıkarma mantığı
    try:
        renderers = contents.get(
            "singleColumnWatchNextResults", {}
        ).get("results", {}).get("results", {}).get("contents", [])
        for item in renderers:
            comment_renderer = (
                item.get("itemSectionRenderer", {})
                .get("contents", [{}])[0]
                .get("commentThreadRenderer", {})
                .get("comment", {})
                .get("commentRenderer", {})
            )
            text = comment_renderer.get("contentText", {}).get("runs", [{}])
            author = comment_renderer.get("authorText", {}).get("simpleText", "")
            comment_text = "".join(t.get("text", "") for t in text)
            if comment_text:
                comments.append({"author": author, "text": comment_text})
    except (KeyError, IndexError, TypeError):
        pass
    return comments


def _find_continuation(contents: dict):
    """Yanıt içinde continuation token'ı arar."""
    try:
        items = contents.get(
            "singleColumnWatchNextResults", {}
        ).get("results", {}).get("results", {}).get("contents", [])
        for item in items:
            cont = item.get("continuationItemRenderer", {}).get(
                "continuationEndpoint", {}
            ).get("continuationCommand", {}).get("token")
            if cont:
                return cont
    except (KeyError, TypeError):
        pass
    return None


# Kullanım
if __name__ == "__main__":
    comments = fetch_video_comments("dQw4w9WgXcQ", max_pages=3)
    for c in comments[:10]:
        print(f"{c['author']}: {c['text'][:80]}")

Örnek 2: Transkript Çekme (youtube-transcript-api + Proxy)

youtube-transcript-api kütüphanesi, YouTube'un transkript endpoint'lerini sarmalar. Proxy desteği için proxies parametresini kullanabilirsiniz:

from youtube_transcript_api import YouTubeTranscriptApi
import requests

PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY_URL, "https": PROXY_URL}


def get_transcript(video_id: str, language: str = "en"):
    """Bir videonun transkriptini çeker."""
    try:
        # youtube-transcript-api proxy desteği
        ytt_api = YouTubeTranscriptApi(
            proxy_config=PROXY_URL
        )
        transcript = ytt_api.fetch(video_id, languages=[language])

        for entry in transcript:
            print(f"[{entry['start']:.1f}s] {entry['text']}")

        return transcript
    except Exception as e:
        print(f"Transkript hatası: {e}")
        return None


if __name__ == "__main__":
    get_transcript("dQw4w9WgXcQ", "en")

Örnek 3: Kanal Video Listesi (InnerTube /browse)

import requests
import json
import time

PROXY_URL = "http://user-country-DE:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY_URL, "https": PROXY_URL}

BROWSE_URL = "https://www.youtube.com/youtubei/v1/browse"

HEADERS = {
    "Content-Type": "application/json",
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36"
    ),
    "X-YouTube-Client-Name": "1",
    "X-YouTube-Client-Version": "2.20240101",
}


def fetch_channel_videos(channel_id: str, max_pages: int = 10):
    """Bir kanalın videolarını /browse ile çeker."""
    videos = []
    continuation = None

    payload = {
        "browseId": channel_id,
        "context": {
            "client": {
                "clientName": "WEB",
                "clientVersion": "2.20240101",
            },
            "hl": "en",
            "gl": "US",
        },
    }

    for page in range(max_pages):
        if continuation:
            payload = {
                "continuation": continuation,
                "context": {
                    "client": {
                        "clientName": "WEB",
                        "clientVersion": "2.20240101",
                    },
                },
            }

        resp = requests.post(
            BROWSE_URL,
            json=payload,
            headers=HEADERS,
            proxies=PROXIES,
            timeout=30,
        )
        resp.raise_for_status()
        data = resp.json()

        # Video öğelerini çıkar
        new_videos = _extract_videos(data)
        videos.extend(new_videos)

        continuation = _find_browse_continuation(data)
        if not continuation:
            break

        time.sleep(3)  # Sayfalar arası bekleme

    return videos


def _extract_videos(data: dict) -> list:
    """Browse yanıtından video başlıklarını ve ID'leri çıkarır."""
    videos = []
    try:
        tabs = data.get("contents", {}).get(
            "twoColumnBrowseResultsRenderer", {}
        ).get("tabs", [])
        for tab in tabs:
            content = tab.get("tabRenderer", {}).get("content", {})
            items = content.get(
                "richGridRenderer", {}
            ).get("contents", [])
            for item in items:
                vid = item.get("richItemRenderer", {}).get(
                    "content", {}
                ).get("videoRenderer", {})
                if vid:
                    videos.append({
                        "videoId": vid.get("videoId", ""),
                        "title": vid.get("title", {}).get(
                            "runs", [{}]
                        )[0].get("text", ""),
                        "views": vid.get("viewCountText", {}).get(
                            "simpleText", ""
                        ),
                    })
    except (KeyError, IndexError, TypeError):
        pass
    return videos


def _find_browse_continuation(data: dict):
    """Browse yanıtında continuation token arar."""
    try:
        tabs = data.get("contents", {}).get(
            "twoColumnBrowseResultsRenderer", {}
        ).get("tabs", [])
        for tab in tabs:
            content = tab.get("tabRenderer", {}).get("content", {})
            items = content.get(
                "richGridRenderer", {}
            ).get("contents", [])
            for item in items:
                token = item.get(
                    "continuationItemRenderer", {}
                ).get("continuationEndpoint", {}).get(
                    "continuationCommand", {}
                ).get("token")
                if token:
                    return token
    except (KeyError, TypeError):
        pass
    return None


if __name__ == "__main__":
    vids = fetch_channel_videos("UCxxxxxxxxxxxx", max_pages=3)
    print(f"{len(vids)} video bulundu")

Örnek 4: Node.js ile Video Metadata Çekme

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

const PROXY = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080";
const agent = new HttpsProxyAgent(PROXY);

function fetchVideoMetadata(videoId) {
  const payload = JSON.stringify({
    videoId,
    context: {
      client: {
        clientName: "WEB",
        clientVersion: "2.20240101",
      },
      hl: "en",
      gl: "US",
    },
  });

  const options = {
    hostname: "www.youtube.com",
    path: "/youtubei/v1/player",
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Content-Length": Buffer.byteLength(payload),
      "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
        "AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
      "X-YouTube-Client-Name": "1",
      "X-YouTube-Client-Version": "2.20240101",
    },
    agent,
  };

  const req = https.request(options, (res) => {
    let body = "";
    res.on("data", (chunk) => (body += chunk));
    res.on("end", () => {
      const data = JSON.parse(body);
      const vd = data.videoDetails || {};
      console.log({
        title: vd.title,
        viewCount: vd.viewCount,
        author: vd.author,
        lengthSeconds: vd.lengthSeconds,
      });
    });
  });

  req.on("error", (e) => console.error(e));
  req.write(payload);
  req.end();
}

fetchVideoMetadata("dQw4w9WgXcQ");

Rate-Limit ve Fingerprint Riskleri

YouTube scraping'inde en büyük risk CAPTCHA ve IP bloklarıdır. İşte bunları minimize etmek için stratejiler:

İstek Hızı Kontrolü

  • Aralıklı istekler: Her istek arasına en az 1-3 saniye ekleyin. Ani burst trafiği, Google'ın bot dedektörünü anında tetikler.
  • Günlük hacim sınırları: Tek bir IP'den günde 500-1.000 istek makul bir üst sınırdır. Proxy havuzunuz yeterliyse bu sayıyı IP başına dağıtabilirsiniz.
  • Rastgele gecikme: Sabit 2 saniye yerine random.uniform(1.5, 4.0) gibi değişken gecikmeler kullanın; bu, trafik paterninizi daha insana benzer hale getirir.

Fingerprint Yönetimi

Google yalnızca IP'nize bakmaz. İsteğinizin browser fingerprint'ini de analiz eder:

  • User-Agent tutarlılığı: Proxy rotasyonu yaparken User-Agent'ınızı da değiştirin. Farklı işletim sistemi ve tarayıcı kombinasyonları kullanın.
  • Header sırası: HTTP header'larının gönderim sırası bile fingerprint oluşturur. requests gibi kütüphaneler sabit sıra kullanır; bu da bot olarak işaretlenme riskini artırır.
  • TLS parmak izi: Python'ın requests kütüphanesi, JA3 fingerprint ile tanınabilir. Daha gelişmiş senaryolarda curl_cffi veya tls_client gibi kütüphaneler tercih edin.

CAPTTCHA ile Başa Çıkma

CAPTTCHA alırsanız, o IP'yi geçici olarak atlayın ve bir sonraki IP ile devam edin. ProxyHat'ın geniş residential havuzu sayesinde engellenen IP'leri hızlıca değiştirebilirsiniz. CAPTCHA çözmeye çalışan servisler kullanmak, YouTube'un Hizmet Şartlarını daha da ciddi şekilde ihlal eder ve bu rehberde önerilmemektedir.

InnerTube API Derinlemesine: /youtubei/v1/next ve Continuation

/youtubei/v1/next endpoint'i, YouTube scraping'inin kalbidir. Bir video sayfasının "sonraki" sekmesine denk gelir ve şu verileri sunar:

  1. Yorum dizisi: İlk yüklemede 20 yorum; her continuation ile 20 daha.
  2. Öneri videoları: Sağ panel / mobilde alt panel önerileri.
  3. İlgili playlist bilgisi: Videonun dahil olduğu playlist'ler.

Continuation Token Akışı

Yorum çekiminin tipik akışı şöyledir:

  1. /youtubei/v1/next'e videoId ile istek gönderin.
  2. Yanıttan commentSectionRenderer içindeki continuationItemRenderer'ı bulun.
  3. Token'ı çıkarın ve bir sonraki /youtubei/v1/next isteğine continuation parametresi olarak ekleyin.
  4. Yanıt artık yorum içerir ve yeni bir continuation token sunar.
  5. Token kalmayana kadar tekrarlayın.

Pratik İpucu: InnerTube yanıt yapısı YouTube'un her güncellemesiyle değişebilir. JSON çıkarma fonksiyonlarınızı sık sık test edin ve güncelleyin. json.dumps(data, indent=2) ile yanıtları kaydedip yapıyı incelemek, debug sürecinizi hızlandırır.

Etik Scraping ve Resmi API Kullanımı

YouTube scraping güçlü bir araçtır, ancak gücüyla sorumluluk gelir. İşte etik sınırlar:

Ne Yapmalısınız?

  • Kamuya açık verilerle yetinin: Yorumlar, görüntülenme sayıları ve video başlıkları herkese açıktır. Özel veya yaş doğrulamalı içeriklere erişmeyin.
  • Yaratıcı haklarına saygı: Transkriptleri ve video içeriklerini yeniden dağıtmayın. Bu içeriklerin telif hakkı yaratıcıya aittir.
  • Veri minimizasyonu: Yalnızca ihtiyacınız olan veriyi çekin. Tüm YouTube'u indirmeye çalışmak hem etik değil hem de teknik olarak verimsiz.
  • robots.txt'i dikkate alın: YouTube'un robots.txt dosyası, belirli endpoint'lerin taranmasını yasaklar. Bu kısıtlamalara uyun.

Ne Zaman Resmi API Kullanmalısınız?

  • Kota yeterli olduğunda: Günde birkaç yüz video veya birkaç bin yorum çekiyorsanız, API v3 yeterlidir ve scraping riskini gereksiz kılar.
  • Uzun vadeli projelerde: InnerTube yapıları değişebilir ve bakım maliyeti yüksektir. API v3 kararlı bir sözleşme sunar.
  • Ticari ürünlerde: Müşterilerinize sunulan bir SaaS ürünü için, resmi API kullanmak hukuki açıdan daha güvenlidir.

Scraping, API'nin yetmediği belirli boşlukları doldurmak için kullanılmalıdır: yorum analizi ölçeklendirme, erken trend tespiti, reklam izleme ve öneri haritalama. Bu senaryolarda scraping, resmi API'nin yanında tamamlayıcı bir araç olarak konumlandırılmalıdır.

Temel Çıkarımlar

  • YouTube Data API v3 günlük 10.000 kota birimi ile sınırlıdır; arama işlemleri 100 birim tüketir ve ölçekli projeler için yetersiz kalır.
  • InnerTube API, YouTube'un dahili endpoint'leridir ve giriş yapmadan video metadatası, yorumlar, transkriptler ve önerilere erişim sağlar.
  • Residential proxy zorunludur: Google datacenter IP'lerini hızla işaretler ve bloklar. ProxyHat'ın residential havuzu bu sorunu çözer.
  • IP rotasyonu ve rate-limit kontrolü, CAPTCHA ve blokları minimize eder. Per-request rotasyon yüksek hacimli işlemler için, sticky session tutarlı oturumlar için idealdir.
  • Etik sınırlar net olmalıdır: Kamuya açık verilerle yetinin, transkriptleri dağıtmayın, yaratıcı haklarına saygı gösterin ve mümkün olduğunda resmi API'yi tercih edin.
  • InnerTube yanıt yapıları sık değişir; JSON çıkarma fonksiyonlarınızı düzenli olarak test edin ve güncelleyin.

Sonraki Adım

YouTube veri çekme projeniz için güvenilir residential proxy'ye ihtiyacınız varsa, ProxyHat fiyatlandırma sayfasını inceleyerek size uygun planı bulabilirsiniz. 190+ ülkede IP havuzu, per-request ve sticky session desteği, ve HTTP/SOCKS5 erişimi ile ölçekli YouTube scraping projelerinizi güvenle yürütebilirsiniz.

Web scraping genel rehberimizi de incelemek isterseniz: Web Scraping Rehberi. SERP izleme ile ilgili daha fazla bilgi için: SERP Tracking Kullanım Senaryosu.

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