Abrufen des href-Attributs eines A-Elements

114

Der Versuch, die Links auf einer Seite zu finden.

Mein Regex ist:

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

scheint aber zu scheitern

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

Wie würde ich meinen regulären Ausdruck ändern, um mit href umzugehen, die nicht an erster Stelle im a-Tag stehen?

bergin
quelle

Antworten:

208

Zuverlässiger Regex für HTML ist schwierig . So geht's mit DOM :

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

Das Obige würde das "OuterHTML" aller AElemente in der $htmlZeichenfolge finden und ausgeben .

Um zu erhalten alle Textwerte des Knotens, was Sie tun

echo $node->nodeValue; 

Um zu überprüfen, ob das hrefAttribut vorhanden ist, können Sie dies tun

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

Um zu erhalten das hrefAttribut , das Sie tun würde

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

Um das Attribut zu ändernhref , würden Sie tun

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

Um das Attribut zu entfernenhref , würden Sie tun

$node->removeAttribute('href'); 

Sie können das hrefAttribut auch direkt mit XPath abfragen

$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
}

Siehe auch:

Nebenbei: Ich bin sicher, dass dies ein Duplikat ist und Sie können die Antwort irgendwo hier finden

Gordon
quelle
Zuverlässige Regex zum Parsen von HTML sind von Natur aus unmöglich, auch wenn HTML keine reguläre Sprache ist.
Asciiom
19

Ich stimme Gordon zu, Sie MÜSSEN einen HTML-Parser verwenden, um HTML zu analysieren. Aber wenn Sie wirklich einen regulären Ausdruck wollen, können Sie diesen ausprobieren:

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

Dies passt <azu Beginn der Zeichenkette, gefolgt von einer beliebigen Anzahl von beliebigen char (nicht gierigen) .*?dann href=durch die Verbindung gefolgt durch entweder umgeben "oder'

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

Ausgabe:

array(3) {
  [0]=>
  string(37) "<a title="this" href="that">what?</a>"
  [1]=>
  string(1) """
  [2]=>
  string(4) "that"
}
Toto
quelle
Nur zur Information: Wenn wir in einem Text suchen, der viele Elemente enthält, ist der Ausdruck (. *?) falsch
Michal - wereda-net
5

Das Muster, nach dem Sie suchen möchten, ist das Link-Anker-Muster, wie (etwas):

$regex_pattern = "/<a href=\"(.*)\">(.*)<\/a>/";
Alex Pliutau
quelle
1
Was ist, wenn der Anker mehr Attribute hat?
Funerr
3

Warum passt du nicht einfach zusammen?

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

?>

dann

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

was funktioniert. Ich habe gerade die ersten Erfassungsklammern entfernt.

Aif
quelle
2
Ich empfehle zu verwenden preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res, PREG_SET_ORDER);, um alle href-Werte in usingforeach($res as $key => $val){echo $val[1]}
Ignacio Bustos
3

Für diejenigen, die die Lösungen mit SimpleXML immer noch nicht sehr einfach und schnell erhalten

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

Es funktioniert für mich

Milan Malani
quelle
2

Ich bin nicht sicher, was Sie hier versuchen, aber wenn Sie versuchen, den Link zu validieren, schauen Sie sich PHPs filter_var () an.

Wenn Sie wirklich einen regulären Ausdruck verwenden müssen, schauen Sie sich dieses Tool an. Es kann hilfreich sein: http://regex.larsolavtorvik.com/

Adam
quelle
2

Mit Ihrer Regex habe ich sie ein wenig an Ihre Bedürfnisse angepasst.

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

Ich persönlich schlage vor, Sie verwenden eine HTML-Parser verwenden

EDIT: Getestet

Ruel
quelle
using myregextester.com - Entschuldigung, findet die Links nicht
bergin
es heißt: KEINE SPIELE. PRÜFEN SIE AUF DELIMITER COLLISION.
Berg
Können Sie mir bitte den passenden Text mitteilen? Ich benutze:<a title="this" href="that">what?</a>
Ruel
1

Schnell Test: <a\s+[^>]*href=(\"\'??)([^\1]+)(?:\1)>(.*)<\/a> Scheint den Trick zu machen, wobei das erste Match "oder" ist, das zweite der "href" -Wert "das" und das dritte das "was?".

Der Grund, warum ich das erste Match von "/ 'dort gelassen habe, ist, dass Sie es verwenden können, um es später für das Schließen zurück zu referenzieren" /', also ist es dasselbe.

Siehe Live-Beispiel unter: http://www.rubular.com/r/jsKyK2b6do

CharlesLeaf
quelle
1
@bergin bitte angeben, was funktioniert nicht? Ich erhalte den genauen Wert von der href in Ihrem Test-HTML. Was erwarten Sie, dass dies nicht funktioniert? Ich sehe, dass Sie eine andere Site zum Testen verwenden. Dort erhalte ich auch erfolgreich den Wert 'href' aus Ihrem Beispiel. myregextester.com/?r=d966dd6b
CharlesLeaf
0

preg_match_all ("/ (] >) (. ?) (</ a) /", $ Inhalt, $ Impmatches, PREG_SET_ORDER);

Es wird getestet und ruft alle Tags aus jedem HTML-Code ab.

Ravi Prakash
quelle
0

Das Folgende funktioniert für mich und gibt sowohl hrefals auch valuedas Ankertag zurück.

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

Das aufgerufene mehrdimensionale Array $urlsenthält jetzt assoziative Unterarrays, die einfach zu verwenden sind.

Meloman
quelle