Skip to content Skip to footer

Ekibimizin Kurduğu Python Scraping Altyapısı

Ekibimizin Kurduğu Python Scraping Altyapısı

Ekibimizin Kurduğu Python Scraping Altyapısı Nasıl Çalışıyor?

Programatik SEO (pSEO), binlerce sayfayı manuel yazmak yerine veri ve şablonlarla otomatik üretme yöntemidir. Ama bu yöntemin can damarı, doğru ve güncel veridir. Veri yoksa veya kalitesizse şablonların hiçbir önemi kalmaz.

Pixenon olarak pSEO projelerimizde içerik şablonlarını besleyen veriyi çoğunlukla iki kaynaktan alıyoruz: müşterinin kendi veri tabanı ve açık web. İkinci kaynağa ulaşmak için ise Python tabanlı bir scraping altyapısı kuruyoruz.

Neden Python?

Scraping dünyasında birden fazla araç var: Apify, Scrapy Cloud, Bright Data gibi hazır platformlar; Node.js tabanlı Playwright veya Puppeteer gibi alternatifler. Biz Python’ı seçiyoruz çünkü:

  • Ekosistemi zengin: requests, httpx, BeautifulSoup, Playwright, Selenium — hepsi Python’da olgun kütüphaneler.
  • Veri işleme ile doğal entegrasyon: Scraping sonrası temizleme, normalizasyon ve yükleme adımları için Pandas, SQLAlchemy, Pydantic kullanıyoruz. Python bu üç adımı tek dilde halletiyor.
  • Ekip içi yaygınlık: Veri, SEO ve backend ekipleri aynı dili konuşuyor; bakımı kolaylaşıyor.

Altyapının Üç Katmanı

1. Veri Toplama Katmanı

İki tür sayfayla karşılaşıyoruz: statik HTML döndüren sayfalar ve JavaScript’in içeriği tarayıcıda işlediği dinamik sayfalar.

Statik sayfalar için:

python

import httpx
from bs4 import BeautifulSoup

def fetch_static(url: str) -> BeautifulSoup:
    headers = {
        "User-Agent": "Mozilla/5.0 (compatible; PixenonBot/1.0)"
    }
    response = httpx.get(url, headers=headers, timeout=15)
    response.raise_for_status()
    return BeautifulSoup(response.text, "lxml")

httpx kullanıyoruz çünkü requests‘e kıyasla async desteği mevcut; aynı arayüzle hem senkron hem asenkron istekler yapılabiliyor. Büyük listeleri tararken asyncio ile paralel istek göndermek ciddi zaman kazandırıyor.

Dinamik sayfalar için:

JavaScript render gerektiren sayfalar (özellikle e-ticaret ve emlak siteleri) için Playwright kullanıyoruz:

python

from playwright.async_api import async_playwright

async def fetch_dynamic(url: str) -> str:
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto(url, wait_until="networkidle")
        content = await page.content()
        await browser.close()
    return content

wait_until="networkidle" parametresi, sayfanın tüm asenkron isteklerini tamamlamasını bekliyor. Bazı projelerde bunu "domcontentloaded" ile değiştirip zaman kazanıyoruz; kritik içerik DOM’a erken yükleniyorsa bu yeterli oluyor.

2. Veri Temizleme ve Normalizasyon Katmanı

Ham HTML’den çekilen veriler nadiren kullanıma hazır geliyor. Ortak sorunlar:

  • Fazla boşluklar ve özel karakterler
  • Tutarsız fiyat formatları (“1.200 TL”, “1200TL”, “1,200”)
  • Eksik alanlar (bazı ürünlerde açıklama yok)
  • Encoding sorunları (özellikle Türkçe karakter içeren eski siteler)

Temizleme adımı için Pydantic modeli kullanıyoruz. Hem validasyon hem de normalizasyonu aynı anda hallediyor:

python

from pydantic import BaseModel, validator
import re

class Product(BaseModel):
    name: str
    price: float
    description: str = ""
    category: str

    @validator("price", pre=True)
    def parse_price(cls, v):
        # "1.200,50 TL" → 1200.50
        cleaned = re.sub(r"[^\d,]", "", str(v)).replace(",", ".")
        return float(cleaned)

    @validator("name")
    def strip_name(cls, v):
        return v.strip()

Bu modeli kullanan bir scraper, eksik alan içeren veriyi otomatik olarak atıyor veya default değerle dolduruyor. Downstream’e kirli veri taşımıyoruz.

3. Depolama ve Entegrasyon Katmanı

Toplanan ve temizlenen veri nereye gidiyor? Bu projeye göre değişiyor:

Google Sheets entegrasyonu (küçük ve orta ölçekli pSEO projeleri):

Webflow, WordPress veya özel CMS’ler için içerik şablonu Google Sheets üzerinden besleniyorsa, scraper doğrudan oraya yazıyor. gspread kütüphanesi ile service account kimlik bilgisiyle erişim sağlıyoruz.

PostgreSQL / Supabase (büyük ölçekli projeler):

Binlerce satır söz konusu olduğunda ilişkisel veritabanı kullanıyoruz. SQLAlchemy ile ORM katmanı kuruyoruz; migration için Alembic. Supabase’i tercih ettiğimiz projelerde REST API üzerinden de veri çekebiliyoruz — bu özellikle headless CMS mimarilerinde işe yarıyor.

