---
title: "PHP Simple HTML DOM Parser Kullanımı ve DOMDocument"
url: "https://cilginyazilim.com/blog/php-simple-html-dom-parser-kullanimi"
description: "PHP Simple HTML DOM Parser kurulumu ve kullanımı, PHP 8'deki uyarısı, 2,5 MB sınırı ve ek paket gerektirmeyen DOMDocument ile Dom\\HTMLDocument alternatifleri."
published: "2026-09-29T16:43:50+03:00"
modified: "2026-09-29T16:43:50+03:00"
author: "Çılgın Yazılım"
category: "Web Geliştirme ve Frameworkler"
tags: ["php", "api", "composer", "karakter kodlama", "web kazıma"]
site: "CılgınYazılım"
language: "tr"
---

# PHP Simple HTML DOM Parser Kullanımı ve DOMDocument

Simple HTML DOM hâlâ çalışıyor ama 2019'dan beri yeni sürümü yok. PHP'nin kendi DOM araçları aynı işi ek paket olmadan yapıyor.

PHP Simple HTML DOM Parser, bir HTML belgesini yükleyip içindeki öğeleri jQuery'ye benzeyen CSS seçicileriyle bulmanızı sağlayan açık kaynak bir kütüphanedir. Composer paketinin son sürümü 9 Kasım 2019 tarihli 2.0-RC2; PHP 8.2'de çalışıyor, boş kurucuyla kullanıldığında deprecation uyarısı veriyor. Yeni bir projede aynı işi **ek paket kurmadan** PHP'nin DOMDocument ve DOMXPath sınıfları, PHP 8.4'ten itibaren de `Dom\HTMLDocument` yapıyor.

Örnekler PHP 8.2.12'de çalıştırıldı; PHP 8.4 örneği php.net'in sürüm notundaki örnekten uyarlandı, yerelde 8.4 olmadığı için çalıştırılmadı.

## Kurulum: Composer ya da klasörü kopyalamak

Paket Packagist'te `simplehtmldom/simplehtmldom` adıyla duruyor ve PHP 5.6 ve üstünü istiyor. İlk tuzak kurulumda: paketin kararlı sürümü yok, yalnız bir sürüm adayı (RC) var. Bu yüzden sürüm yazmadan verilen komut durur:

```bash
composer require simplehtmldom/simplehtmldom
# Could not find a version of package simplehtmldom/simplehtmldom matching
# your minimum-stability (stable).

composer require simplehtmldom/simplehtmldom:2.0-RC2
```

Sürümü komutta açıkça yazmak, projenin `minimum-stability` ayarını düşürmekten daha güvenlidir; o ayar yalnız bu paketi değil, bütün bağımlılıkları kararsız sürümlere açar.

`str_get_html()` ve `file_get_html()` fonksiyonları `simple_html_dom.php` dosyasından gelir. 2.0-RC2'de bu dosya tek başına yetmez; `HtmlDocument.php`, `HtmlNode.php`, `constants.php` ve `Debug.php` dosyalarını aynı klasörden çağırır, yalnız onu kopyalarsanız "include_once(HtmlDocument.php): Failed to open stream" alırsınız. Composer da bu dosyayı otomatik yüklemez: Composer kurulumunda `file_get_html()` tanımsızdır. Sınıf adıyla çalışın ya da dosyayı elle `require` edin.

## Seçiciyle veri çekmek

Aşağıdaki örnek, bir ürün listesinden ad, bağlantı ve fiyatı alır. `find()` seçiciye uyan öğeleri döndürür; ikinci parametre verilirse o sıradaki tek öğeyi verir:

