---
title: "Playwright Timeout 30000ms Exceeded Hatası Nasıl Çözülür?"
description: "Playwright timeout 30000ms exceeded hatası, sayfa açma, locator, expect kontrolü ya da testin tamamı için süre dolunca çıkar. Call log'u okuyup nedeni düzeltin."
url: https://proxynet.io/tr/blog/playwright-timeout
date: 2026-10-05
author: "Acar Diveroli"
category: "Nasıl Yapılır, Web Scraping"
lang: tr
---

# Playwright Timeout 30000ms Exceeded Hatası Nasıl Çözülür?

Fiyat kontrol betiğiniz kendi bilgisayarınızda sorunsuz çalışıyor. Betiği sunucuya taşıyıp trafiği proxy üzerinden geçiriyorsunuz ve yarım dakika sonra günlükte `TimeoutError: page.goto: Timeout 30000ms exceeded.` satırı beliriyor. Bir sonraki çalıştırmada sayfa açılıyor, ama bu kez betik bir satır sonra `locator.click: Timeout 30000ms exceeded.` hatasıyla duruyor. Sayıyı 60000 yapıyorsunuz; betik artık tam bir dakika bekleyip düşüyor, çünkü sorun hiçbir zaman sayıda değildi.

Bu yazıda dört zaman aşımı türünü, mesajın altındaki call log'u, `waitUntil` seçeneklerini, süre sınırlarının nerede ayarlanacağını, yavaş proxy'leri ve "öğe bulunamadı"ya dönüşen engel sayfalarını anlatıyoruz. Ardından Python ve Node.js'te çalıştırıp sınadığımız bir yeniden deneme betiğini ve Puppeteer karşılığını veriyoruz. Aşağıdaki bütün hata mesajlarını Playwright 1.63 ve Puppeteer 25.12 ile, yerel bir test sitesi ve test proxy'si üzerinde kendimiz ürettik.

> **Not: Kısa cevap**
>
> "Timeout 30000ms exceeded", Playwright'ın varsayılan süre olan 30 saniye boyunca beklediği şeyin gerçekleşmediği anlamına gelir. Mesajın ilk kelimeleri neyin beklendiğini gösterir: `page.goto` sayfanın yüklenmesini, `locator.click` öğenin bulunup tıklamayı kabul etmesini, `expect(...)` bir koşulun sağlanmasını (varsayılan 5 saniye) bekler; "Test timeout of 30000ms exceeded" ise Playwright Test'in bir testin tamamına tanıdığı süredir. Call log'un son satırlarını okuyun, sonra nedeni düzeltin: sayfayı `domcontentloaded` ile açıp ihtiyacınız olan öğeyi bekleyin, seçiciyi ya da öğenin üstünü kapatan katmanı düzeltin, içeriği beklemeden önce yanıtın durum koduna bakın ve süre sınırlarını ölçtüğünüz yükleme sürelerine göre belirleyin.

## Playwright'ta "Timeout 30000ms exceeded" ne anlama gelir?

Playwright beklemeyi kendisi yapar: `page.goto()` sayfa belirli bir yükleme aşamasına gelene kadar, locator üzerindeki her eylem de öğe bulunup o eyleme hazır olana kadar bekler. Bekleme süre sınırına ulaşınca Playwright bir `TimeoutError` fırlatır. Kütüphanede bu sınır 30000 ms, yani 30 saniyedir; Python ve Node.js denemelerimizin ikisi de tam 30,0 saniyede durdu.

Mesaj bekleyen metodu, süre sınırını ve "Call log" başlığı altında Playwright'ın o sırada ne yaptığını gösterir. Aşağıdaki mesaj, sunucusu hiç cevap vermeyen bir test sayfasından geldi:

```text
TimeoutError: page.goto: Timeout 30000ms exceeded.
Call log:
  - navigating to "http://127.0.0.1:8090/slow", waiting until "load"
```

Python `Page.goto` ve `Locator.click` diye büyük harfle, Node.js `page.goto` ve `locator.click` diye küçük harfle yazar. Python'da sınıfı başka bir adla içe aktarın: `playwright.sync_api` içindeki `TimeoutError`, Python'ın yerleşik `TimeoutError` sınıfını gölgeler. Node.js'te sınıf `playwright` paketindeki `errors.TimeoutError`'dır.

