PHP'de HTML / XML'i nasıl ayrıştırır ve işlersiniz?


Yanıtlar:


1897

Yerel XML Uzantıları

PHP ile birlikte geldikleri için yerel XML uzantılarından birini kullanmayı tercih ederim , genellikle tüm 3. taraf kütüphanelerinden daha hızlıdır ve bana işaretleme üzerinde ihtiyacım olan tüm kontrolü veririm.

DOM

DOM uzantısı, PHP 5 ile DOM API aracılığıyla XML belgelerinde çalışmanıza izin verir. Programların ve komut dosyalarının dinamik olarak erişmesine ve güncellenmesine izin veren platform ve dilden bağımsız bir arayüz olan W3C'nin Belge Nesne Modeli Çekirdek Seviye 3'ün bir uygulamasıdır. belgelerin içeriği, yapısı ve stili.

DOM, gerçek dünya (bozuk) HTML'yi ayrıştırma ve değiştirme yeteneğine sahiptir ve XPath sorguları yapabilir . Libxml tabanlıdır .

DOM ile üretken olmak biraz zaman alır, ancak bu zaman IMO'ya değer. DOM bir dilden bağımsız arayüz olduğundan, birçok dilde uygulamalar bulacaksınız, bu nedenle programlama dilinizi değiştirmeniz gerekirse, o dilin DOM API'sini nasıl kullanacağınızı zaten biliyorsunuzdur.

Temel bir kullanım örneği, bir A öğesinin href özniteliğini yakalamada bulunabilir ve genel kavramsal genel bakış phd'de DOMDocument adresinde bulunabilir.

DOM uzantısını kullanma StackOverflow üzerinde kapsamlı bir şekilde ele alınmıştır , bu nedenle kullanmayı seçerseniz, karşılaştığınız sorunların çoğunun Yığın Taşması arama / tarama yoluyla çözülebileceğinden emin olabilirsiniz.

XMLReader

XMLReader uzantısı bir XML çekme ayrıştırıcısıdır. Okuyucu, belge akışında ilerleyen ve yoldaki her bir düğümde duran bir imleç görevi görür.

DOM gibi XMLReader libxml tabanlıdır. HTML Ayrıştırıcı Modülünün nasıl tetikleneceğinin farkında değilim, bu yüzden kırık HTML'yi ayrıştırmak için XMLReader'ı kullanma şansı, açıkça libxml'in HTML Ayrıştırıcı Modülünü kullanmasını söyleyebileceğiniz DOM kullanmaktan daha az güçlü olabilir.

Php kullanarak h1 etiketlerinden tüm değerleri almak temel bir kullanım örneği bulunabilir

XML Ayrıştırıcı

Bu uzantı, XML ayrıştırıcıları oluşturmanıza ve ardından farklı XML olayları için işleyiciler tanımlamanıza olanak tanır. Her XML ayrıştırıcısının ayarlayabileceğiniz birkaç parametresi de vardır.

XML Ayrıştırıcı kitaplığı da libxml tabanlıdır ve SAX tarzı bir XML push ayrıştırıcı uygular . Bellek yönetimi için DOM veya SimpleXML'den daha iyi bir seçim olabilir, ancak XMLReader tarafından uygulanan çekme ayrıştırıcısından çalışmak daha zor olacaktır.

SimpleXML

SimpleXML uzantısı, XML'i normal özellik seçicileri ve dizi yineleyicileri ile işlenebilen bir nesneye dönüştürmek için çok basit ve kolay kullanılabilir bir araç seti sağlar.

HTML'nin geçerli XHTML olduğunu bildiğinizde SimpleXML bir seçenektir. Bozuk HTML'yi ayrıştırmanız gerekirse, boğulacağı için SimpleXml'i bile düşünmeyin.

Temel bir kullanım örneği bulunabilir xml dosyasının CRUD düğüm ve düğüm değerleri basit bir programı ve orada Manuel PHP ek örnekler çok .


3. Taraf Kütüphaneleri (libxml tabanlı)

Üçüncü taraf bir lib kullanmayı tercih ediyorsanız , dize ayrıştırma yerine aslında DOM / libxml kullanan bir lib kullanmanızı öneririm .

FluentDom - Repo

FluentDOM, PHP'deki DOMDocument için jQuery benzeri bir akıcı XML arayüzü sağlar. Seçiciler XPath veya CSS'de yazılır (CSS'den XPath'e dönüştürücü kullanılarak). Mevcut sürümler DOM uygulama standart arayüzlerini genişletir ve DOM Living Standard'dan özellikler ekler. FluentDOM, JSON, CSV, JsonML, RabbitFish ve diğerleri gibi formatları yükleyebilir. Composer ile kurulabilir.

HtmlPageDom

