LinkedIn'den Açık Veri Toplama: Proxy Kullanımı ve Etik Sınırlar

LinkedIn'den kamu verisi toplamanın yasal ve teknik sınırlarını, hiQ Labs davasını, residential proxy gerekliliğini ve Playwright ile güvenli uygulama yöntemlerini kapsamlı şekilde ele alan rehber.

LinkedIn'den Açık Veri Toplama: Proxy Kullanımı ve Etik Sınırlar

LinkedIn, dünyanın en büyük profesyonel ağ platformu olarak milyarlarca profil, şirket sayfası ve iş ilanına ev sahipliği yapıyor. Bu veri hazinesi, işe alım araçları geliştirenler, pazar araştırması ekipleri ve rekabet analizi yapanlar için büyük değer taşıyor. Ancak LinkedIn'den veri toplamak, hem teknik zorluklar hem de ciddi yasal ve etik sorumluluklar içeriyor.

Bu rehber, sadece kamuya açık verilere odaklanacak, özel verilere erişimin neden kabul edilemez olduğunu açıklayacak ve residential proxy kullanımının teknik gerekliliğini detaylandıracak. HiQ Labs v. LinkedIn davasını referans alarak mevcut yasal durumu tartışacağız — ancak bu yazı hukuki tavsiye niteliği taşımaz; her zaman kendi hukuk danışmanınıza başvurun.

Yasal Uyarı: CFAA ve Kamu Verisi Erişimi

Amerika Birleşik Devletleri'nde Bilgisayar Dolandırıcılığı ve Kötüye Kullanım Yasası (CFAA), yetkisiz bilgisayar erişimini suç sayıyor. Ancak hiQ Labs, Inc. v. LinkedIn Corporation davası (2017–2022), bu yasının kamuya açık verilere nasıl uygulandığına dair önemli bir emsal oluşturdu.

hiQ Labs v. LinkedIn özeti:

  • hiQ Labs, LinkedIn'in kamuya açık profil verilerini toplayarak çalışan analitiği hizmeti sunuyordu
  • LinkedIn, 2017'de hiQ'ya erişimi durdurmasını talep eden bir cease-and-desist mektubu gönderdi
  • hiQ, LinkedIn'in bu engellemeyen CFAA'yı ihlal ettiğini iddia ederek dava açtı
  • 9. Circuit Temyiz Mahkemesi (2019), kamuya açık verilerin toplanmasının CFAA kapsamında "yetkisiz erişim" sayılamayacağına hükmetti
  • LinkedIn ABD Yüksek Mahkemesi'ne başvurdu, ancak Yüksek Mahkeme davayı reddetti (2022)

Önemli: Bu dava, kamuya açık verilere erişimin belirli koşullarda CFAA ihlali sayılmayabileceğini gösteriyor. Ancak her ülkenin kendi yasaları var — AB'de GDPR, veri işleme için meşru bir gerekçe talep ediyor. Türkiye'de KVKK benzer yükümlülükler getiriyor. Her zaman kendi yargı alanınıza uygun hukuki danışmanlık alın.

Kamuya Açık LinkedIn Verisi Nedir?

LinkedIn'de oturum açmadan (logged-out) erişilebilen veriler:

Kamu Profilleri

  • URL formatı: linkedin.com/in/{username}
  • Ad, soyad, profil fotoğrafı
  • Mevcut pozisyon ve şirket
  • Eğitim geçmişi (kısmen)
  • Konum bilgisi

Erişilemeyen: Bağlantılar listesi, mesajlar, tam iş geçmişi, beceriler, onaylar, özel gizlilik ayarlı profiller.

Şirket Sayfaları

  • URL formatı: linkedin.com/company/{company-name}
  • Şirket adı, logo, endüstri
  • Şirket boyutu, konum
  • Açık pozisyon sayısı

İş İlanları

  • URL formatı: linkedin.com/jobs/view/{job-id}
  • Pozisyon başlığı, şirket, konum
  • İş tanımı, gereklilikler
  • Başvuru tarihi

Kritik ayrım: LinkedIn, oturum açmadan görüntülenen sayfalarda sınırlı veri sunuyor. "Giriş yaparak daha fazla görün" uyarıları, bu verilerin kamuya açık olmadığını gösterir.