```php
require 'vendor/autoload.php';
use simplehtmldom\HtmlDocument;

$html = '<ul><li class="urun"><a href="/p/1">Çağrı Şişesi</a><span class="fiyat">149,90 ₺</span></li></ul>';

// HTML kurucuya verilir: boş kurucu PHP 8.1+'da trim(null) uyarısı üretir
$belge = new HtmlDocument($html);

foreach ($belge->find('li.urun') as $li) {
    $baglanti = $li->find('a', 0);
    $fiyat    = $li->find('span.fiyat', 0);
    if ($baglanti === null || $fiyat === null) {
        continue; // sitenin HTML'i değişti: sessizce geçme, günlüğe yaz
    }
    echo trim($baglanti->plaintext), ' | ', $baglanti->href, ' | ', trim($fiyat->plaintext), "\n";
}
// Çağrı Şişesi | /p/1 | 149,90 ₺

unset($belge); // 2.0-RC2'de clear() boş bir çağrıdır; belleği unset bırakır
```

Dikkat: aranan öğe yoksa `find('…', 0)` `null` döndürür ve zincirdeki bir sonraki `->plaintext` hataya dönüşür. Başka bir sitenin HTML'i değiştiğinde ilk kırılan yer burasıdır; örnekteki gibi her tekil `find()` sonucunu kullanmadan önce kontrol edin.

## PHP 8'de görülen uyarı ve boyut sınırı

Nesne boş kurulup HTML sonradan `load()` ile verildiğinde, `error_reporting(E_ALL)` altında şu satır çıkıyor:

```text
Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated
in …/simplehtmldom/HtmlDocument.php on line 269
```

Uyarının kaynağı yükleme değil, boş kurucudur: `new HtmlDocument()` içeride `trim(null)` çağırır. `str_get_html()` ve `file_get_html()` de nesneyi böyle kurduğu için her çağrıda uyarı verir. HTML'i doğrudan kurucuya verdiğimizde (`new HtmlDocument($html)`) uyarı hiç çıkmadı. PHP 8.1'den beri dahili fonksiyonlara null geçmek deprecation uyarısı verir; düzeltme ana dalda Nisan 2022'den beri duruyor ama hiçbir sürüme girmedi.