Airtable (bazı müşteri projelerinde):

Müşteri ekibinin veriyi kendi görmesi veya düzenlemesi gerekiyorsa Airtable uygun oluyor. Python API client ile yazma operasyonlarını otomatize ediyoruz.

Rate Limiting ve Etik Scraping

Bir siteyi aşırı yüklemek hem etik değil hem de IP banı riskiyle geliyor. Altyapımızda birkaç katman var:

İstek aralıkları:

python

import asyncio
import random

async def polite_fetch(url: str):
    await asyncio.sleep(random.uniform(1.5, 3.5))  # rastgele bekleme
    return await fetch_dynamic(url)

Sabit bekleme yerine rastgele aralık kullanıyoruz; bu bot tespitini zorlaştırıyor.

Retry mekanizması:

tenacity kütüphanesi ile geçici hataları (bağlantı timeout, 429 Too Many Requests) yönetiyoruz:

python

from tenacity import retry, wait_exponential, stop_after_attempt

@retry(wait=wait_exponential(min=2, max=30), stop=stop_after_attempt(4))
async def fetch_with_retry(url: str):
    return await fetch_dynamic(url)

robots.txt kontrolü:

Scraper başlamadan önce hedef sitenin robots.txt dosyasını kontrol ediyoruz. Python’ın standart kütüphanesindeki urllib.robotparser bu iş için yeterli.

Orchestration: Görevler Nasıl Planlanıyor?

Tek seferlik scraping’den ziyade çoğu pSEO projesinde periyodik veri güncelleme gerekiyor. Fiyatlar değişiyor, yeni ürünler ekleniyor, stok durumu farklılaşıyor.

Bu iş için iki yaklaşım kullanıyoruz:

Küçük ölçek: GitHub Actions. YAML ile tanımlanan bir workflow, belirli saatlerde Python scriptini tetikliyor. Basit, ücretsiz ve bakımı kolay.

Orta-büyük ölçek: Prefect veya Airflow. DAG (Directed Acyclic Graph) yapısıyla bağımlılıklı görevleri yönetiyoruz: önce kategori listesi çekilir, sonra her kategori içindeki ürünler paralel çekilir, ardından temizleme ve yükleme adımları çalışır. Hata durumunda alert geliyor, başarısız adım yeniden deneniyor.

Gerçek Bir Senaryo: Yerel Hizmet pSEO Projesi

Bir hizmet sektörü müşterisi için “şehir × hizmet” kombinasyonlarını otomatik olarak içerik şablonuna dönüştüren bir pSEO projesi kuruyoruz. Örnek: “İzmir temizlik şirketi”, “Ankara kira sözleşmesi” gibi binlerce anahtar kelime.

Bu projedeki scraping adımının amacı şu: her şehir için rakip sonuçları analiz etmek ve hangi veri noktalarının sayfada yer alması gerektiğini belirlemek (ortalama fiyat aralığı, sık aranan alt hizmetler, kullanıcı soruları vb.).

Süreç şöyle işliyor:

  1. Hedef anahtar kelimeler bir CSV veya Airtable’dan okunuyor.
  2. Her anahtar kelime için Google SERP verisine ihtiyaç duyuluyorsa SerpAPI veya ValueSERP gibi yasal API’ler kullanılıyor (Google TOS’u doğrudan SERP scraping’i yasaklıyor).
  3. Rakip sayfalardaki yapısal içerik — başlıklar, soru blokları, schema verileri — BeautifulSoup ile çekiliyor.
  4. Bu veriler Pydantic modelleri ile temizlenip Supabase’e yükleniyor.
  5. İçerik şablonu bu tablodan beslenerek her URL için özgün bir sayfa üretiyor.

Ne Yapılmaz?

Bu bölümü yazmak önemli çünkü scraping altyapısının sınırları var:

  • Login gerektiren içerik: Giriş duvarının arkasındaki veri scraping ile alınamaz. Bu sınırı aşmak site şartlarını ihlal eder.
  • Gerçek zamanlı fiyatlandırma: Anlık fiyat verisi için scraping yerine doğrudan API entegrasyonu tercih edilmeli. Scraping gecikme ve tutarsızlık üretir.
  • Büyük medya dosyaları: Görseller ve videolar scraping kapsamı dışında; bunlar için farklı bir pipeline kuruyoruz.

Özet

Pixenon’un Python scraping altyapısı şu bileşenlerden oluşuyor:

Katman Araçlar
HTTP istekleri httpx, requests
Dinamik render Playwright
HTML parse BeautifulSoup, lxml
Veri validasyonu Pydantic
Retry ve dayanıklılık tenacity
Depolama PostgreSQL / Supabase / Google Sheets
Orchestration GitHub Actions / Prefect

Bu altyapı bir araçtır, amaç değil. Scraping’in değer ürettiği nokta, çekilen verinin pSEO şablonlarına doğru ve temiz biçimde ulaşmasıdır. Veri kalitesi düştüğünde sayfanın kalitesi de düşer bu yüzden temizleme katmanına en az toplama katmanı kadar zaman ayırıyoruz.


Yorum bırakın