Bagaimana Anda menguraikan dan memproses HTML / XML dalam PHP?

Jawaban:

1897

Ekstensi XML Asli

Saya lebih suka menggunakan salah satu ekstensi XML asli karena mereka dibundel dengan PHP, biasanya lebih cepat dari semua lib pihak ke-3 dan memberi saya semua kontrol yang saya butuhkan atas markup.

DOM

Ekstensi DOM memungkinkan Anda untuk beroperasi pada dokumen XML melalui DOM API dengan PHP 5. Ini adalah implementasi dari W3C's Document Object Model Core Level 3, antarmuka platform dan bahasa-netral yang memungkinkan program dan skrip untuk mengakses dan memperbarui secara dinamis konten, struktur dan gaya dokumen.

DOM mampu mem-parsing dan memodifikasi dunia nyata (rusak) HTML dan dapat melakukan permintaan XPath . Itu didasarkan pada libxml .

Butuh beberapa waktu untuk menjadi produktif dengan DOM, tetapi waktu itu sangat berharga untuk IMO. Karena DOM adalah antarmuka bahasa-agnostik, Anda akan menemukan implementasi dalam banyak bahasa, jadi jika Anda perlu mengubah bahasa pemrograman Anda, kemungkinan Anda sudah tahu cara menggunakan DOM API bahasa itu.

Contoh penggunaan dasar dapat ditemukan dalam Meraih atribut href dari elemen A dan gambaran umum konseptual umum dapat ditemukan di DOMDocument di php

Cara menggunakan ekstensi DOM telah dibahas secara luas di StackOverflow , jadi jika Anda memilih untuk menggunakannya, Anda dapat yakin bahwa sebagian besar masalah yang Anda hadapi dapat diselesaikan dengan mencari / menelusuri Stack Overflow.

XMLReader

Ekstensi XMLReader adalah parser tarikan XML. Pembaca bertindak sebagai kursor maju pada aliran dokumen dan berhenti di setiap node di jalan.

XMLReader, seperti DOM, didasarkan pada libxml. Saya tidak tahu bagaimana cara memicu Modul Parser HTML, jadi kemungkinan menggunakan XMLReader untuk mem-parsing HTML yang rusak mungkin kurang kuat daripada menggunakan DOM di mana Anda dapat secara eksplisit mengatakannya untuk menggunakan Modul Parser HTML libxml.

Contoh penggunaan dasar dapat ditemukan untuk mendapatkan semua nilai dari tag h1 menggunakan php

Parser XML

Ekstensi ini memungkinkan Anda membuat parser XML dan kemudian menentukan penangan untuk berbagai acara XML. Setiap parser XML juga memiliki beberapa parameter yang dapat Anda sesuaikan.

Pustaka XML Parser juga didasarkan pada libxml, dan mengimplementasikan parser dorong XML gaya SAX . Ini mungkin merupakan pilihan yang lebih baik untuk manajemen memori daripada DOM atau SimpleXML, tetapi akan lebih sulit untuk bekerja dengan daripada parser tarik yang diterapkan oleh XMLReader.

SimpleXml

Ekstensi SimpleXML menyediakan toolset yang sangat sederhana dan mudah digunakan untuk mengkonversi XML ke objek yang dapat diproses dengan pemilih properti normal dan array iterator.

SimpleXML adalah opsi ketika Anda tahu HTML itu valid XHTML. Jika Anda perlu mem-parsing HTML yang rusak, bahkan tidak mempertimbangkan SimpleXml karena itu akan tersedak.

Contoh penggunaan dasar dapat ditemukan di Program sederhana untuk simpul CRUD dan nilai simpul file xml dan ada banyak contoh tambahan dalam Manual PHP .


Perpustakaan Pihak Ketiga (berbasis libxml)

Jika Anda lebih suka menggunakan lib pihak ke-3, saya sarankan menggunakan lib yang benar-benar menggunakan DOM / libxml di bawahnya alih-alih parsing string.

FluentDom - Repo

FluentDOM menyediakan antarmuka XML fasih seperti jQuery untuk DOMDocument di PHP. Selektor ditulis dalam XPath atau CSS (menggunakan pengonversi CSS ke XPath). Versi saat ini memperluas DOM yang mengimplementasikan antarmuka standar dan menambahkan fitur dari DOM Living Standard. FluentDOM dapat memuat format seperti JSON, CSV, JsonML, RabbitFish dan lainnya. Dapat diinstal melalui Komposer.

HtmlPageDom