Neden Residential Proxy Şart?

LinkedIn, bot tespiti konusunda dünyadaki en gelişmiş sistemlerden birine sahip. Datacenter IP'leri neredeyse anında tespit ediliyor ve engelleniyor. İşte residential proxy kullanımının teknik nedenleri:

1. IP Fingerprinting ve ASN Analizi

LinkedIn, IP bloklarının ASN (Autonomous System Number) kayıtlarını analiz ediyor. Datacenter ASN'leri (AWS, Google Cloud, DigitalOcean, vb.) otomatik olarak şüpheli işaretleniyor. Residential ASN'ler ise gerçek İSS'lere ait olduğu için meşru trafik gibi görünüyor.

2. Per-IP Rate Limiting

LinkedIn, tek bir IP'den gelen isteklerde agresif sınırlama uyguluyor:

  • ~50–100 sayfa/saat oturum açmadan görüntüleme
  • Her engel 24–72 saat sürebilir
  • "429 Too Many Requests" veya CAPTCHA sayfası döner

3. Browser Fingerprinting

Sadece IP değil, tarayıcı parmak izi de kontrol ediliyor:

  • Canvas fingerprint
  • WebGL renderer
  • Font listesi
  • Ekran çözünürlüğü
  • Timezone ve dil ayarları

Playwright veya Puppeteer kullanırken bu izleri minimize etmek için gerçekçi browser context'ler oluşturmak şart.

4. Behavioral Analysis

LinkedIn, insan davranışını taklit etmeyen istekleri tespit ediyor:

  • Saniyede 10 sayfa istemek = bot
  • Sayfada 0.1 saniye kalmak = bot
  • Hiç kaydırma yapmamak = bot

Python + Playwright ile Güvenli Uygulama

Aşağıdaki örnek, residential proxy kullanarak LinkedIn kamu profillerini toplayan bir Playwright script'i içerir. ProxyHat residential proxy servisi kullanılmaktadır.

Kurulum

pip install playwright asyncio
playwright install chromium

Temel Script

import asyncio
import random
from playwright.async_api import async_playwright

class LinkedInScraper:
    def __init__(self, proxy_user: str, proxy_pass: str):
        self.proxy_user = proxy_user
        self.proxy_pass = proxy_pass
        # ProxyHat residential proxy - ülke bazlı hedefleme
        self.proxy_url = f"http://{proxy_user}-country-US:{proxy_pass}@gate.proxyhat.com:8080"
        
    async def create_browser_context(self, playwright):
        """Gerçekçi browser context oluşturur"""
        browser = await playwright.chromium.launch(
            proxy={"server": self.proxy_url},
            headless=True
        )
        
        # Gerçekçi viewport ve user agent
        context = await browser.new_context(
            viewport={"width": 1920, "height": 1080},
            user_agent=(
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/120.0.0.0 Safari/537.36"
            ),
            locale="en-US",
            timezone_id="America/New_York"
        )
        
        return browser, context
    
    async def scrape_profile(self, url: str) -> dict:
        """Tek bir kamu profili toplar"""
        async with async_playwright() as p:
            browser, context = await self.create_browser_context(p)
            page = await context.new_page()
            
            try:
                # Sayfaya git
                await page.goto(url, wait_until="networkidle", timeout=30000)
                
                # İnsan taklidi bekleme
                await asyncio.sleep(random.uniform(2, 5))
                
                # Sayfayı kaydır (bot tespiti karşıtı)
                await page.evaluate("window.scrollBy(0, 300)")
                await asyncio.sleep(random.uniform(0.5, 1.5))
                
                # Veriyi çek
                profile_data = await page.evaluate("""() => {
                    const name = document.querySelector('h1')?.innerText || null;
                    const headline = document.querySelector('.text-body-medium')?.innerText || null;
                    const location = document.querySelector('.text-body-small.inline')?.innerText || null;
                    return { name, headline, location };
                }""")
                
                return profile_data
                
            except Exception as e:
                print(f"Hata: {e}")
                return None
                
            finally:
                await browser.close()

