Dari blogging sampai log analysis dan search engine optimization (SEO) orang mencari script yang bisa mengurai halaman web dan RSS feed dari situs-situs lain - untuk melihat kemana lalu lintasnya berasal dari antara lain.
Parsing HTML Anda sendiri seharusnya tidak masalah - dengan asumsi Anda menggunakan format yang konsisten - tapi begitu Anda menetapkan pandangan Anda untuk mengurai HTML orang lain, frustrasi benar-benar terjadi. Halaman ini menyajikan beberapa ekspresi reguler dan sebuah komentar yang diharapkan akan mengarahkan Anda ke sisi yang benar. arah.

1. Kasus yang paling sederhana

Mari kita mulai dengan kasus yang paling sederhana - link yang diformat dengan baik tanpa atribut tambahan:
/<a href=\"([^\"]*)\">(.*)<\/a>/iU
Ini, percaya atau tidak, adalah ekspresi reguler yang sangat sederhana (atau "regexp" singkatnya). Hal ini dapat dipecah sebagai berikut:

  • Dimulai dengan: <a href="
  • Serangkaian karakter sampai, tapi tidak termasuk, kutipan ganda berikutnya (") - tangkapan 1
  • String: ">
  • Serangkaian karakter apapun - ambil ke 2
  • Diakhiri dengan: </a>

Kami juga menggunakan dua 'pengubah pola':

  • I - pertandingan 'tidak beralasan' (huruf besar atau kecil tidak masalah)
  • U - pertandingan 'ungreedy'

Pengubah pertama berarti bahwa kita cocok <A> dan juga <a>.Pengubah 'ungreedy' diperlukan karena jika tidak, string yang ditangkap kedua bisa (dengan menjadi 'serakah') meluas dari isi satu tautan sampai akhir tautan lainnya.
Salah satu kekurangan regexp ini adalah tidak mencocokkan tag tautan yang menyertakan jeda baris - untungnya ada modifer untuk ini juga:
/<a\shref=\"([^\"]*)\">(.*)<\/a>/siU
Sekarang '.' Karakter akan cocok dengan karakter apapun termasuk jeda baris. Kami juga telah mengubah ruang pertama menjadi tipe karakter 'spasi' sehingga bisa cocok dengan spasi, tab atau jeda baris. Ini perlu memiliki semacam spasi pada posisi itu sehingga kami tidak cocok dengan tag lainnya seperti <area> .
Untuk informasi lebih lanjut tentang pengubah pola lihat tautan di bagian bawah halaman ini.

2. Ruang untuk Atribut Ekstra

Sebagian besar tag tautan berisi lebih banyak daripada sekadar atribut href . Atribut umum lainnya meliputi: rel, target dan title. Mereka dapat muncul sebelum atau sesudah atribut href:
/<a\s[^>]*href=\"([^\"]*)\"[^>]*>(.*)<\/a>/siU
Kami telah menambahkan pola tambahan sebelum dan sesudah atribut href. Mereka akan cocok dengan serangkaian karakter yang TIDAK mengandung simbol > . Selalu lebih baik saat menulis kalimat biasa untuk menentukan karakter mana yang diizinkan dan tidak diijinkan - kecuali dengan menggunakan karakter wildcard ('.').

3. Izinkan untuk Kehilangan Kutipan

Sampai sekarang kami telah mengasumsikan bahwa alamat link akan ditutup dengan tanda kutip ganda. Sayangnya tidak ada yang menegakkan ini sehingga banyak orang hanya meninggalkan mereka. Masalahnya adalah kami mengandalkankutipan untuk berada di sana untuk menunjukkan di mana alamat dimulai dan diakhiri. Tanpa tanda petik kita punya masalah.
Ini akan cukup sederhana (bahkan sepele) untuk menulis regexp kedua, tapi di mana kesenangan saat kita bisa melakukan semuanya dengan satu:
/<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>/siU
Apa yang bisa kukatakan? Ekspresi reguler sangat menyenangkan untuk dilakukan, tapi bila butuh waktu setengah jam untuk menyelesaikan di mana harus menambahkan ekstra ? Anda benar-benar tahu Anda ada di dalam.
Pertama, ada apa dengan ekstra itu ? 'S?
Karena kita menggunakan pengubah U , semua pola dalam regexp default menjadi 'ungreedy'. Menambahkan tambahan ? Setelah ? Atau * membalikkan perilaku itu kembali ke 'serakah' tapi hanya untuk pola sebelumnya. Tanpa ini, untuk alasan yang sulit dijelaskan, ungkapannya gagal. Pada dasarnya apapun berikut href= disamakan dengan ekspresi [^>] * .
Kami telah menambahkan tangkapan ekstra ke regexp yang sesuai dengan kutipan ganda jika ada di sana: (\ "??) Kemudian ada backreference \\ 1 yang sesuai dengan kutipan ganda penutup - jika ada yang terbuka.
Untuk memenuhi tautan tanpa tanda kutip, pola yang cocok dengan alamat tautan itu sendiri telah diubah dari [^ \ "] * menjadi [^ ">] *? . Itu berarti bahwa link tersebut bisa diakhiri dengan tidak hanya sekedar double quote (perilaku sebelumnya) tapi juga spasi atau simbol.
Ini berarti bahwa tautan dengan alamat yang berisi ruang yang tidak terenkripsi tidak lagi dapat ditangkap!

4. Menyempurnakan Regexp

Mengingat sifat WWW, selalu ada kasus dimana ekspresi reguler terpecah. Perubahan kecil pada pola bisa memperbaikinya.

Ruang di sekitar = setelah href:

/<a\s[^>]*href\s*=\s*(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>/siU

Hanya mencocokkan link yang dimulai dengan http:

/<a\s[^>]*href=(\"??)(http[^\" >]*?)\\1[^>]*>(.*)<\/a>/siU

Tanda kutip tunggal di sekitar alamat link:

/<a\s[^>]*href=([\"\']??)([^\" >]*?)\\1[^>]*>(.*)<\/a>/siU
Dan ya, semua modifikasi ini bisa digunakan sekaligus untuk membuat satu super regexp, tapi hasilnya terlalu menyakitkan untuk diperhatikan, jadi saya akan meninggalkannya sebagai latihan.
Catatan: Semua ungkapan di halaman ini telah diuji sampai batas tertentu, namun kesalahan dapat terjadi dalam penulisan ulang jadi mohon laporkan kesalahan yang mungkin Anda temukan saat menerapkan contoh ini.

5. Menggunakan Regular Expression untuk mengurai HTML

Menggunakan default untuk preg_match_all array yang dikembalikan berisi array dari 'capture' pertama, maka array dari capture kedua dan sebagainya. Dengan menangkap berarti pola yang ada di () :
<?PHP // Original PHP code by Chirp Internet: www.chirp.com.au // Please acknowledge use of this code by including this header. $url = "http://www.example.net/somepage.html"; $input = @file_get_contents($url) or die("Could not access file: $url"); $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>"; if(preg_match_all("/$regexp/siU", $input, $matches)) { // $matches[2] = array of link addresses // $matches[3] = array of link text - including HTML code } ?>
Menggunakan PREG_SET_ORDER setiap link yang cocok memiliki array itu sendiri dalam nilai pengembalian:
<?PHP // Original PHP code by Chirp Internet: www.chirp.com.au // Please acknowledge use of this code by including this header. $url = "http://www.example.net/somepage.html"; $input = @file_get_contents($url) or die("Could not access file: $url"); $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>"; if(preg_match_all("/$regexp/siU", $input, $matches, PREG_SET_ORDER)) { foreach($matches as $match) { // $match[2] = link address // $match[3] = link text } } ?>
Jika Anda menemukan kasus di mana kode ini jatuh, beri tahu kami menggunakan tautan Masukan di bawah ini.
Sebelum menggunakan skrip ini atau yang serupa untuk mengambil halaman dari situs-situs lain, kami sarankan Anda membaca artikel terkait tentang pengaturan agen pengguna dan penguraian robots.txt .

6. Pertama memeriksa robots.txt

Seperti disebutkan di atas, sebelum menggunakan script untuk mendownload file Anda harus selalu memeriksa file robots.txt .Di sini kita memanfaatkan fungsi robots_allowed dari artikel yang terhubung di atas untuk menentukan apakah kita diizinkan untuk mengakses file:
<?PHP // Original PHP code by Chirp Internet: www.chirp.com.au // Please acknowledge use of this code by including this header. ini_set('user_agent', 'NameOfAgent (http://www.example.net)'); $url = "http://www.example.net/somepage.html"; if(robots_allowed($url, "NameOfAgent")) { $input = @file_get_contents($url) or die("Could not access file: $url"); $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>"; if(preg_match_all("/$regexp/siU", $input, $matches, PREG_SET_ORDER)) { foreach($matches as $match) { // $match[2] = link address // $match[3] = link text } } } else { die('Access denied by robots.txt'); }?>
Sekarang Anda sedang dalam perjalanan untuk membangun laba-laba web profesional. Jika Anda akan menggunakan ini dalam praktik yang mungkin ingin Anda lihat: caching file robots.txt sehingga tidak didownload setiap saat (a la Slurp);Memeriksa header server dan kode respon server ; Dan menambahkan jeda di antara beberapa permintaan - untuk pemula.

7. Terjemahan

8. Referensi