Wa72 \ HtmlPageDom` adalah pustaka PHP untuk memudahkan manipulasi dokumen HTML dengan menggunakan itu membutuhkan DomCrawler dari komponen Symfony2 untuk melintasi pohon DOM dan memperluasnya dengan menambahkan metode untuk memanipulasi pohon DOM dokumen HTML.

phpQuery (tidak diperbarui selama bertahun-tahun)

phpQuery adalah API Document Object Model (DOM) API sisi-server, rantaiable, didorong selektor berdasarkan jQuery JavaScript Library yang ditulis dalam PHP5 dan menyediakan tambahan Command Line Interface (CLI).

Lihat juga: https://github.com/electrolinux/phpquery

Zend_Dom

Zend_Dom menyediakan alat untuk bekerja dengan dokumen dan struktur DOM. Saat ini, kami menawarkan Zend_Dom_Query, yang menyediakan antarmuka terpadu untuk menanyakan dokumen DOM menggunakan pemilih XPath dan CSS.

QueryPath

QueryPath adalah perpustakaan PHP untuk memanipulasi XML dan HTML. Ini dirancang untuk bekerja tidak hanya dengan file lokal, tetapi juga dengan layanan web dan sumber daya database. Ini mengimplementasikan banyak antarmuka jQuery (termasuk pemilih CSS-style), tetapi sangat disetel untuk penggunaan sisi server. Dapat diinstal melalui Komposer.

fDOMDokumen

fDOMDocument memperluas DOM standar untuk menggunakan pengecualian pada semua kesempatan kesalahan alih-alih peringatan atau pemberitahuan PHP. Mereka juga menambahkan berbagai metode khusus dan cara pintas untuk kenyamanan dan untuk menyederhanakan penggunaan DOM.

saber / xml

saber / xml adalah perpustakaan yang membungkus dan memperluas kelas XMLReader dan XMLWriter untuk membuat sistem pemetaan "xml to object / array" sederhana dan pola desain. Menulis dan membaca XML adalah single-pass dan karenanya cepat dan membutuhkan memori rendah pada file xml besar.

FluidXML

FluidXML adalah perpustakaan PHP untuk memanipulasi XML dengan API yang ringkas dan lancar. Ini memanfaatkan XPath dan pola pemrograman yang lancar agar menyenangkan dan efektif.


Pihak ke-3 (tidak berbasis libxml)

Manfaat membangun berdasarkan DOM / libxml adalah Anda mendapatkan kinerja yang baik karena Anda didasarkan pada ekstensi asli. Namun, tidak semua lib pihak ketiga turun rute ini. Beberapa dari mereka tercantum di bawah ini

PHP Parser DOM HTML Sederhana

  • Pengurai HTML DOM yang ditulis dalam PHP5 + memungkinkan Anda memanipulasi HTML dengan cara yang sangat mudah!
  • Membutuhkan PHP 5+.
  • Mendukung HTML yang tidak valid.
  • Temukan tag pada halaman HTML dengan pemilih seperti jQuery.
  • Ekstrak konten dari HTML dalam satu baris.

Saya biasanya tidak merekomendasikan parser ini. Basis kode mengerikan dan parser itu sendiri agak lambat dan memori haus. Tidak semua penyeleksi jQuery (seperti penyeleksi anak ) dimungkinkan. Pustaka berbasis libxml mana pun harus mengungguli ini dengan mudah.

Parser PHP Html

PHPHtmlParser adalah parser html sederhana, fleksibel, yang memungkinkan Anda memilih tag menggunakan pemilih css, seperti jQuery. Tujuannya adalah untuk membantu pengembangan alat yang membutuhkan cara cepat dan mudah untuk menghapus html, apakah itu valid atau tidak! Proyek ini asli didukung oleh sunra / php-simple-html-dom-parser tetapi dukungannya tampaknya telah berhenti sehingga proyek ini adalah adaptasi saya dari karya sebelumnya.

Sekali lagi, saya tidak akan merekomendasikan parser ini. Agak lambat dengan penggunaan CPU yang tinggi. Juga tidak ada fungsi untuk menghapus memori objek DOM yang dibuat. Masalah-masalah ini berskala terutama dengan loop bersarang. Dokumentasi itu sendiri tidak akurat dan salah eja, tanpa respons terhadap perbaikan sejak 14 Apr 16.

Ganon

  • Token universal dan Parser HTML / XML / RSS DOM
    • Kemampuan untuk memanipulasi elemen dan atributnya
    • Mendukung HTML dan UTF8 yang tidak valid
  • Dapat melakukan kueri mirip CSS3 canggih pada elemen (seperti jQuery - namespaces didukung)
  • Perindah HTML (seperti Tidy HTML)
    • Minimalkan CSS dan Javascript
    • Mengurutkan atribut, mengubah huruf besar-kecil, indentasi yang benar, dll.
  • Dapat diperpanjang
    • Parsing dokumen menggunakan panggilan balik berdasarkan karakter / token saat ini
    • Operasi dipisahkan dalam fungsi yang lebih kecil untuk penggantian yang mudah
  • Cepat dan mudah

Tidak pernah menggunakannya. Tidak tahu apakah itu bagus.


HTML 5

Anda dapat menggunakan hal di atas untuk parsing HTML5, tetapi mungkin ada kebiasaan karena markup memungkinkan HTML5. Jadi untuk HTML5 Anda ingin mempertimbangkan untuk menggunakan parser khusus

html5lib

Implementasi Python dan PHP dari parser HTML berdasarkan pada spesifikasi WHATWG HTML5 untuk kompatibilitas maksimum dengan browser web desktop utama.

Kita mungkin melihat lebih banyak pengurai khusus setelah HTML5 selesai. Ada juga blogpost oleh W3 yang berjudul How-To untuk parsing html 5 yang layak untuk dicoba.


Layanan web

Jika Anda merasa tidak ingin pemrograman PHP, Anda juga dapat menggunakan layanan Web. Secara umum, saya menemukan sangat sedikit utilitas untuk ini, tapi itu hanya saya dan kasus penggunaan saya.

ScraperWiki .

Antarmuka eksternal ScraperWiki memungkinkan Anda untuk mengekstrak data dalam bentuk yang Anda inginkan untuk digunakan di web atau di aplikasi Anda sendiri. Anda juga dapat mengekstrak informasi tentang status pengikis apa pun.


Ekspresi Reguler

Terakhir dan paling tidak disarankan , Anda dapat mengekstrak data dari HTML dengan ekspresi reguler . Secara umum menggunakan Ekspresi Reguler pada HTML tidak disarankan.

Sebagian besar cuplikan yang Anda temukan di web untuk mencocokkan markup adalah rapuh. Dalam kebanyakan kasus mereka hanya bekerja untuk bagian HTML yang sangat khusus. Perubahan markup kecil, seperti menambahkan spasi putih di suatu tempat, atau menambahkan, atau mengubah atribut dalam tag, dapat membuat RegEx gagal ketika tidak ditulis dengan benar. Anda harus tahu apa yang Anda lakukan sebelum menggunakan RegEx di HTML.

Pengurai HTML sudah mengetahui aturan sintaksis HTML. Ekspresi reguler harus diajarkan untuk setiap RegEx baru yang Anda tulis. RegEx baik-baik saja dalam beberapa kasus, tetapi itu benar-benar tergantung pada kasus penggunaan Anda.

Anda bisa menulis parser yang lebih andal , tetapi menulis yang lengkap dan andal parser khusus yang dengan ekspresi reguler adalah buang-buang waktu ketika pustaka yang disebutkan di atas sudah ada dan melakukan pekerjaan yang jauh lebih baik dalam hal ini.

Juga lihat Parsing Html The Cthulhu Way


Buku

Jika Anda ingin menghabiskan uang, lihatlah

Saya tidak berafiliasi dengan Arsitek PHP atau penulis.

Gordon
sumber
10
@Dimiliki yang tergantung pada kebutuhan Anda. Saya tidak perlu untuk pertanyaan Pemilih CSS, itulah sebabnya saya menggunakan DOM dengan XPath secara eksklusif. phpQuery bertujuan untuk menjadi port jQuery. Zend_Dom ringan. Anda benar-benar harus memeriksa mereka untuk melihat mana yang paling Anda sukai.
Gordon
2
@ Ms2ger Sebagian besar, tetapi tidak sepenuhnya. Seperti yang sudah ditunjukkan di atas, Anda dapat menggunakan parser berbasis libxml tetapi ada kasus khusus di mana mereka akan tersedak. Jika Anda membutuhkan kompatibilitas maksimum, Anda lebih baik dengan parser khusus. Saya lebih suka menjaga perbedaan.
Gordon
9
Maksud Anda untuk tidak menggunakan PHP Simple HTML DOM Parser tampaknya bisa diperdebatkan.
Petah
3
Pada 29 Maret 2012, DOM tidak mendukung html5, XMLReader tidak mendukung HTML dan komit terakhir pada html5lib untuk PHP pada Sep 2009. Apa yang harus digunakan untuk mem-parsing HTML5, HTML4 dan XHTML?
Shiplu Mokaddim
4
@Nasha Saya sengaja mengecualikan kata-kata kasar Zalgo yang terkenal dari daftar di atas karena itu tidak terlalu membantu sendiri dan menyebabkan beberapa kultus kargo sejak ditulis. Orang-orang ditampar dengan tautan itu tidak peduli seberapa tepat suatu regex sebagai solusi. Untuk pendapat yang lebih seimbang, silakan lihat link saya tidak termasuk bukan dan pergi melalui komentar di stackoverflow.com/questions/4245008/...
Gordon
322

Coba Parser DOM HTML Sederhana

  • Pengurai HTML DOM ditulis dalam PHP 5+ yang memungkinkan Anda memanipulasi HTML dengan cara yang sangat mudah!
  • Membutuhkan PHP 5+.
  • Mendukung HTML yang tidak valid.
  • Temukan tag pada halaman HTML dengan pemilih seperti jQuery.
  • Ekstrak konten dari HTML dalam satu baris.
  • Unduh


Contoh:

Cara mendapatkan elemen HTML:

// 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>';


Cara memodifikasi elemen HTML:

// 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;


Ekstrak konten dari HTML:

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


Scraping Slashdot:

// 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);
Naveed
sumber
8
Yah pertama-tama ada hal-hal yang perlu saya persiapkan seperti DOM buruk, kode Invlid, juga analisis terhadap mesin DNSBL, ini juga akan digunakan untuk mencari situs / konten berbahaya, juga karena saya telah membangun situs saya di sekitar kerangka kerja saya. telah dibangun itu harus bersih, mudah dibaca, dan terstruktur dengan baik. SimpleDim hebat tetapi kodenya sedikit berantakan
RobertPitt
9
@ Robert Anda mungkin juga ingin memeriksa htmlpurifier.org untuk hal-hal terkait keamanan.
Gordon
3
Dia punya satu poin yang valid: simpleHTMLDOM sulit untuk diperluas, kecuali jika Anda menggunakan pola dekorator, yang saya temukan sulit. Saya menemukan diri saya bergidik hanya membuat perubahan pada kelas yang mendasarinya.
Erik
1
Apa yang saya lakukan adalah menjalankan html saya melalui rapi sebelum mengirimnya ke SimpleDOM.
MB34
1
Saya menggunakan ini saat ini, menjalankannya sebagai bagian dari proyek untuk memproses beberapa ratus url. Ini menjadi sangat lambat dan batas waktu reguler tetap ada. Ini adalah skrip pemula yang bagus dan mudah dipelajari secara intuitif, tetapi terlalu mendasar untuk proyek yang lebih maju.
luke_mclachlan
236

Cukup gunakan DOMDocument-> loadHTML () dan selesai dengan itu. Algoritma parsing HTML libxml cukup baik dan cepat, dan bertentangan dengan kepercayaan populer, tidak tersedak HTML yang cacat.

Edward Z. Yang
sumber
19
Benar. Dan ia bekerja dengan kelas XPath dan XSLTProcessor bawaan PHP, yang bagus untuk mengekstraksi konten.
Kornel
8
Untuk HTML yang benar-benar hancur, Anda selalu dapat menjalankannya melalui htmltidy sebelum menyerahkannya ke DOM. Setiap kali saya perlu mengikis data dari HTML, saya selalu menggunakan DOM, atau setidaknya simplexml.
Frank Farmer
9
Hal lain dengan memuat saya salah format HTML bahwa mungkin bijaksana untuk memanggil libxml_use_internal_errors (true) untuk mencegah peringatan yang akan berhenti parsing.
Husky
6
Saya telah menggunakan DOMDocument untuk mem-parsing sekitar 1000 sumber html (dalam berbagai bahasa yang dikodekan dengan rangkaian karakter yang berbeda) tanpa masalah. Anda mungkin mengalami masalah penyandian dengan ini, tetapi mereka tidak dapat diatasi. Anda perlu mengetahui 3 hal: 1) loadHTML menggunakan charset meta tag untuk menentukan penyandian 2) # 2 dapat menyebabkan deteksi penyandian yang salah jika konten html tidak menyertakan informasi ini 3) karakter UTF-8 yang buruk dapat membuat parser tersandung. Dalam kasus seperti itu, gunakan kombinasi mb_detect_encoding () dan Simplepie RSS Parser yang menyandikan / mengubah / menghapus kode karakter UTF-8 yang buruk untuk penyelesaiannya.
Nol
1
DOM benar-benar mendukung XPath, lihatlah DOMXPath .
Ryan McCue
147

Mengapa Anda tidak harus dan kapan Anda harus menggunakan ekspresi reguler?

Pertama, kesalahan nama umum: Regexps bukan untuk " parsing " HTML. Namun Regex dapat " mengekstrak " data. Ekstrak adalah tujuan mereka dibuat. Kelemahan utama dari ekstraksi HTML regex atas toolkit SGML yang tepat atau parser XML dasar adalah upaya sintaksis dan keandalan yang beragam.

Pertimbangkan bahwa membuat regex ekstraksi HTML yang agak dapat diandalkan:

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

jauh lebih mudah dibaca dibandingkan dengan phpQuery atau QueryPath yang sederhana:

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

Namun ada kasus penggunaan khusus di mana mereka dapat membantu.

  • Banyak frontend traversal DOM tidak mengungkapkan komentar HTML <!--, yang terkadang merupakan jangkar yang lebih berguna untuk ekstraksi. Khususnya variasi pseudo-HTML <$var>atau residu SGML mudah dijinakkan dengan regexps.
  • Seringkali ekspresi reguler dapat menghemat pasca pemrosesan. Namun entitas HTML sering membutuhkan pemeliharaan manual.
  • Dan terakhir, untuk tugas yang sangat sederhana seperti mengekstraksi <img src = url, sebenarnya itu adalah alat yang mungkin. Keuntungan kecepatan dibandingkan parser SGML / XML sebagian besar hanya datang untuk bermain untuk prosedur ekstraksi yang sangat mendasar ini.

Kadang-kadang bahkan disarankan untuk mengekstraksi cuplikan HTML menggunakan ekspresi reguler /<!--CONTENT-->(.+?)<!--END-->/dan memproses sisanya menggunakan antarmuka parser HTML yang lebih sederhana.

Catatan: Saya sebenarnya memiliki aplikasi ini , di mana saya menggunakan parsing XML dan ekspresi reguler sebagai gantinya. Baru minggu lalu parsing PyQuery rusak, dan regex masih bekerja. Ya aneh, dan saya tidak bisa menjelaskannya sendiri. Tapi begitulah yang terjadi.
Jadi tolong jangan memilih pertimbangan dunia nyata turun, hanya karena tidak cocok dengan regex = meme jahat. Tapi mari kita juga jangan memilih ini terlalu banyak. Itu hanya sidenote untuk topik ini.

mario
sumber
20
DOMCommentdapat membaca komentar, jadi tidak ada alasan untuk menggunakan Regex untuk itu.
Gordon
4
Baik toolkit SGML atau parser XML tidak cocok untuk parsing HTML dunia nyata. Untuk itu, hanya pengurai HTML khusus yang sesuai.
Alohci
12
@Alohci DOMmenggunakan libxml dan libxml memiliki modul parser HTML terpisah yang akan digunakan saat memuat HTML loadHTML()sehingga sangat banyak memuat "dunia nyata" (baca rusak) HTML.
Gordon
6
Nah, hanya komentar tentang sudut pandang "pertimbangan dunia nyata" Anda. Tentu, ada situasi yang berguna untuk Regex saat mem-parsing HTML. Dan ada juga situasi yang berguna untuk menggunakan GOTO. Dan ada situasi berguna untuk variabel-variabel. Jadi tidak ada implementasi tertentu yang secara pasti membusuk kode untuk menggunakannya. Tapi itu adalah tanda peringatan yang SANGAT kuat. Dan rata-rata pengembang cenderung tidak cukup bernuansa untuk mengatakan perbedaannya. Jadi sebagai aturan umum, Regex GOTO dan Variable-Variables semuanya jahat. Ada kegunaan non-jahat, tetapi itu adalah pengecualian (dan jarang itu) ... (IMHO)
ircmaxell
11
@ Mario: Sebenarnya, HTML dapat 'diurai' dengan benar menggunakan regex, meskipun biasanya dibutuhkan beberapa dari mereka untuk melakukan pekerjaan yang adil. Ini hanya rasa sakit kerajaan dalam kasus umum. Dalam kasus-kasus tertentu dengan input yang terdefinisi dengan baik, inputnya sepele. Itu adalah kasus-kasus di mana orang harus menggunakan regex. Pengurai berat lapar besar dan besar benar-benar apa yang Anda butuhkan untuk kasus-kasus umum, meskipun tidak selalu jelas bagi pengguna biasa di mana menarik garis itu. Kode mana pun yang lebih sederhana dan mudah, akan menang.
tchrist
131

phpQuery dan QueryPath sangat mirip dalam mereplikasi API jQuery yang lancar. Itu juga mengapa mereka dua pendekatan termudah untuk mem-parsing HTML dengan benar di PHP.

Contoh untuk QueryPath

Pada dasarnya, Anda pertama kali membuat pohon DOM yang dapat dicari dari string HTML:

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

Objek yang dihasilkan berisi representasi pohon lengkap dari dokumen HTML. Itu dapat dilalui menggunakan metode DOM. Tetapi pendekatan umum adalah menggunakan penyeleksi CSS seperti di jQuery:

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

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

Sebagian besar Anda ingin menggunakan penyeleksi sederhana #iddan .classatau DIVtag untuk ->find(). Tapi Anda juga bisa menggunakan pernyataan XPath , yang terkadang lebih cepat. Juga metode jQuery yang khas seperti ->children()dan ->text()dan khususnya ->attr()menyederhanakan mengekstrak cuplikan HTML yang tepat. (Dan entitas SGML mereka sudah diterjemahkan.)

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

QueryPath juga memungkinkan menyuntikkan tag baru ke dalam aliran ( ->append), dan kemudian menghasilkan dan mempra cantik dokumen yang diperbarui ( ->writeHTML). Itu tidak hanya dapat menguraikan HTML cacat, tetapi juga berbagai dialek XML (dengan ruang nama), dan bahkan mengekstrak data dari mikroformats HTML (XFN, vCard).

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

.

phpQuery atau QueryPath?

Secara umum QueryPath lebih cocok untuk memanipulasi dokumen. Sementara phpQuery juga mengimplementasikan beberapa metode pseudo AJAX (hanya permintaan HTTP) agar lebih mirip dengan jQuery. Dikatakan bahwa phpQuery seringkali lebih cepat daripada QueryPath (karena lebih sedikit fitur keseluruhan).

Untuk informasi lebih lanjut tentang perbedaan lihat perbandingan ini pada mesin wayback dari tagbyte.org . (Sumber asli hilang, jadi inilah tautan arsip internet. Ya, Anda masih dapat menemukan halaman yang hilang, orang-orang.)

Dan inilah pengantar QueryPath yang komprehensif .

Keuntungan

  • Kesederhanaan dan Keandalan
  • Mudah digunakan alternatif ->find("a img, a object, div a")
  • Penghapusan data yang benar (dibandingkan dengan grepping ekspresi reguler)
mario
sumber
88

Simple HTML DOM adalah parser open-source yang bagus:

simplehtmldom.sourceforge

Ini memperlakukan elemen DOM dengan cara yang berorientasi objek, dan iterasi baru memiliki banyak cakupan untuk kode yang tidak sesuai. Ada juga beberapa fungsi hebat yang akan Anda lihat di JavaScript, seperti fungsi "find", yang akan mengembalikan semua instance elemen dari nama tag itu.

Saya telah menggunakan ini di sejumlah alat, mengujinya pada berbagai jenis halaman web, dan saya pikir ini berfungsi dengan baik.

Robert Elwell
sumber
61

Salah satu pendekatan umum yang belum pernah saya sebutkan di sini adalah menjalankan HTML melalui Tidy , yang dapat diatur untuk meludahkan XHTML yang dijamin-valid. Kemudian Anda bisa menggunakan pustaka XML lama di atasnya.

Tetapi untuk masalah spesifik Anda, Anda harus melihat proyek ini: http://fivefilters.org/content-only/ - ini adalah versi modifikasi dari algoritma Keterbacaan , yang dirancang untuk mengekstrak hanya konten teks (bukan tajuk dan footer) dari sebuah halaman.

Eli
sumber
56

Untuk 1a dan 2: Saya akan memilih kelas Symfony Componet baru DOMCrawler ( DomCrawler ). Kelas ini memungkinkan kueri yang mirip dengan Penyeleksi CSS. Lihatlah presentasi ini untuk contoh dunia nyata: news-of-the-symfony2-world .

Komponen dirancang untuk bekerja mandiri dan dapat digunakan tanpa Symfony.

Satu-satunya kelemahan adalah bahwa itu hanya akan bekerja dengan PHP 5.3 atau lebih baru.

Timo
sumber
query css jquery-like dikatakan dengan baik, karena ada beberapa hal yang hilang dalam dokumentasi w3c, tetapi hadir sebagai fitur tambahan di jquery.
Nikola Petkanski
53

Ngomong -ngomong, ini biasa disebut pengikisan layar . Perpustakaan yang saya gunakan untuk ini adalah Simple HTML Dom Parser .

Joel Verhagen
sumber
8
Tidak sepenuhnya benar ( en.wikipedia.org/wiki/Screen_scraping#Screen_scraping ). Petunjuknya ada di "layar"; dalam kasus yang dijelaskan, tidak ada layar yang terlibat. Meskipun, diakui, istilah ini telah menderita banyak penyalahgunaan baru-baru ini.
Bobby Jack
4
Saya tidak menggores layar, konten yang akan diuraikan akan diotorisasi oleh pemasok konten berdasarkan perjanjian saya.
RobertPitt
41

Kami telah membuat beberapa crawler untuk kebutuhan kami sebelumnya. Pada akhirnya, biasanya adalah ekspresi reguler sederhana yang melakukan hal terbaik. Meskipun pustaka yang tercantum di atas baik untuk alasan pustaka tersebut dibuat, jika Anda tahu apa yang Anda cari, ekspresi reguler adalah cara yang lebih aman untuk digunakan, karena Anda juga dapat menangani struktur HTML / XHTML yang tidak valid , yang akan gagal, jika dimuat melalui sebagian besar parser.

Jancha
sumber
38

Saya merekomendasikan PHP Parser DOM HTML Sederhana .

Ini benar-benar memiliki fitur yang bagus, seperti:

foreach($html->find('img') as $element)
       echo $element->src . '<br>';
Greg
sumber
36

Ini kedengarannya seperti deskripsi tugas yang baik dari teknologi W3C XPath . Sangat mudah untuk mengekspresikan kueri seperti "kembalikan semua hrefatribut dalam imgtag yang bersarang <foo><bar><baz> elements." Bukan sebagai penggemar PHP, saya tidak bisa memberi tahu Anda dalam bentuk apa XPath mungkin tersedia. Jika Anda dapat memanggil program eksternal untuk memproses file HTML, Anda harus dapat menggunakan versi baris perintah XPath. Untuk pengantar cepat, lihat http://en.wikipedia.org/wiki/XPath .

Jens
sumber
29

Alternatif pihak ketiga untuk SimpleHtmlDom yang menggunakan DOM bukannya String Parsing: phpQuery , Zend_Dom , QueryPath dan FluentDom .

Amal Murali
sumber
3
Jika Anda sudah menyalin komentar saya, setidaknya tautkan dengan benar;) Itu seharusnya: Disarankan alternatif pihak ketiga untuk SimpleHtmlDom yang benar-benar menggunakan DOM alih-alih String Parsing: phpQuery , Zend_Dom , QueryPath dan FluentDom .
Gordon
1
Jawaban yang bagus adalah sumber yang bagus. stackoverflow.com/questions/3606792/…
danidacar
24

Ya, Anda dapat menggunakan simple_html_dom untuk tujuan tersebut. Namun saya telah bekerja cukup banyak dengan simple_html_dom, khususnya untuk scrapping web dan merasa terlalu rentan. Ini melakukan pekerjaan dasar tetapi saya tidak akan merekomendasikannya.

Saya tidak pernah menggunakan curl untuk tujuan itu tetapi yang saya pelajari adalah curl dapat melakukan pekerjaan dengan lebih efisien dan jauh lebih solid.

Silakan periksa tautan ini: scraping-websites-with-curl

Rafay
sumber
2
curl bisa mendapatkan file, tetapi itu tidak akan mem-parsing HTML untuk Anda. Itu bagian yang sulit.
cao
23

QueryPath bagus, tetapi hati-hati dengan "status pelacakan" karena jika Anda tidak menyadari apa artinya, itu bisa berarti Anda membuang banyak waktu debugging untuk mencari tahu apa yang terjadi dan mengapa kode tidak berfungsi.

Apa artinya adalah bahwa setiap panggilan pada set hasil memodifikasi set hasil dalam objek, itu tidak dapat diterbangkan seperti di jquery di mana setiap tautan adalah set baru, Anda memiliki satu set yang merupakan hasil dari permintaan Anda dan setiap panggilan fungsi memodifikasi set tunggal itu.

untuk mendapatkan perilaku seperti jquery, Anda perlu melakukan percabangan sebelum melakukan filter / memodifikasi operasi sejenis, yang berarti akan mencerminkan apa yang terjadi di jquery lebih dekat.

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

$resultssekarang berisi hasil yang ditetapkan untuk input[name='forename']TIDAK kueri asli yang sering "div p"membuatku tersandung, apa yang saya temukan adalah bahwa QueryPath melacak filter dan menemukan dan semua yang memodifikasi hasil Anda dan menyimpannya di objek. Anda perlu melakukan ini sebagai gantinya

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

maka $resultstidak akan dimodifikasi dan Anda dapat menggunakan kembali hasil yang ditetapkan berulang-ulang, mungkin seseorang dengan pengetahuan yang lebih banyak dapat menghapus ini sedikit, tetapi pada dasarnya seperti ini dari apa yang saya temukan.

Christopher Thomas
sumber
20

Advanced Html Dom adalah pengganti DOM HTML sederhana yang menawarkan antarmuka yang sama, tetapi berbasis DOM yang berarti tidak ada masalah memori terkait yang terjadi.

Ini juga memiliki dukungan CSS penuh, termasuk ekstensi jQuery .

pguardiario
sumber
Saya mendapat hasil yang baik dari Advanced Html Dom, dan saya pikir itu harus ada dalam daftar di jawaban yang diterima. Suatu hal yang penting untuk diketahui oleh siapa pun yang bergantung pada "Tujuan dari proyek ini adalah menjadi pengganti drop-in berbasis DOM untuk perpustakaan html dom PHP yang sederhana ... Jika Anda menggunakan file / str_get_html maka Anda tidak perlu ubah apa saja. " archive.is/QtSuj#selection-933.34-933.100 adalah Anda mungkin perlu membuat perubahan pada kode Anda untuk mengakomodasi beberapa ketidakcocokan. Saya telah mencatat empat yang saya ketahui dalam masalah github proyek. github.com/monkeysuffrage/advanced_html_dom/issues
ChrisJJ
Bekerja ! Terima kasih
Faisal Shani
18

Untuk HTML5 , lib html5 telah ditinggalkan selama bertahun-tahun sekarang. Satu-satunya perpustakaan HTML5 yang dapat saya temukan dengan catatan pembaruan dan pemeliharaan terbaru adalah html5-php yang baru saja dibawa ke beta 1.0 lebih dari seminggu yang lalu.

Reid Johnson
sumber
17

Saya telah menulis parser XML tujuan umum yang dapat dengan mudah menangani file GB. Ini didasarkan pada XMLReader dan sangat mudah digunakan:

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

Inilah repo github: XmlExtractor

Paul Warelis
sumber
17

Saya membuat perpustakaan bernama PHPPowertools / DOM-Query , yang memungkinkan Anda untuk menjelajah dokumen HTML5 dan XML sama seperti yang Anda lakukan dengan jQuery.

Di bawah tenda, ia menggunakan symfony / DomCrawler untuk konversi pemilih CSS ke pemilih XPath . Itu selalu menggunakan DomDocument yang sama, bahkan ketika melewati satu objek ke objek lain, untuk memastikan kinerja yang baik.


Contoh penggunaan:

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>');

[...]

Metode yang didukung:


  1. Berganti nama menjadi 'pilih', untuk alasan yang jelas
  2. Berganti nama menjadi 'void', karena 'kosong' adalah kata yang disediakan di PHP

CATATAN :

Perpustakaan juga menyertakan autoloader konfigurasi-nol sendiri untuk pustaka yang kompatibel dengan PSR-0. Contoh yang disertakan harus bekerja di luar kotak tanpa konfigurasi tambahan. Atau, Anda dapat menggunakannya dengan komposer.

John Slegers
sumber
Sepertinya alat yang tepat untuk pekerjaan itu tetapi tidak memuat untuk saya di PHP 5.6.23 di Worpress. Adakah petunjuk tambahan tentang cara memasukkannya dengan benar? Termasuk dengan: define ("BASE_PATH", dirname ( FILE )); define ("LIBRARY_PATH", BASE_PATH. DIRECTORY_SEPARATOR. 'lib / vendor'); membutuhkan LIBRARY_PATH. DIRECTORY_SEPARATOR. 'Loader.php'; Loader :: init (array (LIBRARY_PATH, USER_PATH)); di functions.php
lithiumlab
15

Anda dapat mencoba menggunakan sesuatu seperti Tidy HTML untuk membersihkan HTML "rusak" dan mengonversi HTML ke XHTML, yang kemudian dapat diurai dengan parser XML.

CesarB
sumber
15

Opsi lain yang dapat Anda coba adalah QueryPath . Ini terinspirasi oleh jQuery, tetapi di server dalam PHP dan digunakan di Drupal .

Ric
sumber
12

XML_HTMLSaxagak stabil - bahkan jika itu tidak dipertahankan lagi. Opsi lain bisa mem- pipe HTML Anda melalui Html Tidy dan kemudian menguraikannya dengan alat XML standar.

troelskn
sumber
11

The Symfony framework memiliki bundel yang dapat mengurai HTML, dan Anda dapat menggunakan CSS style untuk memilih DOM daripada menggunakan XPath .

Tuong Le
sumber
11

Ada banyak cara untuk memproses HTML / XML DOM yang sebagian besar telah disebutkan. Karenanya, saya tidak akan membuat upaya untuk membuat daftar sendiri.

Saya hanya ingin menambahkan bahwa saya pribadi lebih suka menggunakan ekstensi DOM dan mengapa:

  • iit memanfaatkan secara optimal keunggulan kinerja kode C yang mendasarinya
  • itu OO PHP (dan memungkinkan saya untuk subkelasnya)
  • tingkatnya agak rendah (yang memungkinkan saya menggunakannya sebagai fondasi yang tidak kembung untuk perilaku yang lebih maju)
  • ini menyediakan akses ke setiap bagian DOM (tidak seperti misalnya. SimpleXml, yang mengabaikan beberapa fitur XML yang kurang dikenal)
  • ini memiliki sintaks yang digunakan untuk perayapan DOM yang mirip dengan sintaks yang digunakan dalam Javascript asli.

Dan sementara saya kehilangan kemampuan untuk menggunakan penyeleksi CSS DOMDocument, ada cara yang agak sederhana dan nyaman untuk menambahkan fitur ini: subkelas DOMDocumentdan menambahkan JS-like querySelectorAlldan querySelectormetode untuk subkelas Anda.

Untuk mem-parsing pemilih, saya sarankan menggunakan komponen CssSelector yang sangat minimalis dari kerangka kerja Symfony . Komponen ini hanya menerjemahkan pemilih CSS ke pemilih XPath, yang kemudian dapat dimasukkan ke dalamDOMXpath untuk mengambil Nodelist yang sesuai.

Anda kemudian dapat menggunakan subkelas (tingkat masih sangat rendah) ini sebagai dasar untuk kelas tingkat lebih tinggi, dimaksudkan untuk misalnya. parsing tipe XML yang sangat spesifik atau tambahkan lebih banyak perilaku seperti jQuery.

Kode di bawah ini langsung keluar dari perpustakaan DOM-Query saya dan menggunakan teknik yang saya jelaskan.

Untuk parsing HTML:

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);
                }
            }
        }
    }

    [...]
}

Lihat juga Parsing dokumen XML dengan penyeleksi CSS oleh pembuat Symfony Fabien Potencier tentang keputusannya untuk membuat komponen CssSelector untuk Symfony dan bagaimana menggunakannya.

John Slegers
sumber
9

Dengan FluidXML Anda dapat meminta dan mengulangi XML menggunakan XPath dan CSS Selectors .

$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

Daniele Orlando
sumber
7

JSON dan array dari XML dalam tiga baris:

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

Ta da!

Antonio Max
sumber
7

Ada beberapa alasan untuk tidak mem-parsing HTML dengan ekspresi reguler. Tetapi, jika Anda memiliki kontrol total terhadap HTML apa yang akan dihasilkan, maka Anda dapat melakukannya dengan ekspresi reguler sederhana.

Di atas itu adalah fungsi yang mem-parsing HTML dengan ekspresi reguler. Perhatikan bahwa fungsi ini sangat sensitif dan menuntut agar HTML mematuhi aturan tertentu, tetapi berfungsi dengan baik di banyak skenario. Jika Anda ingin parser sederhana, dan tidak ingin menginstal pustaka, coba ini:

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/")));
Daniel Loureiro
sumber
2

Saya telah membuat perpustakaan bernama HTML5DOMDocument yang tersedia secara bebas di https://github.com/ivopetkov/html5-dom-document-php

Ini mendukung penyeleksi permintaan juga yang saya pikir akan sangat membantu dalam kasus Anda. Berikut ini beberapa contoh kode:

$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;
Ivo Petkov
sumber
0

Jika Anda terbiasa dengan pemilih jQuery, Anda dapat menggunakan ScarletsQuery untuk PHP

<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);

Perpustakaan ini biasanya membutuhkan waktu kurang dari 1 detik untuk memproses html offline.
Ini juga menerima HTML yang tidak valid atau kutipan yang hilang pada atribut tag.

StefansArya
sumber
0

Metode terbaik untuk parse xml:

$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;
}
pengguna8031209
sumber