# Kullanım
async def main():
    scraper = LinkedInScraper(
        proxy_user="kullanici_adi",
        proxy_pass="sifre"
    )
    
    profile = await scraper.scrape_profile(
        "https://www.linkedin.com/in/some-public-profile/"
    )
    print(profile)

asyncio.run(main())

Rate Limiting Stratejisi

import time
from collections import deque

class RateLimiter:
    """Token bucket algoritması ile rate limiting"""
    def __init__(self, requests_per_hour: int = 30):
        self.requests_per_hour = requests_per_hour
        self.requests = deque()
        self.min_interval = 3600 / requests_per_hour  # saniye başına istek
        
    def wait_if_needed(self):
        now = time.time()
        
        # Eski istekleri temizle (1 saatten eski)
        while self.requests and now - self.requests[0] > 3600:
            self.requests.popleft()
        
        # Limit kontrolü
        if len(self.requests) >= self.requests_per_hour:
            sleep_time = 3600 - (now - self.requests[0])
            if sleep_time > 0:
                print(f"Rate limit: {sleep_time:.0f} saniye bekleniyor...")
                time.sleep(sleep_time)
        
        # Minimum aralık kontrolü
        if self.requests:
            elapsed = now - self.requests[-1]
            if elapsed < self.min_interval:
                time.sleep(self.min_interval - elapsed)
        
        self.requests.append(time.time())

# Kullanım
limiter = RateLimiter(requests_per_hour=25)  # Muhafazakar limit

for profile_url in profile_urls:
    limiter.wait_if_needed()
    # scrape_profile() çağır

Session Rotation ile Proxy Kullanımı

Her profil için farklı bir IP kullanmak, tek IP'de engellenme riskini azaltır:

def get_proxy_url(session_id: str) -> str:
    """Her istek için farklı session/IP"""
    return f"http://user-session-{session_id}:pass@gate.proxyhat.com:8080"

# Session ID oluştur
import uuid
session_id = str(uuid.uuid4())[:8]
proxy_url = get_proxy_url(session_id)

LinkedIn İş İlanları Toplama

LinkedIn Jobs, kamu erişimine daha açık olsa da, yine de rate limiting ve fingerprinting uygulanıyor.

Jobs Search URL Yapısı

LinkedIn'in iş arama URL'si sorgu parametreleri ile çalışır:

BASE_URL = "https://www.linkedin.com/jobs/search/"

# Parametreler
params = {
    "keywords": "software engineer",
    "location": "San Francisco",
    "f_JT": "F",  # Tam zamanlı
    "f_E": "2",   # Deneyim seviyesi (1=Intern, 2=Entry, 3=Associate...)
    "start": 0,     # Pagination offset (0, 25, 50...)
}

# URL oluştur
from urllib.parse import urlencode
url = f"{BASE_URL}?{urlencode(params)}"

Jobs Scraper Örneği

import aiohttp
import asyncio
from bs4 import BeautifulSoup

