Mengambil atribut href dari elemen A.

114

Mencoba menemukan tautan pada suatu halaman.

regex saya adalah:

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

tapi sepertinya gagal

<a title="this" href="that">what?</a>

Bagaimana cara mengubah ekspresi reguler saya untuk menangani href yang tidak ditempatkan pertama dalam tag?

bergin
sumber

Jawaban:

208

Regex yang andal untuk HTML itu sulit . Berikut ini cara melakukannya dengan DOM :

$dom = new DOMDocument;
$dom->loadHTML($html);
foreach ($dom->getElementsByTagName('a') as $node) {
    echo $dom->saveHtml($node), PHP_EOL;
}

Di atas akan mencari dan mengeluarkan "outerHTML" dari semua Aelemen di$html string.

Untuk mendapatkan semua nilai teks dari node, Anda melakukannya

echo $node->nodeValue; 

Untuk memeriksa apakah hrefatribut tersebut ada, Anda dapat melakukannya

echo $node->hasAttribute( 'href' );

Untuk mendapatkan yang hrefatribut Anda akan melakukan

echo $node->getAttribute( 'href' );

Untuk mengubah yang hrefatribut Anda akan melakukan

$node->setAttribute('href', 'something else');

Untuk menghapus satu hrefatribut yang akan Anda lakukan

$node->removeAttribute('href'); 

Anda juga dapat menanyakan hrefatribut secara langsung dengan XPath

$dom = new DOMDocument;
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//a/@href');
foreach($nodes as $href) {
    echo $href->nodeValue;                       // echo current attribute value
    $href->nodeValue = 'new value';              // set new attribute value
    $href->parentNode->removeAttribute('href');  // remove attribute
}

Lihat juga:

Di samping itu: Saya yakin ini adalah duplikat dan Anda dapat menemukan jawabannya di suatu tempat di sini

Gordon
sumber
Regex andal untuk parsing HTML secara inheren tidak mungkin dilakukan bahkan karena HTML bukan bahasa biasa.
Asciiom
19

Saya setuju dengan Gordon, Anda HARUS menggunakan pengurai HTML untuk mengurai HTML. Tetapi jika Anda benar-benar menginginkan regex, Anda dapat mencoba yang ini:

/^<a.*?href=(["\'])(.*?)\1.*$/

Ini cocok <adi awal string, diikuti dengan sejumlah karakter apa pun (tidak serakah) .*?lalu href=diikuti dengan tautan yang dikelilingi oleh salah satu "atau'

$str = '<a title="this" href="that">what?</a>';
preg_match('/^<a.*?href=(["\'])(.*?)\1.*$/', $str, $m);
var_dump($m);

Keluaran:

array(3) {
  [0]=>
  string(37) "<a title="this" href="that">what?</a>"
  [1]=>
  string(1) """
  [2]=>
  string(4) "that"
}
Toto
sumber
hanya untuk info: jika kita mencari dalam teks yang mengandung banyak elemen daripada ekspresi (. *?) salah
Michal - wereda-net
5

Pola yang ingin Anda cari adalah pola tautan tautan, seperti (sesuatu):

$regex_pattern = "/<a href=\"(.*)\">(.*)<\/a>/";
Alex Pliutau
sumber
1
Bagaimana jika jangkar memiliki lebih banyak atribut?
funerr
3

kenapa kamu tidak cocok saja

"<a.*?href\s*=\s*['"](.*?)['"]"

<?php

$str = '<a title="this" href="that">what?</a>';

$res = array();

preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res);

var_dump($res);

?>

kemudian

$ php test.php
array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(27) "<a title="this" href="that""
  }
  [1]=>
  array(1) {
    [0]=>
    string(4) "that"
  }
}

yang berhasil. Saya baru saja melepas kawat gigi penangkap pertama.

Aif
sumber
2
saya merekomendasikan untuk menggunakan preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res, PREG_SET_ORDER);untuk menangkap dengan benar semua nilai href dalam menggunakanforeach($res as $key => $val){echo $val[1]}
Ignacio Bustos
3

Untuk orang yang masih belum mendapatkan solusi dengan sangat mudah dan cepat menggunakan SimpleXML

$a = new SimpleXMLElement('<a href="www.something.com">Click here</a>');
echo $a['href']; // will echo www.something.com

Ini bekerja untuk saya

Milan Malani
sumber
2

Saya tidak yakin apa yang Anda coba lakukan di sini, tetapi jika Anda mencoba memvalidasi tautan, lihat filter_var () PHP

Jika Anda benar-benar perlu menggunakan ekspresi reguler, periksa alat ini, ini mungkin membantu: http://regex.larsolavtorvik.com/

Adam
sumber
2

Menggunakan regex Anda, saya memodifikasinya sedikit agar sesuai dengan kebutuhan Anda.

<a.*?href=("|')(.*?)("|').*?>(.*)<\/a>

Saya pribadi menyarankan Anda menggunakan HTML Parser

EDIT: Diuji

Ruel
sumber
menggunakan myregextester.com - maaf, tidak menemukan tautan
bergin
dikatakan: TIDAK ADA PERTANDINGAN. PERIKSA PENGOLAHAN BATAS.
bergin
Bisakah Anda memberi tahu saya teks yang akan dicocokkan? Saya menggunakan:<a title="this" href="that">what?</a>
Ruel
1

Tes cepat: <a\s+[^>]*href=(\"\'??)([^\1]+)(?:\1)>(.*)<\/a> tampaknya berhasil, dengan kecocokan pertama adalah "atau ', yang kedua adalah' nilai 'href' itu ', dan yang ketiga adalah' apa? '.

Alasan saya meninggalkan kecocokan pertama "/ 'di sana adalah karena Anda dapat menggunakannya untuk mereferensikannya nanti untuk penutupan" /' sehingga sama.

Lihat contoh langsung di: http://www.rubular.com/r/jsKyK2b6do

CharlesLeaf
sumber
1
@bergin sebutkan, apa yang tidak berhasil? Saya mendapatkan nilai yang tepat dari href di HTML pengujian Anda. Apa yang Anda harapkan bahwa ini tidak berhasil? Saya melihat Anda menggunakan situs yang berbeda untuk pengujian, di sana saya juga berhasil mendapatkan nilai 'href' dari contoh Anda. myregextester.com/?r=d966dd6b
CharlesLeaf
0

preg_match_all ("/ (] >) (. ?) (</ a) /", $ content, $ impmatches, PREG_SET_ORDER);

Ini diuji dan mengambil semua tag dari kode html apa pun.

Ravi Prakash
sumber
0

Berikut ini bekerja untuk saya dan mengembalikan keduanya hrefdan valuedari tag jangkar.

preg_match_all("'\<a.*?href=\"(.*?)\".*?\>(.*?)\<\/a\>'si", $html, $match);
if($match) {
    foreach($match[0] as $k => $e) {
        $urls[] = array(
            'anchor'    =>  $e,
            'href'      =>  $match[1][$k],
            'value'     =>  $match[2][$k]
        );
    }
}

Array multidimensi yang disebut $urlssekarang berisi sub-array asosiatif yang mudah digunakan.

Meloman
sumber