Afferrare l'attributo href di un elemento A.


114

Tentativo di trovare i link in una pagina.

la mia regex è:

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

ma sembra fallire

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

Come cambierei la mia regex per gestire href non posizionato per primo nel tag a?

Risposte:


208

Regex affidabile per HTML è difficile . Ecco come farlo con DOM :

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

Quanto sopra troverebbe e produrrebbe l ' "outerHTML" di tutti gli Aelementi nella $htmlstringa.

Per ottenere tutti i valori di testo del nodo, lo fai

echo $node->nodeValue; 

Per verificare se l' hrefattributo esiste puoi farlo

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

Per ottenere l' hrefattributo che faresti

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

Per cambiare l' hrefattributo faresti

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

Per rimuovere l' hrefattributo faresti

$node->removeAttribute('href'); 

È inoltre possibile eseguire una query per l' hrefattributo direttamente con 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
}

Vedi anche:

Nota a margine: sono sicuro che questo sia un duplicato e puoi trovare la risposta da qualche parte qui


Le espressioni regolari affidabili per l'analisi dell'HTML sono intrinsecamente impossibili anche poiché l'HTML non è un linguaggio normale.
Asciiom

19

Sono d'accordo con Gordon, DEVI usare un parser HTML per analizzare l'HTML. Ma se vuoi davvero una regex puoi provare questa:

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

Questo partite <aAgli inizi della stringa, seguita da un numero qualsiasi di qualsiasi carattere (non avidi) .*?poi href=seguito dal link circondati da uno "o'

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

Produzione:

array(3) {
  [0]=>
  string(37) "<a title="this" href="that">what?</a>"
  [1]=>
  string(1) """
  [2]=>
  string(4) "that"
}

solo per info: se cerchiamo in un testo contenente molti elementi rispetto all'espressione (. *?) è sbagliato
Michal - wereda-net

5

Il modello che vuoi cercare sarebbe il modello di ancoraggio del collegamento, come (qualcosa):

$regex_pattern = "/<a href=\"(.*)\">(.*)<\/a>/";

1
E se l'ancora avesse più attributi?
funerr

3

perché non combini

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

?>

poi

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

che funziona. Ho appena rimosso le prime parentesi graffe di cattura.


2
consiglio di utilizzare preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res, PREG_SET_ORDER);per catturare correttamente tutti i valori href nell'usoforeach($res as $key => $val){echo $val[1]}
Ignacio Bustos

3

Per chi ancora non ottiene le soluzioni molto facili e veloci usando SimpleXML

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

Sta funzionando per me


2

Non sono sicuro di cosa stai cercando di fare qui, ma se stai cercando di convalidare il collegamento, guarda il filtro_var () di PHP

Se hai davvero bisogno di usare un'espressione regolare, dai un'occhiata a questo strumento, potrebbe aiutarti: http://regex.larsolavtorvik.com/


2

Usando la tua regex, l'ho modificata un po 'per adattarla alle tue necessità.

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

Personalmente suggerisco di utilizzare un HTML Parser

EDIT: testato


utilizzando myregextester.com - scusa, non trova i link
bergin

dice: NESSUNA PARTITA. VERIFICARE LA COLLISIONE DELIMITER.
bergin

Puoi dirmi per favore il testo da abbinare? Io uso:<a title="this" href="that">what?</a>
Ruel

1

Test rapido: <a\s+[^>]*href=(\"\'??)([^\1]+)(?:\1)>(.*)<\/a>sembra funzionare, con la prima corrispondenza "o", la seconda il valore "href" "quello" e la terza il "cosa?".

Il motivo per cui ho lasciato la prima corrispondenza di "/" è che puoi usarla per reindirizzarla successivamente per la chiusura "/", quindi è lo stesso.

Guarda un esempio dal vivo su: http://www.rubular.com/r/jsKyK2b6do


1
@bergin per favore specifica, cosa non funziona? Ottengo il valore esatto dall'href nel tuo HTML di prova. Cosa ti aspetti che questo non funzioni? Vedo che usi un sito diverso per i test, lì ho anche ottenuto il valore 'href' con successo dal tuo esempio. myregextester.com/?r=d966dd6b
CharlesLeaf

0

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

È testato e recupera tutti i tag da qualsiasi codice html.


0

Il seguente sta lavorando per me e restituisce entrambi hrefe valuedel tag di ancoraggio.

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

L'array multidimensionale chiamato $urlscontiene ora sotto-array associativi facili da usare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.