class LinkedInJobsScraper:
    def __init__(self, proxy_user: str, proxy_pass: str):
        self.proxy_auth = aiohttp.BasicAuth(proxy_user, proxy_pass)
        self.proxy_url = "http://gate.proxyhat.com:8080"
        
    async def fetch_jobs_page(self, session, keywords: str, location: str, start: int = 0):
        """Tek bir jobs sayfasını çeker"""
        params = {
            "keywords": keywords,
            "location": location,
            "start": start
        }
        
        headers = {
            "User-Agent": (
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36"
            ),
            "Accept-Language": "en-US,en;q=0.9"
        }
        
        url = f"https://www.linkedin.com/jobs/search/?{urlencode(params)}"
        
        async with session.get(
            url, 
            proxy=self.proxy_url,
            proxy_auth=self.proxy_auth,
            headers=headers,
            timeout=aiohttp.ClientTimeout(total=30)
        ) as response:
            if response.status == 429:
                raise Exception("Rate limited - bekleyin")
            return await response.text()
    
    def parse_jobs(self, html: str) -> list:
        """HTML'den iş ilanlarını ayrıştırır"""
        soup = BeautifulSoup(html, "html.parser")
        jobs = []
        
        # LinkedIn jobs kartları
        job_cards = soup.select(".jobs-search__results-list li")
        
        for card in job_cards:
            title_elem = card.select_one(".base-search-card__title")
            company_elem = card.select_one(".base-search-card__subtitle")
            location_elem = card.select_one(".job-search-card__location")
            link_elem = card.select_one("a.base-card__full-link")
            
            if title_elem and company_elem:
                jobs.append({
                    "title": title_elem.get_text(strip=True),
                    "company": company_elem.get_text(strip=True),
                    "location": location_elem.get_text(strip=True) if location_elem else None,
                    "url": link_elem["href"] if link_elem else None
                })
        
        return jobs
    
    async def scrape_jobs(self, keywords: str, location: str, max_pages: int = 5):
        """Birden fazla sayfa toplar"""
        connector = aiohttp.TCPConnector(limit=1)  # Tek bağlantı
        
        async with aiohttp.ClientSession(connector=connector) as session:
            all_jobs = []
            
            for page in range(max_pages):
                start = page * 25
                
                # Rate limiting
                await asyncio.sleep(random.uniform(3, 7))
                
                html = await self.fetch_jobs_page(session, keywords, location, start)
                jobs = self.parse_jobs(html)
                
                if not jobs:
                    break  # Daha fazla sonuç yok
                    
                all_jobs.extend(jobs)
                print(f"Sayfa {page + 1}: {len(jobs)} iş ilanı")
            
            return all_jobs

# Kullanım
async def main():
    scraper = LinkedInJobsScraper("kullanici_adi", "sifre")
    jobs = await scraper.scrape_jobs(
        keywords="python developer",
        location="Berlin",
        max_pages=3
    )
    print(f"Toplam: {len(jobs)} iş ilanı")

asyncio.run(main())

Hangi Durumlarda Toplama YapMAYIN

Bazı veri türleri ve erişim yöntemleri kesinlikle yasal ve etik sınırlar dışındadır:

1. Oturum Açarak (Logged-In) Erişim

Kendi hesabınızla giriş yapıp veri toplamak:

  • LinkedIn Kullanım Sözleşmesi'ni ihlal eder
  • Hesabınız kalıcı olarak yasaklanabilir
  • CFAA kapsamında "yetkisiz erişim" olarak değerlendirilebilir

2. Sales Navigator ve Premium Veriler

Ücretli abonelikle erişilen veriler:

  • Gelişmiş arama filtreleri
  • InMail mesajları
  • Detaylı şirket analitikleri
  • Lead önerileri

3. Özel (Private) Profiller

Gizlilik ayarları "private" olarak belirlenmiş profiller:

  • "LinkedIn üyesi" olarak görünen profiller
  • Sadece bağlantıların görebildiği veriler

4. Mesajlar ve İletişim Verileri

  • Inbox mesajları
  • E-posta adresleri (çoğu durumda)
  • Telefon numaraları

5. Bağlantı Ağları

  • Bir kullanıcının bağlantı listesi
  • 2. ve 3. derece bağlantı detayları

Altın kural: Eğer veriyi oturum açmadan, gizli modda (incognito) göremiyorsanız — o veri kamuya açık değildir ve toplamamalısınız.

Alternatif: Resmi LinkedIn API'leri

LinkedIn, belirli kullanım durumları için resmi API'ler sunuyor. Bu API'ler yasal ve güvenilir veri erişimi sağlar:

API Hedef Kullanıcı Veri Türü Fiyatlandırma
LinkedIn Recruiter System Connect İşe alım platformları Aday profilleri (onaylı) Kurumsal anlaşma
Marketing Developer Platform Reklam teknolojisi Reklam metrikleri, audience Kullanım bazlı
Profile API Onaylı ortaklar Profil verisi (kullanıcı onayı şart) Değişken
Share API Sosyal medya araçları Paylaşım oluşturma Ücretsiz

API Kullanmanın Avantajları

  • Yasal güvence: LinkedIn ile doğrudan sözleşme
  • Stabil veri: Format değişikliklerinden etkilenmez
  • Destek: Teknik dokümantasyon ve destek
  • Rate limits: Net ve öngörülebilir sınırlar