Wa72 \ HtmlPageDom` O gerektirir kullanarak HTML belgeleri kolay manipülasyon için bir PHP kütüphanesidir Symfony2'nin bileşenlerinden DomCrawler DOM ağacında geçiş için ve HTML belgelerinin DOM ağacını işlemek için yöntemleri ekleyerek genişletir.

phpQuery (yıllardır güncellenmez)

phpQuery, PHP5 ile yazılmış ve ek Komut Satırı Arabirimi (CLI) sağlayan jQuery JavaScript Kütüphanesi tabanlı sunucu tarafı, zincirlenebilir, CSS3 seçici tahrikli Belge Nesne Modeli (DOM) API'sidir.

Ayrıca bakınız: https://github.com/electrolinux/phpquery

Zend_Dom

Zend_Dom, DOM belgeleri ve yapılarıyla çalışmak için araçlar sağlar. Şu anda, hem XPath hem de CSS seçicileri kullanan DOM belgelerini sorgulamak için birleştirilmiş bir arayüz sağlayan Zend_Dom_Query sunuyoruz.

QueryPath

QueryPath, XML ve HTML'yi değiştirmek için kullanılan bir PHP kütüphanesidir. Yalnızca yerel dosyalarla değil, web hizmetleri ve veritabanı kaynaklarıyla da çalışacak şekilde tasarlanmıştır. JQuery arabiriminin çoğunu (CSS stili seçiciler dahil) uygular, ancak sunucu tarafında kullanım için yoğun bir şekilde ayarlanmıştır. Composer ile kurulabilir.

fDOMDocument

fDOMDocument, standart DOM'ları PHP uyarıları veya bildirimleri yerine tüm hata durumlarında istisnalar kullanacak şekilde genişletir. Ayrıca, kolaylık sağlamak ve DOM kullanımını basitleştirmek için çeşitli özel yöntemler ve kısayollar eklerler.

kılıç / xml

saber / xml XMLReader ve XMLWriter sınıflarını saran ve genişleten basit bir "xml nesneye / diziye" eşleme sistemi ve tasarım deseni oluşturmak için bir kütüphanedir. XML yazmak ve okumak tek geçişlidir ve bu nedenle hızlı olabilir ve büyük xml dosyalarında düşük bellek gerektirir.

FluidXML

FluidXML, XML'i kısa ve akıcı bir API ile işlemek için kullanılan bir PHP kütüphanesidir. Eğlenceli ve etkili olması için XPath ve akıcı programlama modelinden yararlanır.


3. Taraf (libxml tabanlı değil)

DOM / libxml üzerine oluşturmanın yararı, yerel bir uzantıya dayandığınız için kutudan iyi performans almanızdır. Ancak, tüm 3. parti kütüphaneleri bu rotadan geçmez. Bunlardan bazıları aşağıda listelenmiştir

PHP Basit HTML DOM Ayrıştırıcı

  • PHP5 + ile yazılmış bir HTML DOM ayrıştırıcısı, HTML'yi çok kolay bir şekilde değiştirmenizi sağlar!
  • PHP 5+ gerektirir.
  • Geçersiz HTML'yi destekler.
  • HTML sayfasındaki etiketleri jQuery gibi seçicilerle bulun.
  • Tek bir satırda HTML'den içerik ayıklayın.

Genellikle bu ayrıştırıcıyı önermiyorum. Kod tabanı korkunç ve ayrıştırıcının kendisi oldukça yavaş ve bellek aç. Tüm jQuery Seçicileri ( alt seçiciler gibi ) mümkün değildir. Libxml tabanlı kütüphanelerden herhangi biri bunu kolayca geçebilir.

PHP Html Ayrıştırıcı

PHPHtmlParser, jQuery gibi herhangi bir css seçiciyi kullanarak etiketleri seçmenizi sağlayan basit, esnek, html ayrıştırıcıdır. Amaç, geçerli olsun ya da olmasın, html'yi hurdaya atmanın hızlı ve kolay bir yolunu gerektiren araçların geliştirilmesinde yardımcı olmaktır! Bu proje orijinal sunra / php-simple-html-dom-parser tarafından destekleniyordu, ancak destek durmuş gibi görünüyor, bu yüzden bu proje daha önceki çalışmasına uyarlamam.

Yine, bu ayrıştırıcı tavsiye etmem. Yüksek CPU kullanımı ile oldukça yavaştır. Ayrıca, oluşturulan DOM nesnelerinin belleğini temizleme işlevi de yoktur. Bu sorunlar özellikle iç içe döngülerle ölçeklendirilir. Belgelerin kendisi yanlış ve yanlış yazılmış, 14 Nis 16'dan bu yana düzeltmelere yanıt yok.

Ganon

  • Evrensel bir belirteç ve HTML / XML / RSS DOM Ayrıştırıcı
    • Elemanları ve niteliklerini manipüle edebilme
    • Geçersiz HTML ve UTF8'i destekler
  • Öğelerde gelişmiş CSS3 benzeri sorgular gerçekleştirebilir (jQuery gibi - ad alanları desteklenir)
  • HTML güzelleştirici (HTML Düzenli gibi)
    • CSS ve Javascript'i küçültün
    • Nitelikleri sıralayın, karakter durumunu değiştirin, girintiyi düzeltin, vb.
  • Genişletilebilir
    • Geçerli karaktere / jetona dayalı geri aramalar kullanarak belgeleri ayrıştırma
    • Kolay geçersiz kılma için daha küçük işlevlerde ayrılmış işlemler
  • Hızlı ve kolay

Hiç kullanmadı. Bunun iyi olup olmadığını söyleyemem.


HTML 5

HTML5'i ayrıştırmak için yukarıdakileri kullanabilirsiniz, ancak HTML5'in izin verdiği biçimlendirme nedeniyle tuhaflıklar olabilir . HTML5 için, özel bir ayrıştırıcı kullanmayı düşünebilirsiniz.

html5lib

Büyük masaüstü web tarayıcılarıyla maksimum uyumluluk için WHATWG HTML5 spesifikasyonunu temel alan bir HTML ayrıştırıcısının Python ve PHP uygulamaları.

HTML5 sonlandırıldığında daha özel ayrıştırıcılar görebiliriz. Ayrıca, W3'ün html 5 ayrıştırma için Nasıl Yapılır başlıklı bir blog yazısı da kontrol edilmeye değer.


Ağ hizmetleri

PHP programlamak istemiyorsanız, Web servislerini de kullanabilirsiniz. Genel olarak, bunlar için çok az fayda buldum, ama bu sadece ben ve kullanım durumlarım.

ScraperWiki .

ScraperWiki'nin harici arayüzü, web'de veya kendi uygulamalarınızda kullanmak istediğiniz formdaki verileri çıkarmanızı sağlar. Ayrıca herhangi bir kazıyıcı durumu hakkında bilgi de çıkarabilirsiniz.


Düzenli ifadeler

Son ve en az tavsiye edilen , HTML'den düzenli ifadelerle veri ayıklayabilirsiniz . Genel olarak HTML'de Normal İfadeler kullanılması önerilmez.

İşaretlemeyi eşleştirmek için web'de bulacağınız snippet'lerin çoğu kırılgandır. Çoğu durumda yalnızca belirli bir HTML parçası için çalışırlar. Bir yere boşluk eklemek, bir etikete özellik eklemek veya bir etiketi değiştirmek gibi küçük biçimlendirme değişiklikleri, RegEx'in düzgün yazılmadığı zamanlarda başarısız olmasına neden olabilir. HTML'de RegEx'i kullanmadan önce ne yaptığınızı bilmelisiniz.

HTML ayrıştırıcıları HTML'nin sözdizimsel kurallarını zaten biliyorlar. Yazdığınız her yeni RegEx için düzenli ifadeler öğretilmelidir. RegEx bazı durumlarda iyidir, ancak gerçekten kullanım durumunuza bağlıdır.

Sen daha güvenilir ayrıştırıcılar yazabilirsiniz , ancak bir yazma tam ve güvenilir düzenli ifadeler ile özel ayrıştırıcı yukarıda belirtilen kütüphaneler zaten var ve bu konuda çok daha iyi bir iş yapmak zaman kaybıdır.

Ayrıca bkz. Html Cthulhu Yolu Ayrıştırma


Kitabın

Eğer biraz para harcamak istiyorsanız,

PHP Architect ya da yazarlara bağlı değilim.


10
@ İhtiyaçlarınıza göre değişti. CSS Seçici sorgularına ihtiyacım yok, bu yüzden DOM'u yalnızca XPath ile kullanıyorum. phpQuery bir jQuery portu olmayı amaçlamaktadır. Zend_Dom hafiftir. Hangisini en çok sevdiğini görmek için onları kontrol etmelisin.
Gordon

2
@ Ms2ger Çoğunlukla ama tamamen değil. Yukarıda belirtildiği gibi, libxml tabanlı ayrıştırıcıları kullanabilirsiniz, ancak bunların boğulacağı özel durumlar vardır. Maksimum uyumluluğa ihtiyacınız varsa, özel bir ayrıştırıcı ile daha iyi durumdasınızdır. Ayrımı korumayı tercih ederim.
Gordon

9
PHP Basit HTML DOM Ayrıştırıcı kullanmamanız için önemli.
Petah

3
29 Mart 2012 itibariyle DOM html5'i desteklemez, XMLReader HTML'yi desteklemez ve PHP için html5lib'de son taahhüt Eylül 2009'dadır. HTML5, HTML4 ve XHTML ayrıştırmak için ne kullanılır?
Shiplu Mokaddim

4
@Nasha Kasten rezil Zalgo rantını yukarıdaki listeden hariç tuttum çünkü kendi başına çok yararlı değil ve yazıldığından beri bazı kargo kültüne yol açıyor. Bir regex'in çözüm olarak ne kadar uygun olursa olsun, insanlar bu bağlantıyla tokatlandı. Daha dengeli görüş için, ben bağlantıya bakın lütfen vermedi yerine dahil ve en yorumlarınızı geçmesi stackoverflow.com/questions/4245008/...
Gordon

322

Basit HTML DOM Ayrıştırıcısını Deneyin

  • PHP 5+ ile yazılmış ve HTML'yi çok kolay bir şekilde değiştirmenizi sağlayan bir HTML DOM ayrıştırıcısı!
  • PHP 5+ gerektirir.
  • Geçersiz HTML'yi destekler.
  • HTML sayfasındaki etiketleri jQuery gibi seçicilerle bulun.
  • Tek bir satırda HTML'den içerik ayıklayın.
  • İndir


Örnekler:

HTML öğeleri nasıl edinilir:

// Create DOM from URL or file
$html = file_get_html('http://www.example.com/');

// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '<br>';

// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '<br>';


HTML öğelerini değiştirme:

// Create DOM from string
$html = str_get_html('<div id="hello">Hello</div><div id="world">World</div>');

$html->find('div', 1)->class = 'bar';

$html->find('div[id=hello]', 0)->innertext = 'foo';

echo $html;


HTML'den içerik ayıklayın:

// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;


Slashdot Kazıma:

// Create DOM from URL
$html = file_get_html('http://slashdot.org/');

// Find all article blocks
foreach($html->find('div.article') as $article) {
    $item['title']     = $article->find('div.title', 0)->plaintext;
    $item['intro']    = $article->find('div.intro', 0)->plaintext;
    $item['details'] = $article->find('div.details', 0)->plaintext;
    $articles[] = $item;
}

print_r($articles);

8
Öncelikle kötü DOM'lar, Invlid kodu, ayrıca DNSBL motoruna karşı analiz yapan js için hazırlamam gereken şeyler var, bu da kötü amaçlı sitelere / içeriğe bakmak için kullanılacak, ayrıca sitemi bir çerçeve etrafında oluşturduğum gibi temiz, okunabilir ve iyi yapılandırılmış olması gerekir. SimpleDim harika ama kod biraz dağınık
RobertPitt

9
@Robert , güvenlikle ilgili şeyler için htmlpurifier.org adresini de kontrol etmek isteyebilirsiniz .
Gordon

3
Geçerli bir noktası var: basit bulmuyorum dekoratör desenini kullanmadığınız sürece simpleHTMLDOM'u uzatmak zor. Kendimi sadece temel sınıf (lar) da kendileri üzerinde değişiklik yaparken ürperti buldum .
Erik

1
Yaptığım html'yi SimpleDOM'a göndermeden önce düzenli olarak çalıştırmaktı.
MB34

1
Bunu şu anda kullanıyorum, birkaç yüz URL'yi işlemek için bir projenin parçası olarak çalıştırıyorum. Çok yavaş oluyor ve düzenli zaman aşımı sürüyor. Harika bir başlangıç ​​betiği ve öğrenmesi sezgisel olarak basit, ancak daha gelişmiş projeler için çok basit.
luke_mclachlan

236

Sadece DOMDocument-> loadHTML () kullanın ve onunla işiniz bitti. libxml'in HTML ayrıştırma algoritması oldukça iyi ve hızlıdır ve popüler inanışın aksine, hatalı biçimlendirilmiş HTML'yi boğmaz.


19
Doğru. Ayrıca, PHP'nin içerik çıkarmak için mükemmel olan yerleşik XPath ve XSLTPişlemci sınıflarıyla çalışır.
Kornel

8
Gerçekten karıştırılmış HTML için, DOM'a teslim etmeden önce her zaman htmltidy ile çalıştırabilirsiniz. HTML'den veri kazımam gerektiğinde, daima DOM veya en azından simplexml kullanıyorum.
Frank Farmer

9
Ayrıştırmayı durduracak uyarıları önlemek için libxml_use_internal_errors (true) öğesini çağırmanın akıllıca olabileceği hatalı biçimlendirilmiş HTML i yüklemeyle ilgili başka bir şey.
Husky

6
DOMDocument'i yaklaşık 1000 html kaynağını (farklı karakter kümeleriyle kodlanmış çeşitli dillerde) ayrıştırmak için kullandım. Bununla ilgili kodlama sorunları yaşayabilirsiniz, ancak bunlar aşılmaz değildir. 3 şeyi bilmeniz gerekir: 1) loadHTML, kodlamayı belirlemek için meta etiketin karakter kümesini kullanır 2) # 2, html içeriği bu bilgileri içermiyorsa yanlış kodlama algılamasına neden olabilir 3) kötü UTF-8 karakterleri ayrıştırıcıyı açabilir. Bu gibi durumlarda, geçici çözümler için mb_detect_encoding () ve Simplepie RSS Parser'in kötü UTF-8 karakter kodlamasını kodlama / dönüştürme / sıyırma kombinasyonunu kullanın.
Sıfır

1
DOM aslında XPath'i destekliyor , DOMXPath'e bir göz atın .
Ryan McCue

147

Neden düzenli ifadeler kullanmamalısınız ve ne zaman kullanmalısınız?

Öncelikle, yaygın bir yanlış adlandırma: Normal ifadeler HTML'yi " ayrıştırmak " için değildir . Normal ifadeler verileri " çıkarabilir " . Çıkarmak için yapıldıkları şey budur. Normal SGML araç kitleri veya temel XML ayrıştırıcıları üzerinden normal ifade HTML'sinin çıkarılmasının en büyük dezavantajı sözdizimsel çabaları ve değişen güvenilirlikleri.

Biraz güvenilir bir HTML çıkarma normal ifadesi oluşturmayı düşünün:

<a\s+class="?playbutton\d?[^>]+id="(\d+)".+?    <a\s+class="[\w\s]*title
[\w\s]*"[^>]+href="(http://[^">]+)"[^>]*>([^<>]+)</a>.+?

basit bir phpQuery veya QueryPath eşdeğerinden daha az okunabilir:

$div->find(".stationcool a")->attr("title");

Bununla birlikte, yardım edebilecekleri belirli kullanım durumları vardır.

  • Birçok DOM geçiş ön tarafı <!--, HTML yorumlarını göstermez , ancak bazen çıkarma için daha yararlı çapalardır. Özellikle sahte HTML varyasyonları <$var>veya SGML kalıntılarının normal ifadelerle uyumu kolaydır.
  • Genellikle düzenli ifadeler işlem sonrası tasarruf sağlayabilir. Ancak HTML varlıkları genellikle manuel bakım gerektirir.
  • Son olarak, son derece basit görevler için <img src = url'leri ayıklamak gibi için, aslında olası bir araçtır. SGML / XML ayrıştırıcılarına göre hız avantajı çoğunlukla bu çok temel çıkarma prosedürleri için geçerlidir.

Bazen düzenli ifadeler kullanarak bir HTML snippet'inin ön ayıklanması bile önerilir /<!--CONTENT-->(.+?)<!--END-->/ ve daha basit HTML ayrıştırıcı ön uçlarını kullanarak kalanını işlemek .

Not: Aslında alternatif olarak XML ayrıştırma ve düzenli ifadeler istihdam bu app var . Geçen hafta PyQuery ayrışması kırıldı ve normal ifade hala işe yaradı. Evet garip, ve kendim açıklayamam. Ama öyle oldu.
Bu yüzden lütfen regex = evil meme ile eşleşmediği için gerçek dünyayı dikkate almayın. Ama buna çok fazla oy vermeyelim. Bu konu için sadece bir sidenote.


20
DOMCommentyorumları okuyabilir, bu nedenle bunun için Regex kullanmak için hiçbir neden yoktur.
Gordon

4
SGML araç setleri veya XML ayrıştırıcıları gerçek dünya HTML'sini ayrıştırmak için uygun değildir. Bunun için sadece özel bir HTML ayrıştırıcısı uygundur.
Alohci

12
@Alohci libxmlDOM kullanır ve libxml HTML yüklerken kullanılacak ayrı bir HTML ayrıştırıcı modülüne sahiptir . loadHTML()
Gordon

6
Peki, sadece "gerçek dünyadaki düşünceniz" bakış açınız hakkında bir yorum. Tabii, HTML ayrıştırılırken Regex için yararlı durumlar vardır. Ayrıca GOTO'yu kullanmak için de faydalı durumlar var. Ve değişken değişkenler için yararlı durumlar vardır. Bu nedenle, belirli bir uygulama onu kullanmak için kesinlikle kod çürümesi değildir. Ama bu ÇOK güçlü bir uyarı işaretidir. Ortalama bir geliştiricinin farkı anlatacak kadar incelikli olması muhtemel değildir. Genel bir kural olarak, Regex GOTO ve Değişken Değişkenlerin hepsi kötüdür. Kötü kullanımlar vardır, ancak bunlar istisnalardır (ve nadirdir) ... (IMHO)
ircmaxell

11
@mario: Aslında, HTML olabilir genellikle adil bir işi bir meme ucu yapmak birçoğunun sürer rağmen, 'düzgün' Regexes kullanılarak çözümlenebilir olması. Genel durumda sadece bir kraliyet ağrısı. İyi tanımlanmış girdisi olan belirli durumlarda, önemsizdir. Bunlar, insanların düzenli ifadeler kullanması gereken durumlardır . Büyük eski aç ağır ayrıştırıcılar, genel durumlar için gerçekten ihtiyacınız olan şeydir, ancak sıradan kullanıcı için bu çizgiyi nerede çizeceği her zaman açık değildir. Hangi kod daha basit ve kolay olursa kazanır.
tchrist

131

phpQuery ve QueryPath , akıcı jQuery API'sinin çoğaltılmasında oldukça benzerdir. Bu yüzden PHP'de HTML'yi düzgün bir şekilde ayrıştırmak için en kolay iki yaklaşımdır .

QueryPath için örnekler

Temel olarak önce bir HTML dizesinden sorgulanabilir bir DOM ağacı oluşturursunuz:

 $qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL

Ortaya çıkan nesne, HTML belgesinin tam bir ağaç temsilini içerir. DOM yöntemleri kullanılarak geçilebilir. Ancak ortak yaklaşım, jQuery'de olduğu gibi CSS seçicilerini kullanmaktır:

 $qp->find("div.classname")->children()->...;

 foreach ($qp->find("p img") as $img) {
     print qp($img)->attr("src");
 }

Çoğunlukla için basit #idve / .classveya DIVetiket seçicileri kullanmak istersiniz ->find(). Ancak , bazen daha hızlı olan XPath deyimlerini de kullanabilirsiniz . Gibi Ayrıca tipik jQuery yöntemleri ->children()ve ->text()özellikle ->attr()sağ HTML parçacıkları ayıklanması basitleştirmek. (Ve zaten SGML varlıklarının kodu çözüldü.)

 $qp->xpath("//div/p[1]");  // get first paragraph in a div

QueryPath ayrıca akışa ( ->append) yeni etiketler eklenmesine ve daha sonra güncellenmiş bir belgenin ( ->writeHTML) çıktısına ve ön bilgisine izin verir . Yalnızca hatalı biçimlendirilmiş HTML'yi ayrıştırmakla kalmaz, aynı zamanda çeşitli XML lehçelerini (ad alanlarıyla birlikte) ve hatta HTML mikro biçimlerinden (XFN, vCard) veri ayıklayabilir.

 $qp->find("a[target=_blank]")->toggleClass("usability-blunder");

.

phpQuery veya QueryPath?

Genellikle QueryPath belgelerin manipülasyonu için daha uygundur. PhpQuery de jQuery daha yakından benzemek için bazı sahte AJAX yöntemleri (sadece HTTP istekleri) uygular. PhpQuery genellikle QueryPath (daha az genel özellikleri nedeniyle) daha hızlı olduğu söylenir.

Farklılıklar hakkında daha fazla bilgi için tagbyte.org adresinden geri dönüşüm makinesindeki bu karşılaştırmaya bakın . (Orijinal kaynak kayboldu, işte bir internet arşivi bağlantısı. Evet, yine de eksik sayfaları, insanları bulabilirsiniz.)

Ve işte kapsamlı bir QueryPath tanıtımı .

Avantajları

  • Sadelik ve Güvenilirlik
  • Kullanımı kolay alternatifler ->find("a img, a object, div a")
  • Uygun veri kaçışı (normal ifade yönlendirme ile karşılaştırıldığında)

88

Basit HTML DOM harika bir açık kaynaklı ayrıştırıcıdır:

simplehtmldom.sourceforge

DOM öğelerini nesneye yönelik bir şekilde ele alır ve yeni yinelemenin, uyumsuz kod için çok fazla kapsama alanı vardır. Ayrıca, JavaScript'te gördüğünüz gibi, o etiket adının tüm öğelerinin örneklerini döndürecek "bul" işlevi gibi bazı harika işlevler de vardır.

Bunu birçok araçta kullandım, birçok farklı web sayfasında test ettim ve bence harika çalışıyor.


61

Burada bahsetmediğim genel bir yaklaşım HTML'yi Tidy aracılığıyla çalıştırmaktır , garantili geçerli XHTML tükürmek için ayarlanabilen . Sonra üzerinde herhangi bir eski XML kitaplığını kullanabilirsiniz.

Ancak özel sorununuza göre, bu projeye bir göz atmalısınız: http://fivefilters.org/content-only/ - Okunabilirlik algoritmasının yalnızca metinsel içeriği (başlıkları değil) çıkarmak için tasarlanmış değiştirilmiş bir sürümüdür ve altbilgiler) bir sayfadan alabilirsiniz.


56

1a ve 2 için: Yeni Symfony Componet sınıfı DOMCrawler'a ( DomCrawler ) oy verirdim . Bu sınıf, CSS Seçicileri'ne benzer sorgulara izin verir. Gerçek dünyadan örnekler için bu sunuma bir göz atın: symfony2-world haberleri .

Bileşen bağımsız çalışacak şekilde tasarlanmıştır ve Symfony olmadan kullanılabilir.

Tek dezavantajı, sadece PHP 5.3 veya daha yeni bir sürümle çalışmasıdır.


jquery benzeri css sorguları iyi söylenir, çünkü w3c belgelerinde eksik olan, ancak jquery'de ekstra özellikler olarak bulunan bazı şeyler vardır.
Nikola Petkanski

53

Bu, genellikle ekran kazıma olarak adlandırılır . Bunun için kullandığım kütüphane Simple HTML Dom Parser .


8
Kesinlikle doğru değil ( en.wikipedia.org/wiki/Screen_scraping#Screen_scraping ). İpucu "ekran" içindedir; açıklanan durumda, hiçbir ekran dahil değildir. Her ne kadar, kuşkusuz, terim son zamanlarda çok fazla yanlış kullanıldı.
Bobby Jack

4
Ekran kazıma yapmıyorum, ayrıştırılacak içeriğe sözleşmem kapsamında içerik tedarikçisi tarafından izin verilecek.
RobertPitt

41

Daha önce ihtiyaçlarımız için oldukça az sayıda tarayıcı oluşturduk. Günün sonunda, genellikle en iyisini yapan basit düzenli ifadelerdir. Yukarıda listelenen kütüphaneler, oluşturuldukları nedenden ötürü iyi olsa da, ne aradığınızı biliyorsanız, düzenli ifadeler gitmek için daha güvenli bir yoldur, çünkü yüklenirse başarısız olan geçerli olmayan HTML / XHTML yapılarını da işleyebilirsiniz parsers çoğu aracılığıyla.



36

Bu, W3C XPath teknolojisinin iyi bir görev açıklaması gibi görünüyor . " İç içe yerleştirilmiş etiketlerdeki tüm hrefözellikleri döndür" gibi sorguları ifade etmek kolaydır . PHP tutkunu olmadığından, XPath'in hangi formda olabileceğini size söyleyemem. HTML dosyasını işlemek için harici bir program çağırabiliyorsanız, XPath'ın komut satırı sürümünü kullanabilmeniz gerekir. Hızlı bir giriş için bkz. Http://en.wikipedia.org/wiki/XPath .img<foo><bar><baz> elements


29

String Parsing yerine DOM kullanan üçüncü taraf alternatifleri SimpleHtmlDom: phpQuery , Zend_Dom , QueryPath ve FluentDom .


3
Yorumlarımı zaten kopyaladıysanız, en azından onları düzgün bir şekilde bağlayın ;) Bu şöyle olmalıdır : SimpleHtmlDom'a String Parsing yerine DOM kullanan üçüncü taraf alternatifleri önerdi : phpQuery , Zend_Dom , QueryPath ve FluentDom .
Gordon

1
İyi cevaplar harika bir kaynaktır. stackoverflow.com/questions/3606792/…
danidacar

24

Evet, amaç için simple_html_dom kullanabilirsiniz. Ancak, özellikle web hurdaya çıkarmak için, simple_html_dom ile oldukça çok çalıştım ve çok savunmasız olduğunu bulduk. Temel işi yapar ama yine de tavsiye etmeyeceğim.

Bu amaçla kıvrımı hiç kullanmadım ama öğrendiğim şey, kıvrımın işi çok daha verimli bir şekilde yapabilmesi ve çok daha sağlam olmasıdır.

Lütfen bu bağlantıyı kontrol edin: scraping-websites-with-curl


2
curl dosyayı alabilir , ancak sizin için HTML'yi ayrıştırmaz. Zor kısmı bu.
cHao

23

QueryPath iyidir, ancak "izleme durumu" na dikkat edin, çünkü ne anlama geldiğini anlamadıysanız, ne olduğunu ve kodun neden çalışmadığını bulmak için çok fazla hata ayıklama zamanı harcadığınız anlamına gelebilir.

Bunun anlamı, sonuç kümesindeki her çağrı nesnedeki sonuç kümesini değiştirir, her bağlantının yeni bir küme olduğu jquery'deki gibi zincirlenemez, sorgunuzdan elde edilen sonuçlar olan tek bir kümeniz vardır ve her işlev çağrısı değişir bu tek set.

jquery benzeri davranışlar elde etmek için, bir filtre yapmadan / benzer bir işlem yapmadan önce dallamanız gerekir, bu da jquery'de olanları çok daha yakından yansıtacağı anlamına gelir.

$results = qp("div p");
$forename = $results->find("input[name='forename']");

$resultsŞimdi bu çok beni tetikledi input[name='forename']değil orijinal sorgu için sonuç kümesi içerir "div p", ne buldum QueryPath filtreleri ve bulgular ve sonuçlarınızı değiştirir ve bunları nesnede saklar her şeyi izledi . bunun yerine bunu yapmalısın

$forename = $results->branch()->find("input[name='forname']")

daha sonra $resultsdeğiştirilmeyecek ve sonuç setini tekrar tekrar kullanabilirsiniz, belki çok daha fazla bilgiye sahip biri bunu biraz temizleyebilir, ancak temelde bulduğumdan böyle.


20

Advanced Html Dom , aynı arabirimi sunan basit bir HTML DOM değişimidir, ancak DOM tabanlıdır, bu da ilişkili bellek sorunlarının hiçbirinin meydana gelmediği anlamına gelir.

Ayrıca jQuery uzantıları da dahil olmak üzere tam CSS desteğine sahiptir .


Advanced Html Dom'dan iyi sonuçlar aldım ve kabul edilen cevapta listede olması gerektiğini düşünüyorum. "Bu projenin amacı, PHP'nin basit html dom kütüphanesi için DOM tabanlı bir drop-in yerine geçmektir." / Str_get_html dosyasını kullanıyorsanız ... herhangi bir şeyi değiştir." archive.is/QtSuj#selection-933.34-933.100 , bazı uyumsuzlukları karşılamak için kodunuzda değişiklik yapmanız gerekebileceğidir. Projenin github konularında bildiğim dört kişiyi not ettim. github.com/monkeysuffrage/advanced_html_dom/issues
ChrisJJ

Çalıştı! Teşekkürler
Faisal Shani

18

İçin HTML5 , HTML5 lib yıllardır terk edildi. Son güncelleme ve bakım kayıtları ile bulabildiğim tek HTML5 kütüphanesi , bir haftadan biraz önce beta 1.0'a getirilen html5-php'dir .


17

GB dosyalarını kolayca işleyebilen genel amaçlı bir XML ayrıştırıcı yazdım. XMLReader'a dayanır ve kullanımı çok kolaydır:

$source = new XmlExtractor("path/to/tag", "/path/to/file.xml");
foreach ($source as $tag) {
    echo $tag->field1;
    echo $tag->field2->subfield1;
}

İşte github repo: XmlExtractor


17

PHPPowertools / DOM-Query adında , jQuery ile yaptığınız gibi HTML5 ve XML belgelerini taramanızı sağlayan bir kütüphane oluşturdum .

Kaputun altında, CSS seçicilerinin XPath seçicilerine dönüştürülmesi için symfony / DomCrawler kullanır . İyi bir performans sağlamak için bir nesneyi diğerine geçirirken bile her zaman aynı DomDocument'i kullanır.


Örnek kullanım:

namespace PowerTools;

// Get file content
$htmlcode = file_get_contents('https://github.com');

// Define your DOMCrawler based on file string
$H = new DOM_Query($htmlcode);

// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query($H->select('body'));

// Passing a string (CSS selector)
$s = $H->select('div.foo');

// Passing an element object (DOM Element)
$s = $H->select($documentBody);

// Passing a DOM Query object
$s = $H->select( $H->select('p + p'));

// Select the body tag
$body = $H->select('body');

// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');

// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');

// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
    return $i . " - " . $val->attr('class');
});

// Append the following HTML to all site blocks
$siteblocks->append('<div class="site-center"></div>');

// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));

// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
    return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});

// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();

// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');

// Wrap the site's footer within two nex selectors
$sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');

[...]

Desteklenen yöntemler:


  1. Belirgin nedenlerle 'select' olarak yeniden adlandırıldı
  2. 'Boş' PHP'de ayrılmış bir kelime olduğu için 'void' olarak yeniden adlandırıldı

NOT :

Kitaplık ayrıca PSR-0 uyumlu kitaplıklar için kendi sıfır yapılandırmalı otomatik yükleyicisini de içerir. Dahil edilen örnek, herhangi bir ek yapılandırma olmadan kutudan çıkarılmalıdır. Alternatif olarak, besteci ile kullanabilirsiniz.


İş için doğru araç gibi görünüyor, ancak benim için PHP 5.6.23'te Worpress'te yüklenmiyor. Doğru bir şekilde dahil etmek için herhangi bir ek talimat var mı? Şunlarla dahil: define ("BASE_PATH", dirname ( FILE )); define ("LIBRARY_PATH", BASE_PATH. DIRECTORY_SEPARATOR. 'lib / satıcı'); LIBRARY_PATH gerektirir. DIRECTORY_SEPARATOR. 'Loader.php'; Yükleyici :: init (dizi (LIBRARY_PATH, USER_PATH)); in function.php
lithiumlab

15

Herhangi bir "bozuk" HTML'yi temizlemek ve HTML'yi XHTML'ye dönüştürmek için HTML Tidy gibi bir şey kullanmayı deneyebilir ve daha sonra bir XML ayrıştırıcıyla ayrıştırabilirsiniz.


15

Deneyebileceğiniz başka bir seçenek de QueryPath . Bu jQuery esinlenerek, ancak PHP sunucu üzerinde ve içinde kullanılan Drupal .


12

XML_HTMLSaxdaha istikrarlı - artık korunmasa bile. Başka bir seçenek de HTML'yi Html Tidy aracılığıyla yönlendirmek ve daha sonra standart XML araçlarıyla ayrıştırmak olabilir.



11

Daha önce bahsedilen HTML / XML DOM'yi işlemenin birçok yolu vardır. Dolayısıyla, bunları kendim listelemeye çalışmam.

Ben sadece DOM uzantısı kullanmayı tercih neden eklemek istiyorum ve neden:

  • iit, temeldeki C kodunun performans avantajından en iyi şekilde yararlanır
  • OO PHP (ve alt sınıflamama izin veriyor)
  • oldukça düşük seviyedir (daha gelişmiş davranışlar için şişirilmemiş bir temel olarak kullanmamı sağlar)
  • DOM'un her bölümüne erişim sağlar (örneğin, daha az bilinen XML özelliklerinden bazılarını yok sayan SimpleXml)
  • DOM taraması için kullanılan ve yerel Javascript'te kullanılan sözdizimine benzer bir sözdizimine sahiptir.

CSS seçicilerini kullanma yeteneğini kaçırırken DOMDocument, bu özelliği eklemenin oldukça basit ve kullanışlı bir yolu var: alt sınıfınıza alt sınıflandırma DOMDocumentve JS benzeri querySelectorAllve querySelectoryöntemler ekleme .

Seçicileri ayrıştırmak için Symfony çerçevesinden çok minimalist CssSelector bileşenini kullanmanızı öneririm . Bu bileşen yalnızca CSS seçicilerini XPath seçicilerine çevirir;DOMXpath karşılık gelen Nodelist'i almak için a'ya beslenebilir.

Daha sonra bu (hala çok düşük seviye) alt sınıfı daha yüksek seviyeli sınıflar için temel olarak kullanabilirsiniz, örn. çok özel XML türlerini ayrıştırın veya daha fazla jQuery benzeri davranış ekleyin.

Aşağıdaki kod doğrudan DOM-Query kütüphanemden çıkıyor ve tarif ettiğim tekniği kullanıyor.

HTML ayrıştırma için:

namespace PowerTools;

use \Symfony\Component\CssSelector\CssSelector as CssSelector;

class DOM_Document extends \DOMDocument {
    public function __construct($data = false, $doctype = 'html', $encoding = 'UTF-8', $version = '1.0') {
        parent::__construct($version, $encoding);
        if ($doctype && $doctype === 'html') {
            @$this->loadHTML($data);
        } else {
            @$this->loadXML($data);
        }
    }

    public function querySelectorAll($selector, $contextnode = null) {
        if (isset($this->doctype->name) && $this->doctype->name == 'html') {
            CssSelector::enableHtmlExtension();
        } else {
            CssSelector::disableHtmlExtension();
        }
        $xpath = new \DOMXpath($this);
        return $xpath->query(CssSelector::toXPath($selector, 'descendant::'), $contextnode);
    }

    [...]

    public function loadHTMLFile($filename, $options = 0) {
        $this->loadHTML(file_get_contents($filename), $options);
    }

    public function loadHTML($source, $options = 0) {
        if ($source && $source != '') {
            $data = trim($source);
            $html5 = new HTML5(array('targetDocument' => $this, 'disableHtmlNsInDom' => true));
            $data_start = mb_substr($data, 0, 10);
            if (strpos($data_start, '<!DOCTYPE ') === 0 || strpos($data_start, '<html>') === 0) {
                $html5->loadHTML($data);
            } else {
                @$this->loadHTML('<!DOCTYPE html><html><head><meta charset="' . $encoding . '" /></head><body></body></html>');
                $t = $html5->loadHTMLFragment($data);
                $docbody = $this->getElementsByTagName('body')->item(0);
                while ($t->hasChildNodes()) {
                    $docbody->appendChild($t->firstChild);
                }
            }
        }
    }

    [...]
}

Ayrıca Symfony için CssSelector bileşenini oluşturma kararı ve nasıl kullanılacağı konusunda Symfony'nin yaratıcısı Fabien Potencier tarafından XML belgelerini ayrıştırma konusuna bakın .


9

FluidXML ile XPath ve CSS Seçicileri kullanarak XML'yi sorgulayabilir ve yineleyebilirsiniz .

$doc = fluidxml('<html>...</html>');

$title = $doc->query('//head/title')[0]->nodeValue;

$doc->query('//body/p', 'div.active', '#bgId')
        ->each(function($i, $node) {
            // $node is a DOMNode.
            $tag   = $node->nodeName;
            $text  = $node->nodeValue;
            $class = $node->getAttribute('class');
        });

https://github.com/servo-php/fluidxml


7

Üç satır halinde XML'den JSON ve dizi:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

Ta da!


7

HTML'yi normal ifadeyle ayrıştırmamak için çeşitli nedenler vardır. Ancak, hangi HTML'nin oluşturulacağı üzerinde tam denetime sahipseniz, basit normal ifade ile yapabilirsiniz.

Yukarıda HTML'yi normal ifadeyle ayrıştıran bir işlev var. Bu işlevin çok hassas olduğunu ve HTML'nin belirli kurallara uymasını gerektirdiğini, ancak birçok senaryoda çok iyi çalıştığını unutmayın. Basit bir ayrıştırıcı istiyorsanız ve kitaplık yüklemek istemiyorsanız, bunu deneyin:

function array_combine_($keys, $values) {
    $result = array();
    foreach ($keys as $i => $k) {
        $result[$k][] = $values[$i];
    }
    array_walk($result, create_function('&$v', '$v = (count($v) == 1)? array_pop($v): $v;'));

    return $result;
}

function extract_data($str) {
    return (is_array($str))
        ? array_map('extract_data', $str)
        : ((!preg_match_all('#<([A-Za-z0-9_]*)[^>]*>(.*?)</\1>#s', $str, $matches))
            ? $str
            : array_map(('extract_data'), array_combine_($matches[1], $matches[2])));
}

print_r(extract_data(file_get_contents("http://www.google.com/")));

2

Https://github.com/ivopetkov/html5-dom-document-php adresinde ücretsiz olarak bulunan HTML5DOMDocument adlı bir kütüphane oluşturdum.

Sorgu seçicileri de desteklediğini düşünüyorum. İşte bazı örnek kod:

$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('<!DOCTYPE html><html><body><h1>Hello</h1><div class="content">This is some text</div></body></html>');
echo $dom->querySelector('h1')->innerHTML;

0

JQuery seçicisine aşina iseniz, ScarletsQuery for PHP'yi kullanabilirsiniz

<pre><?php
include "ScarletsQuery.php";

// Load the HTML content and parse it
$html = file_get_contents('https://www.lipsum.com');
$dom = Scarlets\Library\MarkupLanguage::parseText($html);

// Select meta tag on the HTML header
$description = $dom->selector('head meta[name="description"]')[0];

// Get 'content' attribute value from meta tag
print_r($description->attr('content'));

$description = $dom->selector('#Content p');

// Get element array
print_r($description->view);

Bu kütüphane genellikle çevrimdışı html işlemek için 1 saniyeden az sürer.
Ayrıca, etiket özelliklerinde geçersiz HTML veya eksik teklifi kabul eder.


0

Xml ayrıştırma için en iyi yöntem:

$xml='http://www.example.com/rss.xml';
$rss = simplexml_load_string($xml);
$i = 0;
foreach ($rss->channel->item as $feedItem) {
  $i++;
  echo $title=$feedItem->title;
  echo '<br>';
  echo $link=$feedItem->link;
  echo '<br>';
  if($feedItem->description !='') {
    $des=$feedItem->description;
  } else {
    $des='';
  }
  echo $des;
  echo '<br>';
  if($i>5) break;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.