İkinci ayrıntı kaynak kodda: `file_get_html()` ve `str_get_html()`, içerik boşsa ya da `MAX_FILE_SIZE` sınırını (2.0-RC2'de 2.621.440 bayt) aşıyorsa hata vermeden `false` döndürür. Sonraki `->find()` satırı bu yüzden "Call to a member function find() on bool" hatasıyla durur; bu hatayı görüyorsanız önce bu sınıra bakın. Sınır yalnız bu iki fonksiyonda var: `new HtmlDocument($html)` 2,7 MB'lık bir belgeyi de yükledi. Fonksiyonda kalmanız gerekiyorsa `file_get_html()`'in beşinci parametresi (`$maxLen`) sınırı yükseltir.

## Ek paket olmadan: DOMDocument ve DOMXPath

PHP'nin yerleşik DOM eklentisi aynı işi CSS yerine XPath sorgusuyla yapar. Tek bir tuzağı var: `loadHTML()` kodlama bilgisi olmayan bir parçayı UTF-8 değil ISO-8859-1 sayar. Aynı ürün listesini kodlama belirtmeden yüklediğimizde "Çağrı Şişesi" metni "ÃaÄrÄ± ÅiÅesi" olarak çıktı. Başa kodlama bildirimi eklemek bunu düzeltir:

```php
libxml_use_internal_errors(true);   // HTML5 etiketlerindeki uyarıları topla
$dom = new DOMDocument();
$dom->loadHTML('<?xml encoding="UTF-8">' . $html);
libxml_clear_errors();              // biriken uyarı listesini boşalt
$xp = new DOMXPath($dom);

foreach ($xp->query('//li[contains(concat(" ", normalize-space(@class), " "), " urun ")]') as $li) {
    $a = $xp->query('.//a', $li)->item(0);
    echo trim($a->textContent), ' | ', $a->getAttribute('href'), "\n";
}
// Çağrı Şişesi | /p/1
```

XPath'te sınıf eşleştirme uzun görünür, çünkü `class` niteliği birden çok sınıf taşıyabilir; `contains(concat(…))` kalıbı "urun" sınıfını "urunler" gibi benzer adlardan ayırır.

## PHP 8.4 ve sonrası: Dom\HTMLDocument ile querySelector

PHP 8.4, HTML5 kurallarına uyan yeni bir DOM API'si getirdi. Belge `Dom\HTMLDocument::createFromString()` ile oluşturulur ve CSS seçicisi doğrudan kullanılır:

```php
$dom = Dom\HTMLDocument::createFromString($html, LIBXML_NOERROR);
$fiyat = $dom->querySelector('li.urun span.fiyat');
echo $fiyat?->textContent;
```

Canlı sunucunuz 8.4 ya da üstündeyse yeni kod için ne Simple HTML DOM'a ne de XPath'e gerek kalır.

## Hangisini seçmeli?

Üç seçeneği aynı ölçütlerle karşılaştırınca karar PHP sürümüne bağlanıyor:

|  | Simple HTML DOM | DOMDocument + DOMXPath | Dom\HTMLDocument |
| --- | --- | --- | --- |
| Kurulum | Composer ya da klasörü kopyalamak | PHP ile gelir | PHP 8.4 ile gelir |
| Seçici | CSS | XPath | CSS (querySelector) |
| Türkçe karakter | Denemede sorunsuz | Kodlama bildirilmeli | Kodlama parametreyle de verilebilir |
| Bakım | Son sürüm 2019 | PHP ile güncellenir | PHP ile güncellenir |

Eski bir projede Simple HTML DOM çalışıyorsa acele taşımaya gerek yok; yeni kodu DOMDocument ya da 8.4'te Dom\HTMLDocument ile yazın.

## CodeIgniter 4'te sayfayı indirip ayrıştırmak

Ayrıştırıcı sayfayı indirmez, yalnız okur. `file_get_html($url)` indirmeyi de üstlenir; ama üçüncü parametreye stream context verilmezse php.ini'deki `default_socket_timeout` (varsayılan 60 saniye) geçerlidir, 404'te de yalnız `false` döner. CI4'ün istemcisi de kendiliğinden korumaz: 4.6.3'te `timeout` varsayılanı 0 (sınırsız), `connect_timeout` ise 150 saniyedir. Uzak sayfayı zaman aşımı tanımlı bir HTTP istemcisiyle alıp ayrıştırıcıya metin olarak verin. Aşağıdaki kodu bu blogun liste sayfasının yerel kopyasına karşı çalıştırdık: durum 200 döndü ve ilk üç yazı başlığı okundu; olmayan bir adres 404 verdi.

```php
use CodeIgniter\HTTP\Exceptions\HTTPException;

function basliklariOku(string $adres): array
{
    $istemci = single_service('curlrequest', ['timeout' => 5, 'connect_timeout' => 3, 'http_errors' => false]);
    try {
        $yanit = $istemci->get($adres, ['headers' => ['User-Agent' => 'OrnekOkuyucu/1.0']]);
    } catch (HTTPException $e) {
        log_message('warning', 'İndirilemedi: {adres}', ['adres' => $adres]);
        return []; // zaman aşımı ya da bağlantı hatası
    }
    if ($yanit->getStatusCode() !== 200) {
        return []; // 404, 500: ayrıştırmaya geçme
    }

    libxml_use_internal_errors(true);
    $dom = new DOMDocument();
    $dom->loadHTML('<?xml encoding="UTF-8">' . $yanit->getBody());
    libxml_clear_errors();
    $xp = new DOMXPath($dom);
    $basliklar = [];
    foreach ($xp->query('//h2[contains(concat(" ", normalize-space(@class), " "), " cy-yazi-satir__baslik ")]/a') as $a) {
        $basliklar[] = trim($a->textContent);
    }

    return $basliklar;
}
```

Dikkat: `service()` paylaşılan örneği döndürür; aynı istekte istemci daha önce kurulduysa verdiğiniz timeout sessizce yok sayılır, `single_service()` bu yüzden. `http_errors` kapalıyken 404 ve 500 istisna fırlatmaz, ama zaman aşımı yine `HTTPException` fırlatır; çağrı bu yüzden `try/catch` içinde.

## Başka sitelerden veri çekerken

`basliklariOku()` fonksiyonunu her sayfa isteğinde çağırmayın: sonuç boş değilse `cache()->save('blog_basliklari', $basliklar, 3600)` ile bir saat saklayın (süreyi seçmek için [önbellek stratejileri](https://cilginyazilim.com/blog/onbellek-stratejileri-ne-zaman-nerede-ne-kadar)). 200 yanıtla gelen boş dizi, seçicinin artık eşleşmediği anlamına gelir; `log_message('warning', 'Seçici eşleşmedi: {adres}', ['adres' => $adres])` satırı kırılmayı ilk gün gösterir. robots.txt'nin yasakladığı yolları okumayın. Dış kaynağa bağımlı her işte zaman aşımı ve yeniden deneme kuralları için [üçüncü parti API entegrasyonunda dayanıklılık](https://cilginyazilim.com/blog/ucuncu-parti-api-entegrasyonunda-dayaniklilik) yazısına bakabilirsiniz.

Simple HTML DOM'u bugün kırılgan yapan seçicileri değil, 2019'da dondurulmuş sürümüdür: PHP 8 uyarısının düzeltmesi ana dalda duruyor ama hiçbir sürüme girmedi. Eski projede kalıyorsa nesneyi `new HtmlDocument($html)` ile kurun, `clear()` yerine `unset()` kullanın, her tekil `find()` sonucunu null'a karşı kontrol edin ve `str_get_html()` false döndürürse önce 2.621.440 baytlık sınıra bakın. Yeni kodu PHP 8.3 ve öncesinde kodlama bildirimli DOMDocument ile, 8.4 ve sonrasında Dom\HTMLDocument ile yazın; sayfayı her durumda zaman aşımı tanımlı bir istemciyle indirin.

Konunun derinlemesine anlatımı için: [php.net — PHP 8.4 sürüm notları](https://www.php.net/releases/8.4/en.php).

## Sıkça Sorulan Sorular

### Simple HTML DOM Parser PHP 8 ile çalışır mı?

Çalışır. 2.0-RC2'yi PHP 8.2.12'de denedik; seçiciler doğru sonuç verdi. Nesne boş kurulduğunda (new HtmlDocument()) ve str_get_html() ile file_get_html() her çağrıldığında "trim(): Passing null" deprecation uyarısı çıkıyor. HTML'i kurucuya verirseniz uyarı hiç çıkmaz.

### file_get_html neden false döndürüyor?

Üç durumda false döner: sayfa indirilemediğinde, boş geldiğinde ya da 2.621.440 baytlık MAX_FILE_SIZE sınırını aştığında. İndirme hatası 404, 403, zaman aşımı ya da kapalı allow_url_fopen olabilir; bu durumda bir de "Failed to open stream" uyarısı düşer. Hangisinin olduğunu false söylemez; sayfayı durum kodunu gösteren bir HTTP istemcisiyle indirin.

### DOMDocument Türkçe karakterleri neden bozuyor?

loadHTML kodlama bilgisi olmayan bir parçayı UTF-8 değil ISO-8859-1 sayar; "Çağrı" metni "ÃaÄrÄ±" gibi görünür. HTML'in başına <?xml encoding="UTF-8"> eklemek ya da belgede meta charset bulunması sorunu çözer.

### DOMDocument loadHTML "Tag … invalid in Entity" uyarısı neden çıkar?

loadHTML'in kullandığı libxml ayrıştırıcısı HTML5 etiketlerini tanımaz; header, section, nav gibi her etiket için bu uyarıyı verir. Ağaç yine kurulur ve sorgular çalışır. Yüklemeden önce libxml_use_internal_errors(true) çağırın, iş bitince libxml_clear_errors() ile biriken listeyi boşaltın.

---

Kaynak: [PHP Simple HTML DOM Parser Kullanımı ve DOMDocument](https://cilginyazilim.com/blog/php-simple-html-dom-parser-kullanimi)
