Chwytanie atrybutu href elementu A.

114

Próbuję znaleźć linki na stronie.

moje wyrażenie regularne to:

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

ale wydaje się, że zawodzi

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

Jak zmienić moje wyrażenie regularne, aby obsługiwało href, które nie jest umieszczone jako pierwsze w tagu?

Bergin
źródło

Odpowiedzi:

208

Niezawodne Regex dla HTML są trudne . Oto jak to zrobić z DOM :

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

Powyższe mogłoby znaleźć i wyprowadzić „zewnętrzny HTML” wszystkich Aelementów w $htmlciągu.

Aby uzyskać wszystkie wartości tekstowe węzła, musisz to zrobić

echo $node->nodeValue; 

Aby sprawdzić, czy hrefatrybut istnieje, możesz to zrobić

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

Aby uzyskać ten hrefatrybut zrobiłbyś

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

Aby zmienić ten hrefatrybut chcesz zrobić

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

Aby usunąć ten hrefatrybut zrobiłbyś

$node->removeAttribute('href'); 

Możesz również zapytać o hrefatrybut bezpośrednio za pomocą 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
}

Zobacz także:

Na marginesie: jestem pewien, że jest to duplikat, a odpowiedź można znaleźć gdzieś tutaj

Gordon
źródło
Niezawodne wyrażenia regularne do analizowania kodu HTML są z natury niemożliwe, nawet jeśli HTML nie jest zwykłym językiem.
Asciiom
19

Zgadzam się z Gordonem, MUSISZ użyć parsera HTML do parsowania HTML. Ale jeśli naprawdę potrzebujesz wyrażenia regularnego, możesz wypróbować ten:

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

Dopasowuje <ana początku łańcucha, a następnie dowolną liczbę dowolnego char (nie chciwy) .*?następnie href=następuje link otoczony albo "albo'

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

Wynik:

array(3) {
  [0]=>
  string(37) "<a title="this" href="that">what?</a>"
  [1]=>
  string(1) """
  [2]=>
  string(4) "that"
}
Toto
źródło
tylko dla informacji: jeśli szukamy w tekście zawierającym wiele elementów, to wyrażenie (. *?) jest błędne
Michał - wereda-net
5

Wzorzec, którego chcesz szukać, byłby wzorcem kotwicy linku, na przykład (coś):

$regex_pattern = "/<a href=\"(.*)\">(.*)<\/a>/";
Alex Pliutau
źródło
1
Co jeśli kotwica ma więcej atrybutów?
funerr
3

dlaczego po prostu nie pasujesz

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

?>

następnie

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

który działa. Właśnie usunąłem pierwsze szelki do chwytania.

Aif
źródło
2
polecam użycie preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res, PREG_SET_ORDER);w celu prawidłowego wyłapania wszystkich wartości href podczas używaniaforeach($res as $key => $val){echo $val[1]}
Ignacio Bustos
3

Dla tych, którzy nadal nie otrzymują rozwiązań bardzo łatwo i szybko przy użyciu SimpleXML

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

To działa dla mnie

Milan Malani
źródło
2

Nie jestem pewien, co próbujesz tutaj zrobić, ale jeśli próbujesz zweryfikować łącze, spójrz na zmienną filter_var () PHP

Jeśli naprawdę potrzebujesz użyć wyrażenia regularnego, wypróbuj to narzędzie, może ono pomóc: http://regex.larsolavtorvik.com/

Adam
źródło
2

Używając Twojego wyrażenia regularnego, zmodyfikowałem go nieco, aby odpowiadał Twoim potrzebom.

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

Osobiście sugeruję użycie parsera HTML

EDYCJA: testowane

Ruel
źródło
używając myregextester.com - przepraszam, nie mogę znaleźć linków
bergin
mówi: BRAK MECZÓW. Sprawdź, czy nie ma kolizji ogranicznika.
Bergin
Czy możesz mi podać tekst do dopasowania? Używam:<a title="this" href="that">what?</a>
Ruel
1

Szybki test: <a\s+[^>]*href=(\"\'??)([^\1]+)(?:\1)>(.*)<\/a>wygląda na to, że pierwszy mecz to „lub”, drugi to wartość „href”, a trzeci to „co?”.

Powodem, dla którego zostawiłem tam pierwsze dopasowanie „/”, jest to, że możesz go użyć do późniejszego odniesienia do niego w celu zamknięcia „/”, więc jest to to samo.

Zobacz przykład na żywo na: http://www.rubular.com/r/jsKyK2b6do

CharlesLeaf
źródło
1
@bergin proszę określić, co nie działa? Dokładną wartość otrzymuję z href w testowym kodzie HTML. Czego spodziewasz się, że to nie zadziała? Widzę, że używasz innej witryny do testowania, tam również pomyślnie otrzymałem wartość „href” z Twojego przykładu. myregextester.com/?r=d966dd6b
CharlesLeaf
0

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

Jest testowany i pobiera cały tag z dowolnego kodu HTML.

Ravi Prakash
źródło
0

Poniższe działa dla mnie i zwraca zarówno tag kotwicy, jak hrefi value.

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

Wielowymiarowa tablica o nazwie $urlszawiera teraz asocjacyjne tablice podrzędne, które są łatwe w użyciu.

Meloman
źródło