Kendi şirketinizin paneline her sabah elle girip bir rapor indiriyorsunuz. Panelin dışa aktarma düğmesi var, resmî bir API'si yok ve aynı beş tıklama her gün tekrarlanıyor. Bunu bir Python betiğine devretmek istediğinizde ilk duvar giriş sayfasıdır: requests.get() ile indirdiğiniz sayfa rapor değil, giriş formudur. Çünkü HTTP durumsuz bir protokoldür ve sunucu sizi ancak her isteğe eklediğiniz bir çerezden tanır.
Bu yazıda çerez ile oturumun ne olduğunu, CSRF belirtecinin neden her formda yeniden okunduğunu ve requests.Session ile bir giriş akışının nasıl kurulduğunu anlatıyoruz. Ardından oturumu diske kaydetmeyi, süresi dolunca yenilemeyi, kimlik bilgisini koddan çıkarmayı ve oturum boyunca aynı çıkış IP'sinde kalmayı ele alıyoruz. Sonunda formunu JavaScript ile gönderen siteler için Playwright'ın storage_state yöntemi var. Kod örnekleri quotes.toscrape.com üzerinde denendi.
Bu yazı hangi girişler için geçerli?
Buradaki her şey tek bir varsayıma dayanıyor: giriş yaptığınız hesap sizin, ya da hesabın sahibi size yazılı izin verdi. Kendi şirketinizin yönetim paneli, kendi mağaza hesabınız, müşterinizin "şu raporu her gün bize çekin" diye yazıyla istediği sistem. Bunun dışındaki senaryolar bu yazının konusu değil.
Koda geçmeden önce üç soru:
- Resmî bir API ya da dışa aktarma var mı? Varsa arayüzü otomatikleştirmeyin. Bir API anahtarı kararlıdır ve arayüz değiştiğinde kırılmaz; giriş otomasyonu veriye başka türlü ulaşamadığınızda başvurulan yoldur.
- Sitenin kullanım şartları ne diyor? Otomatik erişimi yasaklayan bir madde varsa hesabınız askıya alınabilir. Teknik olarak mümkün olması izinli olduğu anlamına gelmez. Konunun hukuki çerçevesini Web Scraping (Web Kazıma) Yasal mı? yazımızda ele aldık.
- İzniniz yazılı mı? Müşteri işlerinde sözlü onay yeterli değildir. Hangi hesapla, hangi sayfalardan, hangi sıklıkta veri çekeceğiniz bir sözleşmede ya da e-postada yazılı olsun.
Bu yazıda bilerek anlatılmayan dört şey var:
- Parola denemek yok. Bir listeyi form alanına sırayla yazdıran kod (credential stuffing) ya da kombinasyon üreten kod (brute force) burada geçmiyor. Bunları yapmayın: başkasının hesabına yetkisiz erişim Türk Ceza Kanunu'nun 243. maddesinin alanına girer.
- İki aşamalı doğrulama ve CAPTCHA atlatma yok. Bu kontroller hesabı korumak için konuldu; bir betikle aşmaya çalışmak, korumaya çalıştığınız hesabın güvenliğini düşürür. Kendi hesabınızda 2FA açıksa doğru yol sağlayıcının API anahtarı ya da uygulama parolası mekanizmasıdır; yoksa o iş otomatikleşmeyecek demektir.
- Başkasının hesabı yok. "Arkadaşımın hesabı", "şirketten ayrılan kişinin hesabı" ya da internette paylaşılmış kimlik bilgileri de buna dahildir.
- Oturum çerezi çalmak ya da taşımak yok. Başka birinin tarayıcısından kopyalanan çerezle açılan oturum, o kişinin kimliğine bürünmektir. Bu yazıdaki çerez dosyaları yalnız sizin kendi girişinizle üretilir ve yalnız sizin makinenizde durur.
Bir ayrım da isim benzerliği yüzünden gerekiyor: proxy sunucusuna kimlik doğrulamak (user:pass ya da IP yetkilendirme) ile hedef siteye giriş yapmak farklı iki iştir. Birincisini Proxy Kimlik Doğrulama: User:Pass ve IP Whitelist yazımızda anlattık; bu yazının konusu ikincisi.
Çerez ve oturum nedir?
HTTP durumsuzdur: sunucu, iki isteği birbirine bağlayan hiçbir şey hatırlamaz. Bu boşluğu çerezler doldurur. Sunucu yanıtına bir Set-Cookie başlığı koyar, istemci bu değeri saklar ve aynı alan adına giden sonraki isteklere Cookie başlığıyla geri gönderir. Başlığın tüm alanları MDN'in Set-Cookie sayfasında tek tek açıklanır.
"Oturum" ise bu çerezin bir anlamı olmasıdır. İki yaygın kurgu vardır:
- Sunucu tarafı oturum. Çerezde yalnız rastgele bir kimlik (
sessionid,PHPSESSID,JSESSIONID) taşınır; kullanıcının kim olduğu sunucudaki bir kayıtta durur. Sunucu o kaydı silerse oturum, çerez elinizde olsa bile biter. - İmzalı çerez. Kullanıcı bilgisi çerezin içindedir ve sunucu onu gizli bir anahtarla imzalar. Flask'ın varsayılan
sessionçerezi böyledir.
Çerezin ne kadar yaşayacağını Expires ve Max-Age belirler. RFC 6265'in 4.1.2.2 numaralı bölümü şunu söyler: bir çerezde Max-Age da Expires da yoksa, istemci onu "geçerli oturum bitene kadar" tutar. Tarayıcıda bu "tarayıcıyı kapatana kadar" demektir; bir Python betiğinde ise "süreç yaşadığı sürece". Bu yüzden betiğiniz her çalıştığında yeniden giriş yapıyorsa şaşırmayın: sakladığı çerez zaten kalıcı değildi.
Çerezin hangi isteklere ekleneceğini ise Set-Cookie başlığının şu alanları belirler:
| Alan | Ne yapar | Betikte anlamı |
|---|---|---|
Domain | Çerezin hangi alan adına gideceği | panel.ornek.com çerezi ornek.com isteğine eklenmez |
Path | Hangi yol altında geçerli olduğu | /rapor yolundaki çerez / isteğine gönderilmez |
Secure | Yalnız HTTPS üzerinden gönderilir | HTTP'ye düşen bir istek çerezi taşımaz |
HttpOnly | Sayfa içi JavaScript okuyamaz | Tarayıcı konsolundan document.cookie ile göremezsiniz, HTTP istemcisi yine görür |
SameSite | Başka siteden gelen isteklere eklenip eklenmeyeceği | Strict ise dış bağlantıdan gelen ilk istek oturumsuz görünür |
Bu tablo teorik değil, teşhis listesidir: "giriş başarılı görünüyor ama sonraki istek yine giriş sayfasına düşüyor" şikâyetlerinin çoğu Domain ya da Path uyuşmazlığından çıkar.
CSRF belirteci nedir ve neden her seferinde okunur?
Bir bankacılık sayfasında oturumunuz açıkken başka bir sitedeki gizli form sizin adınıza istek gönderebilir. Tarayıcı çerezi otomatik eklediği için sunucu bunu sizin isteğiniz sanır. Buna siteler arası istek sahteciliği (CSRF) denir.
En yaygın savunma, OWASP'ın CSRF önleme sayfasında "senkronize belirteç" diye geçen yöntemdir: sunucu her form sayfasına, o oturuma bağlı rastgele bir değeri gizli bir alan olarak gömer. Form gönderildiğinde bu değer, oturum çerezindeki karşılığıyla eşleşmek zorundadır. Başka bir sitedeki form, sizin oturumunuza ait belirteci bilemeyeceği için eşleşme tutmaz.
Bunun betik yazan taraf için üç sonucu var:
- Belirteç sabit değildir. Bir kez tarayıcıdan kopyalayıp koda gömerseniz ertesi gün çalışmaz. Her çalıştırmada giriş sayfasını indirip alanı oradan okumanız gerekir.
- Belirteç oturuma bağlıdır. Belirteci bir istekte, formu başka bir bağlantıda göndermek işe yaramaz. İkisi de aynı
Sessionnesnesinden geçmelidir; zatenSessionkullanmanın ilk nedeni bu. - Alanın adı siteye göre değişir.
csrf_token,csrfmiddlewaretoken(Django),authenticity_token(Rails),_token(Laravel) hepsi aynı işi görür. Kod yazmadan önce formun kaynağına bakın.
Belirteci gizli alan yerine bir başlıkta (X-CSRF-Token) bekleyen uygulamalarda değeri yine sayfadan okursunuz, ama gövdeye değil headers sözlüğüne koyarsınız.
Hangi yolu seçmeli?
Giriş gerektiren bir işte üç yol var ve seçimi sitenin giriş formu belirler.
| Yol | Ne zaman | Maliyeti | Zayıf yanı |
|---|---|---|---|
requests.Session | Form düz HTML, alanlar sayfada görünüyor | En düşük, tarayıcı yok | JavaScript ile üretilen alanları göremez |
Playwright storage_state | Giriş formu JavaScript ile gönderiliyor ya da belirteç betikle üretiliyor | Yüksek, gerçek tarayıcı açılır | Bellek ve süre, kurulum yükü |
| Hibrit: tarayıcıyla gir, HTTP ile devam et | Giriş karmaşık ama veri sayfaları düz HTML | Bir kerelik tarayıcı, sonrası ucuz | Çerezler iki ortam arasında taşınır, IP tutarlılığı şart |
Seçimi tahminle değil, sayfanın kaynağına bakarak yapın: <form method="post"> içinde name taşıyan input alanları görüyorsanız requests yeter. Alanlar boşsa ya da form fetch() ile gönderiliyorsa ikinci ya da üçüncü yola geçin.
requests.Session ile giriş nasıl yapılır?
Sırası önemli beş adım var: ilk dördü girişin kendisi, beşincisi sonraki çalıştırmalar için.
- Giriş sayfasını
GETile indirin. Bu yanıt iki şey getirir: henüz anonim olan bir oturum çerezi ve formdaki CSRF belirteci.Sessionçerezi kendi kavanozuna koyar. - Form alanlarını gerçekten okuyun. Tarayıcıda formu doldurup gönderin ve geliştirici araçlarının Ağ sekmesinde isteğin gövdesine bakın. Alan adları tahmin edilmez, oradan kopyalanır; gizli bir
nextya daredirectalanı varsa onu da gönderin. POSTisteğini aynıSessionile atın. Çerez kendiliğinden eklenir. Formunactionalanı başka bir yol gösteriyorsa isteği oraya gönderin.- Girişi içerikten doğrulayın. Durum kodu yanıltıcıdır: pek çok uygulama hatalı parolada da
200döner ve formu bir hata mesajıyla yeniden basar. Ölçüt, yalnız oturum açıkken görünen bir öğedir: çıkış bağlantısı, kullanıcı adı, hesap menüsü. - Çerezleri saklayın. Sonraki çalıştırma giriş adımını atlar.
Requests belgelerinin Session Objects bölümüne göre Session, çerezleri örnek boyunca saklamasının yanında aynı sunucuya giden istekler için TCP bağlantısını da yeniden kullanır. Desen HTTPX, Requests ve AIOHTTP yazımızdaki üç kütüphanede de aynıdır, yalnız sınıf adı değişir.
Çalışan örnek: quotes.toscrape.com
Aşağıdaki kod quotes.toscrape.com/login üzerinde denenmiştir. Burası scraping alıştırması için kurulmuş açık bir eğitim sitesidir ve girdiğiniz her kullanıcı adı ile parolayı kabul eder; bir kimlik doğrulaması yapmaz, yalnız akışı taklit eder. Mekanizmayı önce burada görmek, kendi hesabınızda arka arkaya başarısız giriş üretmenizi önler.
Önce çekirdek akış, dört adım:
import os
import requests
from bs4 import BeautifulSoup
BASE_URL = "https://quotes.toscrape.com"
session = requests.Session()
# 1) Giriş formunu iste: oturum çerezi ve CSRF belirteci bu yanıtla gelir
page = session.get(f"{BASE_URL}/login", timeout=20)
page.raise_for_status()
token = BeautifulSoup(page.text, "html.parser").select_one('input[name="csrf_token"]')["value"]
# 2) Kimlik bilgisi koda gömülmez, ortam değişkeninden okunur
payload = {
"csrf_token": token,
"username": os.environ["SITE_USERNAME"],
"password": os.environ["SITE_PASSWORD"],
}
# 3) Formu aynı Session ile gönder; çerezi Session kendisi ekler
result = session.post(f"{BASE_URL}/login", data=payload, timeout=20)
result.raise_for_status()
# 4) Durum koduna değil, sayfanın içeriğine bakarak doğrula
if BeautifulSoup(result.text, "html.parser").select_one('a[href="/logout"]') is None:
raise SystemExit("Giriş doğrulanamadı")
print("Giriş başarılı, çerezler:", list(session.cookies.keys()))Kimlik bilgisini çalıştırmadan önce ortama koyun; parolayı koda yazmak onu sürüm geçmişine de yazmaktır:
export SITE_USERNAME="kullanici"
export SITE_PASSWORD="parola"
python login.pyWindows PowerShell'de $env:SITE_USERNAME = "kullanici" biçimi kullanılır. Ortam değişkenlerinin komut satırı araçlarıyla nasıl kalıcı hâle getirileceğini Wget ile Proxy Kullanımı yazımızda anlattık.
Oturum diske nasıl kaydedilir ve ne zaman yenilenir?
Her çalıştırmada yeniden giriş yapmak hesabınızın güvenlik günlüğünü gereksiz kayıtlarla doldurur; bazı uygulamalarda kısa sürede tekrarlanan girişler ek doğrulama da tetikler. Çözüm, çerez kavanozunu bir dosyaya yazıp sonraki çalıştırmada geri yüklemektir.
Aşağıdaki tam betik bunu yapar: kayıtlı çerez varsa yükler, yoksa giriş yapar, oturumun hâlâ açık olduğunu her istekte kontrol eder ve düştüyse bir kez yeniden giriş yapar. Tek seferlik olması önemli: koşulsuz bir döngü, sorun kimlik bilgisindeyse sonsuz giriş denemesine dönüşür.
import json
import os
import time
from pathlib import Path
import requests
from bs4 import BeautifulSoup
BASE_URL = "https://quotes.toscrape.com"
COOKIE_FILE = Path("session_cookies.json")
DELAY_SECONDS = 2.0
class LoginError(Exception):
"""Giriş tamamlanamadı; yeniden denemek yerine nedenine bakın."""
def build_session():
session = requests.Session()
session.headers["User-Agent"] = "rapor-betigi/1.0 (iletisim: siz@ornek.com)"
proxy_url = os.environ.get("PROXY_URL") # ör. http://user:pass@pr.proxynet.io:8000
if proxy_url:
session.proxies = {"http": proxy_url, "https": proxy_url}
return session
def save_cookies(session, path=COOKIE_FILE):
cookies = [
{"name": c.name, "value": c.value, "domain": c.domain, "path": c.path,
"expires": c.expires, "secure": c.secure}
for c in session.cookies
]
path.write_text(json.dumps(cookies), encoding="utf-8")
try:
path.chmod(0o600) # dosya parola kadar hassastır; Windows'ta etkisi sınırlıdır
except OSError:
pass
def load_cookies(session, path=COOKIE_FILE):
if not path.exists():
return False
try:
cookies = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return False
now = time.time()
for c in cookies:
if c["expires"] and c["expires"] < now:
continue # süresi dolmuş çerezi hiç yükleme
session.cookies.set(c["name"], c["value"], domain=c["domain"], path=c["path"],
expires=c["expires"], secure=c["secure"])
return True
def is_logged_in(html):
return BeautifulSoup(html, "html.parser").select_one('a[href="/logout"]') is not None
def login(session):
page = session.get(f"{BASE_URL}/login", timeout=20)
page.raise_for_status()
field = BeautifulSoup(page.text, "html.parser").select_one('input[name="csrf_token"]')
if field is None:
raise LoginError("Formda csrf_token alanı yok; sayfa yapısı değişmiş olabilir")
payload = {
"csrf_token": field["value"],
"username": os.environ["SITE_USERNAME"],
"password": os.environ["SITE_PASSWORD"],
}
result = session.post(f"{BASE_URL}/login", data=payload, timeout=20)
result.raise_for_status()
if not is_logged_in(result.text):
raise LoginError("Giriş doğrulanamadı; kimlik bilgisini ve form alanlarını kontrol edin")
save_cookies(session)
def get_page(session, path):
"""Sayfayı getirir; oturum düşmüşse yalnız bir kez yeniden giriş yapar."""
for attempt in range(2):
response = session.get(f"{BASE_URL}{path}", timeout=20)
response.raise_for_status()
if is_logged_in(response.text):
return response
if attempt == 0:
print("Oturum geçersiz, yeniden giriş yapılıyor")
session.cookies.clear()
login(session)
raise LoginError("Yeniden girişten sonra da oturum açılamadı; durun ve nedenine bakın")
def main():
session = build_session()
if load_cookies(session):
print("Kayıtlı çerezler yüklendi")
else:
print("Kayıtlı oturum yok, giriş yapılıyor")
login(session)
for number in range(1, 4):
response = get_page(session, f"/page/{number}/")
quotes = BeautifulSoup(response.text, "html.parser").select("div.quote")
print(f"Sayfa {number}: {len(quotes)} kayıt")
time.sleep(DELAY_SECONDS)
if __name__ == "__main__":
main()İlk çalıştırma "Kayıtlı oturum yok" diyerek giriş yapar, ikincisi "Kayıtlı çerezler yüklendi" diyerek doğrudan veriye geçer. Dikkat edilecek üç nokta:
- Çerez dosyası bir sırdır. İçindeki değer, o oturum için parolanın yerine geçer. Dosyayı
.gitignore'a ekleyin, yedeklere ve paylaşılan klasörlere koymayın; Playwright'ın belgeleri de durum dosyası için aynı uyarıyı yapar. - Süresi dolan çerezi yüklemeyin.
load_cookiesbunuexpiresalanına bakarak eler; yoksa betik geçersiz bir oturumla yola çıkar. - Oturumun düştüğünü içerikten anlayın. Bazı uygulamalar giriş sayfasına
302ile yönlendirir, bazıları200ile formu basar.is_logged_ingibi tek bir ölçüt ikisini de yakalar.
Oturum boyunca neden aynı IP gerekir?
Uygulamaların bir kısmı açılan oturumu, girişin yapıldığı IP adresine ya da o adresin ağına bağlar. Sonraki istek başka bir adresten gelirse oturum kapatılır, kullanıcı giriş sayfasına yönlendirilir ya da ek doğrulama istenir. Bu bir güvenlik kararıdır ve amacı çalınmış bir oturum çerezinin başka bir yerde kullanılmasını zorlaştırmaktır.
Proxy kullanan bir betikte bu şu anlama gelir: rotasyonlu bir havuz, giriş gerektiren işlerde oturumu bozar. Rotasyonlu proxy her istekte ya da kısa aralıklarla çıkış IP'sini değiştirir; giriş yaptığınız adresle rapor indirdiğiniz adres farklı olur ve uygulama sizi tanımaz. Rotasyonun nasıl çalıştığını ve hangi işler için doğru olduğunu IP Rotasyonu Nedir ve Nasıl Çalışır? yazımızda anlattık.
Doğru kurgu iki seçenekten biridir:
- Sticky Proxy ile panelden 1-60 dakika arasında seçtiğiniz süre boyunca aynı çıkış IP'sinde kalırsınız. Oturum süresi kısaysa ve iş bitince bağlantıyı bırakacaksanız bu yeter.
- ISP Proxy ile adres çalışmadan çalışmaya da sabit kalır. Panele erişimi belirli IP'lerle sınırlayan sistemlerde tek yol budur, çünkü adresi karşı tarafa bir kez bildirip listeye eklettirirsiniz.
Adresi bir API'nin izin listesine ekletme senaryosu API için Statik IP: IP Yetkilendirme Hatası Nasıl Çözülür? yazımızda, sabit IP'nin genel gerekçesi ise Web Scraping'de Engellenmeden Veri Toplama Yöntemleri yazımızın "Oturum gereken yerde sticky IP" bölümünde.
Bir yanlış okumanın önüne geçelim: sabit IP bir güvenlik kontrolünü atlatma aracı değildir. Yaptığı şey, zaten yetkili olduğunuz bir hesapta kendi trafiğinizi tutarlı göstermektir. Hesap sizin değilse sabit IP de yasal bir erişim üretmez.
Hız sınırı: betiği nazik tutmak
Giriş yapmış bir betik, anonim bir betikten daha görünürdür: istekleriniz artık bir IP adresine değil, doğrudan hesabınıza yazılır. Hız sınırına uymak burada teknik bir tercih değil, hesabınızı korumanın parçasıdır.
- Tek iş parçacığıyla başlayın. Günde bir rapor için paralellik kurmayın.
- İstekler arasına bekleme koyun. Yukarıdaki betikteki
DELAY_SECONDSbunun en basit hâlidir. 429gördüğünüzde durun. YanıttakiRetry-Afterbaşlığı ne kadar bekleyeceğinizi söyler. Kodun tamamı 429 Too Many Requests ve Rate Limit Hatası Nedir? ve Scraping'de HTTP Hata Kodları yazılarımızda.- Kendinizi tanıtın.
User-Agentalanına betiğin adını ve bir iletişim adresi yazmak, site yöneticisinin sizinle konuşabilmesini sağlar; alanın işlevi User-Agent Nedir, Nasıl Öğrenilir ve Değiştirilir? yazımızda.
Giriş JavaScript ile yapılıyorsa: Playwright storage_state
Bazı uygulamalarda giriş formu klasik bir POST göndermez: alanları JavaScript okur, belirteci tarayıcı üretir, yanıt bir API çağrısıyla gelir. Böyle bir sayfada requests ile gönderilen form sessizce başarısız olur. Bu noktada gerçek bir tarayıcı çalıştırmak gerekir.
Playwright, oturum durumunu tek bir JSON dosyasına yazabilir. Playwright'ın kimlik doğrulama belgelerine göre bu dosya çerezleri ve localStorage içeriğini birlikte taşır; yani oturum bilgisini çerez yerine localStorage içinde tutan uygulamalarda da işe yarar. Uygulama kimlik belirtecini IndexedDB içinde saklıyorsa bunu ayrıca istemeniz gerekir: context.storage_state(path=..., indexed_db=True).
import os
from pathlib import Path
from playwright.sync_api import sync_playwright
BASE_URL = "https://quotes.toscrape.com"
STATE_FILE = Path("storage_state.json")
PROXY = {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"}
with sync_playwright() as p:
browser = p.chromium.launch(proxy=PROXY)
if STATE_FILE.exists():
context = browser.new_context(storage_state=STATE_FILE) # kayıtlı oturumla aç
else:
context = browser.new_context()
page = context.new_page()
page.goto(BASE_URL)
if page.locator('a[href="/logout"]').count() == 0:
page.goto(f"{BASE_URL}/login")
page.fill("#username", os.environ["SITE_USERNAME"])
page.fill("#password", os.environ["SITE_PASSWORD"])
page.click('input[type="submit"]')
page.wait_for_selector('a[href="/logout"]') # girişin kanıtı
context.storage_state(path=STATE_FILE) # çerezler ve localStorage tek dosyada
print("Giriş yapıldı, durum kaydedildi")
else:
print("Kayıtlı durumla oturum açık")
browser.close()İlk çalıştırma giriş yapıp dosyayı yazar, ikincisi giriş adımını hiç görmez. Playwright'ın proxy ayarını ve tarayıcı kurulumunu Playwright Nedir ve Proxy ile Nasıl Kullanılır? yazımızda ayrıntılı anlattık; Selenium tarafındaki karşılığı için Selenium Proxy Entegrasyonu yazımıza bakabilirsiniz.
Hibrit desen buradan çıkar: tarayıcıyla bir kez girip storage_state.json üretir, sonra çerezleri bir requests.Session'a aktarıp veriyi ucuz yoldan çekersiniz.
import json
from pathlib import Path
import requests
state = json.loads(Path("storage_state.json").read_text(encoding="utf-8"))
session = requests.Session()
for c in state["cookies"]:
session.cookies.set(c["name"], c["value"], domain=c["domain"], path=c["path"])Bu desenin tek şartı var: tarayıcı da, ardından gelen HTTP istemcisi de aynı çıkış IP'sinden çıkmalı. İkisine farklı proxy verirseniz oturum ilk istekte düşer. Hangi tarayıcı otomasyonunun hangi işe uyduğunu Playwright ve Selenium Farkı: Hangisini Seçmeli? yazımızda karşılaştırdık.
Kullanım alanları
- Kendi panelinizden günlük rapor indirme. Dışa aktarma düğmesinin arkasındaki adres çoğu zaman düz bir dosya bağlantısıdır; oturum çerezi durdukça
requestsile indirilir. Genel kurgu veri kazıma çözümü sayfamızda. - Giriş arkasındaki bir akışı izleme. Kendi uygulamanızın giriş ve sepet adımlarını her dağıtımdan sonra denetlemek için; kurgusu uygulama testi sayfamızda.
- Müşteri sisteminden veri aktarımı. Yazılı izin ve sabit bir çıkış IP'siyle, karşı taraf o adresi kendi listesine ekleyebilir.
- Çok sayfalı listeden veri toplama. Oturum açıldıktan sonrası sıradan bir sayfalama işidir; deseni Sayfalama (Pagination) Nedir, Scraping'de Nasıl Taranır? yazımızda anlattık.
Sık yapılan hatalar ve teşhis
- Giriş sayfasına sonsuz yönlendirme. İstek
302ile/login'e dönüyorsa çerez ya hiç gönderilmiyor ya da sunucu tarafında geçersiz. Öncesession.cookiesiçeriğine bakın, sonra çerezinDomainalanını istediğiniz adresle karşılaştırın. Sessionyerinerequests.getkullanmak. Modül düzeyindekirequests.get()her çağrıda yeni bir bağlantı ve boş bir çerez kavanozu açar. Giriş akışında çalışmaz.- Girişi durum koduna bakarak doğrulamak. Hatalı parolada da
200gelebilir. İçerikten bir kanıt arayın. - CSRF belirtecini koda gömmek. Bir gün çalışır, ertesi gün "geçersiz belirteç" hatası verir.
- Oturum ortasında IP değiştirmek. Rotasyonlu bir havuzla giriş yapıp veri çekmek, oturumun düşmesinin en sık nedenidir.
- Başarısız girişte döngüye girmek. Parola yanlışsa tekrar denemek düzeltmez; bazı sistemlerde hesabı kilitler. Betik ilk başarısızlıkta durmalıdır.
Karar rehberi
| Durum | Yapılacak |
|---|---|
| Sitenin resmî API'si var | Giriş otomasyonuna hiç girmeyin, API anahtarı kullanın |
| Form düz HTML, alanlar sayfada | requests.Session ile giriş, çerezleri dosyaya kaydedin |
Formda csrf_token benzeri gizli alan | Her çalıştırmada sayfadan okuyun, koda gömmeyin |
| Form JavaScript ile gönderiliyor | Playwright ile girin, storage_state dosyasını saklayın |
| Giriş karmaşık, veri sayfaları düz | Hibrit: tarayıcıyla gir, çerezleri requests'e taşı |
| Oturum ortasında kapanıyor | Çıkış IP'sini sabitleyin: Sticky Proxy |
| Panel yalnız belirli IP'lere açık | ISP Proxy ile sabit adres |
| Hesapta iki aşamalı doğrulama var | API anahtarı ya da uygulama parolası isteyin, doğrulamayı aşmaya çalışmayın |
| Hesap sizin değil | Durun; sahibinden yazılı izin alın |
Sıkça sorulan sorular
Session ile cookie arasındaki fark nedir?
Çerez, sunucunun tarayıcınıza ya da istemcinize sakladığı küçük bir veri parçasıdır ve her istekte geri gönderilir. Oturum ise o çerezin işaret ettiği durumdur: kim olduğunuz, ne zamandan beri giriş yaptığınız, hangi yetkileriniz olduğu. Python tarafında requests.Session bu ikisini birleştiren nesnedir; çerezleri saklar ve istekler arasında taşır.
Giriş yaptım ama sonraki istek yine giriş sayfasına düşüyor, neden?
En sık üç neden var. Birincisi, giriş isteğini Session dışında atmışsınızdır ve çerez kaybolmuştur. İkincisi, çerezin Domain ya da Path alanı isteğinizin adresiyle uyuşmuyordur. Üçüncüsü, uygulama oturumu IP'ye bağlamıştır ve rotasyonlu bir proxy yüzünden ikinci istek başka adresten gelmiştir.
CSRF belirtecini bir kere alıp saklayabilir miyim?
Hayır. Belirteç oturuma bağlıdır ve oturum yenilendiğinde değişir. Her çalıştırmada giriş sayfasını indirip alanı oradan okumanız gerekir. Saklanacak şey belirteç değil, girişten sonra gelen oturum çerezidir.
Şifreli bir siteden veri çekmek suç mu?
Belirleyici olan sitenin şifreli olması değil, o hesaba erişim yetkinizin olup olmadığıdır. Kendi hesabınızdan kendi verinizi çekmek olağan bir kullanımdır; başkasının kimlik bilgisiyle giriş yapmak yetkisiz erişimdir ve Türk Ceza Kanunu'nun bilişim suçları bölümünün alanına girer. Kullanım şartları otomatik erişimi yasaklıyorsa kendi hesabınızda bile sözleşmeye aykırı davranmış olursunuz. Ayrıntısı Web Scraping (Web Kazıma) Yasal mı? yazımızda.
Oturum çerezi ne kadar süre geçerli olur?
Uygulamaya göre değişir. Max-Age ya da Expires taşımayan bir çerez, istemci kapandığında biter. Süre taşıyanlar birkaç saatten birkaç haftaya kadar yaşayabilir, ama sunucu kendi tarafındaki kaydı sildiğinde çerez elinizde olsa bile oturum biter. Bu yüzden betikte "süresi doldu mu" kontrolü yerine "oturum hâlâ açık mı" kontrolü yapılır.
Giriş yaptıktan sonra proxy'yi değiştirebilir miyim?
Değiştirmemek gerekir. Oturumu açan IP ile sonraki isteklerin çıktığı IP farklıysa uygulama oturumu kapatabilir ya da ek doğrulama isteyebilir. Aynı iş içinde hem tarayıcı hem HTTP istemcisi kullanıyorsanız ikisine de aynı proxy'yi verin.
Özetle
Giriş gerektiren bir işte teknik çekirdek küçüktür: requests.Session çerezleri taşır, giriş sayfasından okunan CSRF belirteci forma eklenir, sonuç durum koduna değil sayfa içeriğine bakılarak doğrulanır ve oturum bir dosyaya kaydedilip sonraki çalıştırmaya devredilir. Formunu JavaScript ile gönderen sitelerde aynı işi Playwright'ın storage_state dosyası yapar. Oturumun düşmemesi için çıkış IP'si oturum boyunca değişmemeli; bunun için Sticky Proxy ya da sabit adres kullanılır. Ön koşul ise değişmez: hesap sizin olacak ya da sahibinin yazılı izni bulunacak, resmî bir API varsa önce o denenecek. Uygun proxy türlerini proxy hizmetlerimizde bulabilirsiniz.