## Hangi zaman aşımı doldu? Dört tür

Scraper'ların kullandığı kütüphane, navigasyona (sayfa açma) ve eylemlere ayrı ayrı 30 saniye tanır. Playwright Test çalıştırıcısı ise bunlara ayrı bir sınır koymaz, testin tamamına 30 saniye verir; [Playwright'ın zaman aşımı dokümantasyonu](https://playwright.dev/docs/test-timeouts) bunu tablo hâlinde listeler. JavaScript API başvurusunun `goto` için varsayılanı 0 diye yazmasının nedeni de budur.

| Mesajın başı | Tür | Varsayılan | Nasıl değiştirilir |
|---|---|---|---|
| `page.goto: Timeout …` | Navigasyon | 30 sn (kütüphane), yok (Test) | Çağrıda `timeout`, `set_default_navigation_timeout()`, `navigationTimeout` |
| `locator.click: Timeout …` | Eylem ya da locator | 30 sn (kütüphane), yok (Test) | Çağrıda `timeout`, `set_default_timeout()`, `actionTimeout` |
| `expect(locator)… failed` ve `Timeout: 5000ms` | Doğrulama (assertion) | 5 sn | `expect: { timeout }`, Python'da `expect.set_options(timeout=…)` |
| `Test timeout of 30000ms exceeded.` | Testin tamamı (Playwright Test) | 30 sn | Config'de `timeout`, `test.setTimeout()`, `test.slow()` |

Denemelerimizden iki ayrıntı: Python'da başarısız bir `expect()` düz bir `AssertionError` fırlatır ve `except PlaywrightTimeoutError` onu yakalamaz. Test süresi `page.goto` sırasında dolduğunda ise Playwright Test, zaman aşımı satırının altına `page.goto: net::ERR_ABORTED; maybe frame was detached?` ekler. Bu bir ağ hatası değildir: çağrı beklerken çalıştırıcı sayfayı kapatmıştır.

## Call log nasıl okunur?

Mesajın en yararlı kısmı call log'dur (çağrı kaydı). Aşağıda, üstünü bir çerez bildirimi kapatan bir düğmeye tıklama denemesi var; kendi çalıştırmamızdan kısaltarak aldık:

```text
Locator.click: Timeout 5000ms exceeded.
Call log:
  - waiting for locator("#buy")
    - locator resolved to <button id="buy">Add to cart</button>
  - attempting click action
    2 × waiting for element to be visible, enabled and stable
      - element is visible, enabled and stable
      - scrolling into view if needed
      - done scrolling
      - <div id="cookie-banner">We use cookies</div> intercepts pointer events
    - retrying click action
```

Dört adımda okuyun:

1. **İlk satırdaki metot** neyin beklendiğini söyler: `goto`, `click`, `fill`, `textContent`.
2. **Call log'daki son adım** beklemenin nerede kaldığını gösterir. Altında hiçbir şey olmayan `waiting for locator("#price")`, seçiciye uyan bir öğe bulunamadığı anlamına gelir. `locator resolved to …` ise öğenin bulunduğunu ama eylemin yapılamadığını söyler.
3. **Neden satırı**, varsa: `intercepts pointer events` (üstünde başka bir öğe var), `element is not visible` (görünmüyor), `element is not enabled` (devre dışı).
4. **Geçen süre.** Tam olarak süre sınırınızda düşen hata gerçek bir beklemedir. Daha erken gelen `net::ERR_PROXY_CONNECTION_FAILED` gibi bir hata ise başka bir sorundur; bu proxy hatalarını [Playwright Nedir ve Proxy ile Nasıl Kullanılır?](/tr/blog/playwright-proxy) yazısında ele aldık.

## Navigasyon zaman aşımları: page.goto ve waitUntil

`page.goto()` bir yükleme olayını bekler; hangisi olacağını `waitUntil` (Python'da `wait_until`) seçeneği belirler:

- **`commit`**: yanıt geldi ve belge yüklenmeye başladı.
- **`domcontentloaded`**: HTML ayrıştırıldı; görseller, fontlar ve iframe'ler hâlâ yükleniyor olabilir.
- **`load`** (varsayılan): sayfa ve çektiği kaynaklar, görseller ve stil dosyaları dahil, yüklenmeyi bitirdi.
- **`networkidle`**: en az 500 ms boyunca hiçbir ağ bağlantısı yok. [page.goto başvurusu](https://playwright.dev/docs/api/class-page#page-goto) bu seçeneği önerilmez (discouraged) olarak işaretler; sayfanın hazır olup olmadığını doğrulamalarla (assertion) anlamanızı söyler.

Pek çok navigasyon zaman aşımının kaynağı varsayılan `load` seçeneğidir: aradığınız metin çoktan sayfadayken yavaş bir görsel, cevap vermeyen bir izleme pikseli ya da üçüncü taraf bir bileşen bu olayın tetiklenmesini engeller. Test sayfamızda fiyat HTML'in içindeydi ve bir görsel hiç yüklenmedi. `load` ile `goto` 10 saniye sonra zaman aşımına uğradı; `domcontentloaded` ile 0,1 saniyede döndü ve fiyat okunabildi. `networkidle` ise her 300 ms'de bir uç noktaya istek atan bir sayfada başarısız oldu; canlı destek bileşenleri ve anlık fiyatlar da böyle çalışır.

İşe yarayan kalıp şudur: sayfayı `domcontentloaded` ile açın, sonra ihtiyacınız olan tek öğeyi bekleyin.

```python
response = page.goto(url, wait_until="domcontentloaded")
price = page.locator("#price").inner_text()  # öğeyi bekler, en fazla eylem süre sınırı kadar
```

```js
const response = await page.goto(url, { waitUntil: "domcontentloaded" });
const price = await page.locator("#price").innerText();
```

`goto`, `domcontentloaded` ile de zaman aşımına uğruyorsa HTML'in kendisi geç gelmiştir; bu bir ağ sorunudur (aşağıdaki proxy bölümüne bakın). Veri HTML'in içinde ya da bir JSON uç noktasında duruyorsa tarayıcıya hiç gerek olmayabilir; nasıl anlaşılacağını [Statik ve Dinamik Sayfalar](/tr/blog/static-vs-dynamic-pages) yazısında anlattık.

## Locator ve eylem zaman aşımları: otomatik bekleme ve onu durduranlar

Playwright bir tıklamadan önce öğenin görünür, sabit (yani hareket etmeyen) ve etkin olduğunu, tıklamayı o noktada gerçekten kendisinin aldığını kontrol eder; süre dolana kadar bu kontrolleri tekrarlar. Locator zaman aşımlarının nedenleri kısa bir listeye sığar:

- **Seçiciye uyan öğe yok.** Bir yazım hatası, her derlemede değişen bir sınıf adı ya da dile göre farklılaşan bir metin. Kalıcı öznitelikler (`id`, `data-*`) ya da `get_by_role()` daha uzun ömürlüdür.
- **Öğe çok geç geliyor.** Sayfa yüklendikten 12 saniye sonra ekrana gelen bir fiyat, 10 saniyelik süre sınırına her seferinde takılır.
- **Üstünü bir şey kapatıyor.** Çerez bildirimleri ve açılır pencereler call log'da `intercepts pointer events` satırıyla görünür. Katmanı bir ziyaretçi nasıl kapatıyorsa öyle kapatın. `force=True` kontrolü atlar, ama tıklama bu kez hiçbir kullanıcının tıklayamayacağı bir yere düşer.
- **Öğe bir iframe'in içinde.** `page.locator("#price")` çerçevelerin içine bakmaz. Testimizde zaman aşımına uğradı; `page.frame_locator("iframe").locator("#price")` ise fiyatı hemen döndürdü.
- **Sandığınızdan başka bir sayfadasınız.** Engel sayfasında ya da giriş duvarında `#price` yoktur (aşağıya bakın).

`page.wait_for_selector()` hâlâ çalışır, ama Playwright'ın API başvurusu onu önerilmeyenler arasında gösterir ve locator kullanmanızı ister. Locator öğeyi her denemede yeniden arar, bu yüzden sayfanın yeniden çizilmesinden etkilenmez. Selenium'un açık beklemelerinden (explicit wait) farkını [Playwright ve Selenium Farkı](/tr/blog/playwright-vs-selenium) yazısında anlattık.

## Süre sınırlarını bilerek ayarlamak: çağrı, context ve config

Tek bir çağrıya verilen `timeout` her şeyin önüne geçer. Sayfaya verilen varsayılanlar context'e verilenlerden, navigasyon varsayılanı da genel varsayılandan önce gelir. Python'da varsayılanları context'e verin; böylece içindeki her sayfa bunları devralır:

```python
context = browser.new_context()
context.set_default_navigation_timeout(15_000)  # goto, reload, wait_for_url
context.set_default_timeout(10_000)             # locator'lar, tıklamalar, beklemeler
page = context.new_page()
page.goto(slow_report_url, timeout=45_000)      # yavaş olduğu bilinen tek sayfaya daha fazla süre
```

Playwright Test'te bu sınırlar config dosyasında durur. Aşağıdaki config ile yaptığımız denemede sayfada olmayan bir öğe `locator.click: Timeout 10000ms exceeded.`, hiç cevap vermeyen bir sayfa da `page.goto: Timeout 15000ms exceeded.` hatasıyla düştü:

```js
import { defineConfig } from "@playwright/test";

export default defineConfig({
  timeout: 60_000,              // testin tamamı, hook'lar ve fixture'lar dahil
  expect: { timeout: 10_000 },  // her expect(...) doğrulaması
  use: {
    actionTimeout: 10_000,      // click, fill, textContent ...
    navigationTimeout: 15_000,  // goto, reload, waitForURL ...
  },
});
```

`test.slow()` tek bir yavaş testin süresini üç katına çıkarır. Canlı ortamda `timeout=0` kullanmayın: hiç cevap vermeyen bir sayfa context'i sonsuza kadar meşgul eder. Her yere iki dakikalık sınır koymak da pek daha iyi değildir: içinde cevap vermeyen yüz URL bulunan bir kuyruk bu durumda üç saatten uzun sürer.

## Yavaş proxy'ler: önce ölçün, sonra süreyi belirleyin

Proxy her isteğe bir ara durak ekler ve tarayıcı tek bir sayfa için çok sayıda istek yapar. Residential çıkışlar ev bağlantıları üzerinden çalışır ve datacenter çıkışlara göre genellikle daha fazla gecikme ekler; ofis hattınızda hiç dolmayan bir süre sınırı uzak bir çıkışta dolabilir. Bu yüzden sayıyı seçmeden önce ölçün. Aşağıdaki betik aynı sayfayı temiz context'lerde beş kez açar; süre sınırı yalnız ölçüm için kapalıdır:

```python
import statistics
import time

from playwright.sync_api import sync_playwright

PROXY = {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"}
URL = "https://shop.example.com/product/42"

with sync_playwright() as p:
    browser = p.chromium.launch(proxy=PROXY)
    times = []
    for _ in range(5):
        context = browser.new_context()  # temiz oturum, denemeler arasında önbellek yok
        page = context.new_page()
        start = time.monotonic()
        page.goto(URL, wait_until="domcontentloaded", timeout=0)  # ölçüm sırasında süre sınırı yok
        page.locator("#price").wait_for(timeout=0)
        times.append(time.monotonic() - start)
        context.close()
    browser.close()

print("runs:", " ".join(f"{t:.2f}s" for t in times))
print(f"median {statistics.median(times):.2f}s, slowest {max(times):.2f}s")
```

Betik, her isteğe 2 saniye ekleyen yerel test proxy'miz üzerinden şu çıktıyı verdi:

```text
runs: 3.42s 3.38s 3.37s 3.38s 3.38s
median 3.38s, slowest 3.42s
```

Süre sınırını ortanca değere (median) değil en yavaş ölçüme göre, üstünde pay bırakarak belirleyin; biz 15 saniye seçtik. Gerçek bir hedefte daha çok örnek alın ve ülke, proxy türü ya da site değiştiğinde yeniden ölçün. Üç nokta daha:

- **Daha az yükleyin.** Görsel, medya ve font isteklerini `page.route()` ile engellemek sayfa başına istek sayısını düşürür; kodu Playwright proxy yazımızda bulabilirsiniz.
- **İşe uygun çıkışı seçin.** Hedef datacenter IP'lerini kabul ediyorsa [Datacenter Proxy](https://proxynet.io/tr/datacenter-proxy) çıkışları daha hızlıdır. Site ev IP'si ya da belirli bir şehir istiyorsa [Residential Proxy](https://proxynet.io/tr/residential-proxy) çıkışlarını kullanın ve onlar için ayrıca ölçtüğünüz bir süre sınırı belirleyin.
- **Kimlik bilgilerini kontrol edin.** HTTPS bir sitede proxy parolası yanlış olduğunda `requestfailed` dinleyicimiz `net::ERR_TUNNEL_CONNECTION_FAILED` hatasını hemen yazdı, ama `page.goto` ancak 10 saniyelik süresi dolunca düştü. Kimlik doğrulama sorunu yavaş bir proxy gibi görünebilir; hata ayıklarken bu dinleyiciyi ekleyin:

```python
page.on("requestfailed", lambda r: print("FAILED:", r.url, r.failure))
```

Tarayıcı dışında, Python'ın Requests kütüphanesi proxy hatalarını "Max retries exceeded" diye bildirir; nasıl okunacağını [Max Retries Exceeded With URL Hatası Nedir, Nasıl Çözülür?](/tr/blog/max-retries-exceeded-with-url) yazısında anlattık.

## Engel sayfası "öğe bulunamadı"ya dönüşünce

En çok zaman kaybettiren durum budur. Site isteği reddeder ve `403` ya da `429` durum koduyla bir engel sayfası döndürür. `page.goto()`, 4xx ve 5xx durum kodlarında hata fırlatmaz; bizim `goto` çağrımız da `403` ile normal biçimde döndü. Betik ardından, engel sayfasında hiçbir zaman olmayacak bir öğe için süre sınırının sonuna kadar bekler. Günlükte zaman aşımı yazar; asıl cevap ise bir rettir.

Test engel sayfamızın başlığı "Access denied" idi; Python'daki `expect()` hatası sayfanın erişilebilirlik özetini bile yazdırdı ve içinde `heading "Access denied"` satırı vardı. Öğeyi beklemeden önce şunlara bakın:

1. `goto`'nun döndürdüğü yanıtı saklayın ve durum kodunu okuyun.
2. `page.title()` değerini okuyun; engel ve doğrulama sayfalarının kendi başlıkları vardır.
3. İkisinden biri engel diyorsa durun: yeniden deneme yok, öğe beklemek yok.
4. Nedenini bulun: istek hızınıza, sitenin `robots.txt` dosyasına ve kullanım şartlarına, sitenin bir API sunup sunmadığına bakın.

Engel sayfasını yeniden denemek durumu kötüleştirir, reddi aşmak için IP değiştirmek de çözüm değildir: site hayır demiştir. `429`, çok fazla istek gönderdiğiniz anlamına gelir; hızınızı düşürün ve `Retry-After` başlığına uyun ([429 Too Many Requests ve Rate Limit Hatası Nedir?](/tr/blog/http-429-too-many-requests)). Sitelerin bir ziyaretçiyi neden bot olarak işaretlediğini [Bot Tespiti Nasıl Yapılır?](/tr/blog/how-bot-detection-works) yazısında anlattık. Bu sayfaları aşmanın yollarını anlatmıyoruz; kalıcı olan daha yavaş bir tarama, siteden izin ya da resmî API'dir ([Web Scraping ve API Farkı](/tr/blog/web-scraping-vs-api)).

## Tam örnek: ölçülmüş süreler, engel kontrolü ve yeniden deneme

Aşağıdaki betik ürün sayfalarını proxy üzerinden açar. Her deneme, bilerek seçilmiş süre sınırlarıyla temiz bir context'te yapılır. Betik içeriği beklemeden önce durum koduna ve başlığa bakar, engel sayfasında durur ve yalnız zaman aşımlarını yeniden dener. Denemeler arasındaki bekleme üstel olarak artar (exponential backoff) ve rastgele bir pay (jitter) içerir, böylece paralel çalışan worker'lar aynı anda yeniden denemez.

```python
"""Ürün sayfalarını proxy üzerinden ölçülmüş süre sınırları, engel kontrolü ve yeniden denemeyle açar."""
import random
import time

from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
from playwright.sync_api import sync_playwright

PROXY = {"server": "http://pr.proxynet.io:8000", "username": "user", "password": "pass"}
URLS = [f"https://shop.example.com/product/{n}" for n in (42, 43, 44)]

NAV_TIMEOUT = 15_000     # ms: proxy üzerinden ölçtüğümüz en yavaş sayfanın yaklaşık 4 katı
ACTION_TIMEOUT = 10_000  # ms: locator'lar, tıklamalar ve beklemeler
ATTEMPTS = 3
STOP_STATUS = {403, 429}  # ret ya da hız sınırı: yeniden denemek durumu kötüleştirir
STOP_WORDS = ("access denied", "blocked", "captcha", "verify you are human")  # siteye göre uyarlayın

class Blocked(Exception):
    """Site engel ya da hız sınırı sayfası döndürdü: durun ve nedenini bulun."""

def fetch_price(browser, url):
    for attempt in range(1, ATTEMPTS + 1):
        context = browser.new_context()  # her denemede temiz çerezler ve önbellek
        context.set_default_navigation_timeout(NAV_TIMEOUT)
        context.set_default_timeout(ACTION_TIMEOUT)
        page = context.new_page()
        start = time.monotonic()
        try:
            response = page.goto(url, wait_until="domcontentloaded")
            status = response.status if response else None
            title = page.title()
            if status in STOP_STATUS or any(word in title.lower() for word in STOP_WORDS):
                raise Blocked(f"HTTP {status}, title {title!r}")
            return page.locator("#price").inner_text()  # ACTION_TIMEOUT'a kadar kendiliğinden bekler
        except PlaywrightTimeoutError as exc:
            print(f"  attempt {attempt}: {str(exc).splitlines()[0]} ({time.monotonic() - start:.1f}s)")
            if attempt == ATTEMPTS:
                raise
            time.sleep(2**attempt + random.random())  # 2-3 sn, sonra 4-5 sn
        finally:
            context.close()

with sync_playwright() as p:
    browser = p.chromium.launch(proxy=PROXY)
    for url in URLS:
        print(url)
        try:
            print("  price:", fetch_price(browser, url))
        except Blocked as exc:
            print("  stopped, not retrying:", exc)
        except PlaywrightTimeoutError:
            print(f"  gave up after {ATTEMPTS} attempts")
    browser.close()
```

Betiği, alan adını yerel test sitemizle (`shop.test`) değiştirip her isteğe 2 saniye ekleyen proxy üzerinden çalıştırdık. Üçüncü sayfa ilk iki isteğinde takılacak şekilde ayarlıydı:

```text
http://shop.test/product/42
  price: $19.90
http://shop.test/product/43
  stopped, not retrying: HTTP 403, title 'Access denied'
http://shop.test/product/44
  attempt 1: Page.goto: Timeout 15000ms exceeded. (15.0s)
  attempt 2: Page.goto: Timeout 15000ms exceeded. (15.0s)
  price: $19.90
```

Engel sayfası yalnızca bir isteğe mal oldu ve hiç bekletmedi; takılan sayfa ise iki zaman aşımından sonra açıldı. `Retry-After` başlığıyla gelen `503` gibi durum koduna bağlı yeniden denemeler ayrı bir katmanda ele alınır; o katmanın kodunu [Scraping'de HTTP Hata Kodları: 403, 407, 429 ve 503](/tr/blog/http-status-codes-web-scraping) yazısında bulabilirsiniz. Aynı mantığın Node.js karşılığı şöyle:

```js
import { chromium, errors } from "playwright";

const PROXY = { server: "http://pr.proxynet.io:8000", username: "user", password: "pass" };
const URLS = ["https://shop.example.com/product/42", "https://shop.example.com/product/45"];

const browser = await chromium.launch({ proxy: PROXY });
for (const url of URLS) {
  const context = await browser.newContext();
  context.setDefaultNavigationTimeout(15_000); // goto, reload, waitForURL
  context.setDefaultTimeout(10_000);           // locator'lar, tıklamalar, beklemeler
  const page = await context.newPage();
  try {
    const response = await page.goto(url, { waitUntil: "domcontentloaded" });
    console.log(url, "status", response?.status(), "title", await page.title());
    console.log("  price:", await page.locator("#price").innerText());
  } catch (err) {
    if (!(err instanceof errors.TimeoutError)) throw err;
    console.log("  timeout:", err.message.split("\n")[0]);
  } finally {
    await context.close();
  }
}
await browser.close();
```

Test sitemizde ikinci sayfa fiyatı 12 saniye sonra gösteriyor:

```text
http://shop.test/product/42 status 200 title Product
  price: $19.90
http://shop.test/product/45 status 200 title Product
  timeout: locator.innerText: Timeout 10000ms exceeded.
```

## Puppeteer: "Navigation timeout of 30000 ms exceeded"

Puppeteer aynı modeli başka adlarla kullanır. Varsayılan süre burada da 30 saniyedir; `page.setDefaultNavigationTimeout()` ve `page.setDefaultTimeout()` bunu değiştirir, `waitUntil` ise `load`, `domcontentloaded`, `networkidle0` ve `networkidle2` değerlerini alır. [Puppeteer'ın yükleme olayları başvurusu](https://pptr.dev/api/puppeteer.puppeteerlifecycleevent) son ikisini 500 ms boyunca en fazla 0 ya da 2 açık bağlantı diye tanımlar; yani yoğun sayfalarda `networkidle` gibi takılırlar.

```js
import puppeteer, { TimeoutError } from "puppeteer";

const browser = await puppeteer.launch({ args: ["--proxy-server=http://pr.proxynet.io:8000"] });
const page = await browser.newPage();
await page.authenticate({ username: "user", password: "pass" });
page.setDefaultNavigationTimeout(15_000); // goto, reload, waitForNavigation
page.setDefaultTimeout(10_000);           // waitForSelector ve diğer beklemeler

try {
  const response = await page.goto("https://shop.example.com/product/45", { waitUntil: "domcontentloaded" });
  console.log("status", response?.status(), "title", await page.title());
  await page.waitForSelector("#price");
} catch (err) {
  if (!(err instanceof TimeoutError)) throw err;
  console.log(`${err.name}: ${err.message} (${err.cause?.message})`);
} finally {
  await browser.close();
}
```

Puppeteer 25.12 denemelerimiz şu mesajları verdi; ilki, varsayılan süre sınırıyla hiç cevap vermeyen bir sayfadan geldi:

```text
TimeoutError: Navigation timeout of 30000 ms exceeded
TimeoutError: Waiting for selector `#price` failed (Waiting failed: 10000ms exceeded)
```

Seçici mesajı süre sınırını yazmaz; o bilgi `err.cause` içindedir. Proxy Chromium'a bir başlatma parametresiyle, kimlik bilgileri de `page.authenticate()` ile verilir; bu metot arka planda istek yakalamayı (request interception) açar. Yukarıdaki nedenler ve çözümler aynen geçerlidir.

## Bu hatayla nerelerde karşılaşırsınız?

- **JavaScript ile oluşturulan mağaza sayfalarından veri toplarken:** fiyat HTML'den sonra yüklenir, bu yüzden ağı değil öğeyi bekleyin ([veri kazıma](/tr/data-scraping)).
- **Uzun bir sayfa kuyruğunu tararken:** takılan bir sayfa bütün çalıştırmaya değil, tek bir zaman aşımına mal olmalı ([web crawler](/tr/web-crawler)).
- **Kendi uygulamanızı başka ülkelerden test ederken:** her çıkışın gecikmesi farklıdır; süre sınırını ülkeye göre belirleyin ([uygulama testi](/tr/app-testing)).
- **Tarayıcıyı yöneten yapay zekâ ajanlarında:** `goto` çağıran bir ajan da aynı sınırlara takılır ([Playwright MCP](/tr/blog/playwright-mcp)).
- **Zamanlanmış taramalarda:** hız ve süre ayarlarından önce sitenin tarama kurallarını okuyun ([robots.txt Dosyası Nedir, Nasıl Okunur?](/tr/blog/robots-txt)).

## Sık yapılan hatalar

- **Varsayılanı 60 ya da 120 saniyeye çıkarmak.** Başarılı olamayacak bir bekleme yalnızca daha geç düşer.
- **`networkidle` olayını "sayfa hazır" diye yorumlamak.** Yoğun sayfalar hiçbir zaman sessizleşmez.
- **Her adımdan önce sabit bekleme koymak.** `time.sleep()` ve `waitForTimeout()` hızlı sayfada fazla uzun, yavaş sayfada fazla kısadır.
- **Python'da `expect()` çevresinde yalnız `TimeoutError` yakalamak.** Başarısız bir `expect()` ise `AssertionError` fırlatır.
- **Durum koduna ve başlığa bakmamak.** Engel sayfası bu durumda 30 saniyelik bir "öğe bulunamadı" hatasına dönüşür.
- **Engellenen istekleri yeniden denemek.** Yeniden deneme zaman aşımları ve kısa ağ kopmaları içindir, `403` ve `429` için değil.
- **Üstteki katmanı `force=True` ile görmezden gelmek.** Tıklama, bir kullanıcının tıklayamayacağı yere düşer.

## Karar rehberi

| Gördüğünüz | Yapılacak |
|---|---|
| `page.goto: Timeout`, waiting until "load" | `domcontentloaded`, ardından öğeyi bekleyin |
| `page.goto: Timeout`, waiting until "networkidle" | `networkidle`'ı bırakın, tek bir öğeyi bekleyin |
| `domcontentloaded` ile `page.goto: Timeout` | Proxy üzerinden yükleme süresini ölçün, sınırı ona göre koyun |
| `waiting for locator(...)` ve altında hiçbir şey | Seçiciyi, çerçeveleri ve hangi sayfada olduğunuzu kontrol edin |
| `intercepts pointer events` | Katmanı bir kullanıcının kapatacağı gibi kapatın |
| `403` ya da `429` durum kodu, ya da engel başlığı | Durun; yavaşlayın, `robots.txt`'ye bakın, izin isteyin ya da API kullanın |
| `Test timeout of 30000ms exceeded.` | Takılan adımı bulun; sınırı yalnız yavaş testler için artırın |
| `requestfailed` içinde `ERR_TUNNEL_CONNECTION_FAILED` | Zaman aşımlarına dokunmadan önce proxy kimlik bilgilerini düzeltin |

## Sıkça sorulan sorular

### Playwright'ta varsayılan timeout nedir?

Kütüphanede navigasyon ve eylemler için 30 saniyedir. Playwright Test'te testin tamamına 30 saniye, her `expect()` doğrulamasına 5 saniye verilir; eylemlerin ve navigasyonun kendine ait bir sınırı yoktur.

### page.goto için timeout nasıl artırılır?

Süreyi çağrıya verin (Python'da `page.goto(url, timeout=60_000)`, Node.js'te `{ timeout: 60_000 }`), context'te `set_default_navigation_timeout()` kullanın ya da Playwright Test config'inde `navigationTimeout` ayarlayın. Süreyi ancak ölçtükten sonra artırın.

### Sayfa ekranda olduğu hâlde page.goto neden zaman aşımına uğruyor?

`goto` varsayılan olarak `load` olayını bekler ve hiç bitmeyen tek bir görsel ya da bileşen bu olayı geciktirir. `domcontentloaded` kullanın ve ihtiyacınız olan öğeyi bekleyin.

### networkidle kullanmalı mıyım?

Hayır. Playwright'ın kendi başvurusu bu seçeneği önerilmez (discouraged) olarak işaretler; sürekli istek atan ya da canlı destek bileşeni olan sayfalar bu duruma hiç ulaşmayabilir. Bunun yerine belirli bir öğeyi bekleyin.

### Python'da Playwright TimeoutError nasıl yakalanır?

Sınıfı `from playwright.sync_api import TimeoutError as PlaywrightTimeoutError` diye içe aktarıp bu adla yakalayın. Başarısız bir `expect()` ise `AssertionError` fırlatır.

### Proxy, Playwright'ta zaman aşımına yol açar mı?

Açabilir. Yavaş bir çıkış sayfaları süre sınırının ötesine taşıyabilir, HTTPS sitelerde yanlış kimlik bilgileri de açık bir hata yerine zaman aşımı olarak görünebilir. Proxy üzerinden ölçün, süre sınırlarını sonuca göre belirleyin ve `requestfailed` olayını dinleyin. Engel sayfası ise başka bir proxy ile çözülmez.

## Özet

"Timeout 30000ms exceeded" nedeni değil, dolan beklemeyi söyler. Metodu ve call log'un son satırlarını okuyun, sonra gösterdiği şeyi düzeltin: `load` ya da `networkidle` beklemesi, seçici, üstteki katman, çerçeve, engel sayfası ya da yavaş bir çıkış. Süre sınırlarını ölçülmüş yükleme sürelerine göre context düzeyinde belirleyin, ara sıra yavaş açılan sayfaya kendi süresini verin, yalnızca zaman aşımlarını artan beklemeyle yeniden deneyin ve engel sayfasında durun. Hedeflerinize uygun çıkışları seçmek için [proxy hizmetlerimizi](/tr/proxy) karşılaştırın.