API Kullanmanın Dezavantajları

  • Onay süreci: LinkedIn partner olmak zorunda
  • Maliyet: Kurumsal düzeyde ücretler
  • Kısıtlı kapsam: Sadece belirli veri türleri
  • Kullanıcı onayı: Bazı veriler için kullanıcı izni şart

Etik Veri Toplama İlkeleri

Yasal sınırların ötesinde, etik veri toplama için şu ilkeleri izleyin:

1. Saygılı Rate Limiting

LinkedIn'in altyapısına aşırı yük bindirmeyin. Dakikada 1–2 sayfa gibi muhafazakar sınırlar koyun.

2. Robots.txt Kontrolü

LinkedIn'in robots.txt dosyasını inceleyin:

# linkedin.com/robots.txt (örnek)
User-agent: *
Disallow: /search/
Disallow: /jobs/api/
Allow: /jobs/view/
Allow: /in/
Allow: /company/

3. Veri Minimizasyonu

Sadece gerçekten ihtiyacınız olan veriyi toplayın. Tüm profili değil, sadece gerekli alanları alın.

4. KVKK/GDPR Uyumu

AB'den veya Türkiye'den toplanan kişisel veriler için:

  • Veri işleme amacını belgeleyin
  • Meşru bir gerekçe belirleyin
  • Veri saklama sürelerini sınırlayın
  • Kişilerin erişim/silme taleplerini karşılayın

5. Veri Güvenliği

Toplanan kişisel verileri güvenli saklayın:

  • Şifreli depolama
  • Erişim kontrolü
  • Gerektiğinde anonimleştirme

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

Aşağıdaki durumlarda scraping yerine resmi API'leri tercih edin:

  • Üretim sistemi: Müşterilerinize hizmet veren bir ürün geliştiriyorsanız
  • Ölçeklenebilirlik: Binlerce profil toplamanız gerekiyorsa
  • Yasal güvence: Hukuki risk almak istemiyorsanız
  • Veri kalitesi: Doğru ve güncel veri kritikse
  • Uzun vadeli: Proje yıllar sürecekse

Scraping, araştırma, prototipleme ve küçük ölçekli analizler için uygun olabilir. Üretim sistemleri için resmi API'ler veya LinkedIn Partner Program'ı değerlendirin.

Key Takeaways

  • Sadece kamuya açık veriyi hedefleyin: Oturum açmadan görünen profiller, şirket sayfaları ve iş ilanları. Private veriler ve Sales Navigator içeriği kesinlikle yasak.
  • Residential proxy şart: LinkedIn datacenter IP'leri anında engelliyor. Residential ASN'ler gerçek kullanıcı trafiği gibi görünür.
  • hiQ Labs emsali: ABD'de kamuya açık veri toplama belirli koşullarda CFAA ihlali sayılmayabilir, ancak her ülkenin yasaları farklı. Kendi hukuk danışmanınıza başvurun.
  • Rate limiting kritik: Saatte 25–30 sayfa gibi muhafazakar sınırlar koyun. İnsan taklidi bekleme süreleri ve sayfa kaydırma kullanın.
  • Resmi API'leri değerlendirin: Üretim sistemleri için LinkedIn Recruiter System Connect veya Marketing Developer Platform daha güvenli ve yasal.
  • GDP/KVKK uyumu: Kişisel veri işleme için meşru gerekçe belirleyin, veri minimizasyonu uygulayın, güvenli saklama sağlayın.

Sonuç

LinkedIn'den kamuya açık veri toplamak, doğru teknik yaklaşım ve yasal/etik sınırlara uyumla mümkün. Residential proxy kullanımı, gerçekçi browser context'ler ve muhafazakar rate limiting, teknik başarının anahtarları.

Ancak unutmayın: yasal olmak ile etik olmak aynı şey değil. Sadece yasalara uymak yetmez; kullanıcıların gizliliğine saygı göstermek, platformun kurallarını dikkate almak ve veriyi sorumlu şekilde kullanmak da etik sorumluluğunuz.

ProxyHat olarak, residential proxy hizmetlerimizle yasal veri toplama projelerinize destek sunuyoruz. Daha fazla bilgi için web scraping kullanım senaryoları sayfamızı inceleyebilirsiniz.

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