Получение атрибута href элемента A

114

Пытаюсь найти ссылки на странице.

мое регулярное выражение:

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

но, похоже, не справляется

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

Как мне изменить свое регулярное выражение, чтобы иметь дело с href, который не помещается первым в теге?

Bergin
источник

Ответы:

208

Надежное регулярное выражение для HTML сложно . Вот как это сделать с помощью DOM :

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

Вышеупомянутое найдет и выведет "externalHTML" всех Aэлементов в $htmlстроке.

Чтобы получить все текстовые значения узла, выполните

echo $node->nodeValue; 

Чтобы проверить, существует ли hrefатрибут, вы можете сделать

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

Для того, чтобы получить на hrefатрибут , который бы сделать

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

Для того, чтобы изменить на hrefатрибут , который нужно сделать

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

Для того, чтобы удалить с hrefатрибута вы бы сделать

$node->removeAttribute('href'); 

Вы также можете запросить hrefатрибут напрямую с помощью 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
}

Также см:

На полях: я уверен, что это дубликат, и вы можете найти ответ где-то здесь

Гордон
источник
Надежное регулярное выражение для синтаксического анализа HTML по сути невозможно, даже если HTML не является обычным языком.
Asciiom
19

Я согласен с Гордоном, вы ДОЛЖНЫ использовать парсер HTML для синтаксического анализа HTML. Но если вам действительно нужно регулярное выражение, вы можете попробовать это:

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

Это соответствует <aв начале строки, а затем любое количество любого полукокса (не жадные) , .*?то href=затем по ссылке в окружении либо "или'

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

Вывод:

array(3) {
  [0]=>
  string(37) "<a title="this" href="that">what?</a>"
  [1]=>
  string(1) """
  [2]=>
  string(4) "that"
}
Toto
источник
просто для информации: если мы ищем в тексте, содержащем много элементов, выражение (. *?) неверно
Михал - wereda-net
5

Шаблон, который вы хотите найти, будет шаблоном привязки ссылки, например (что-то):

$regex_pattern = "/<a href=\"(.*)\">(.*)<\/a>/";
Алексей Плютау
источник
1
Что, если у якоря больше атрибутов?
funerr
3

почему бы тебе просто не сопоставить

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

?>

затем

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

который работает. Я только что снял первые фиксирующие скобы.

Aif
источник
2
Я рекомендую использовать preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res, PREG_SET_ORDER);, чтобы правильно уловить все значения href в использованииforeach($res as $key => $val){echo $val[1]}
Игнасио Бустос
3

Для тех, кто все еще не получил решения, очень просто и быстро с помощью SimpleXML

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

Это работает для меня

Милан Малани
источник
2

Я не уверен, что вы здесь пытаетесь сделать, но если вы пытаетесь проверить ссылку, посмотрите на PHP filter_var ()

Если вам действительно нужно использовать регулярное выражение, попробуйте этот инструмент, он может помочь: http://regex.larsolavtorvik.com/

Адам
источник
2

Используя ваше регулярное выражение, я немного изменил его в соответствии с вашими потребностями.

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

Я лично предлагаю вам использовать парсер HTML

РЕДАКТИРОВАТЬ: проверено

Ruel
источник
с помощью myregextester.com - извините, не нашел ссылки
бергин
он говорит: НЕТ МАТЧЕЙ. ПРОВЕРИТЬ НАЛИЧИЕ СТОЛКНОВЕНИЯ РАЗДЕЛИТЕЛЯ
bergin
Подскажите, пожалуйста, текст для соответствия? Я использую:<a title="this" href="that">what?</a>
Ruel
1

Быстрый тест: <a\s+[^>]*href=(\"\'??)([^\1]+)(?:\1)>(.*)<\/a>похоже, помогает: первое совпадение - "or", второе - значение href - "that", а третье - "что?".

Причина, по которой я оставил первое совпадение "/" там, заключается в том, что вы можете использовать его для обратной ссылки позже для закрытия "/ ', так что это то же самое.

См. Живой пример на: http://www.rubular.com/r/jsKyK2b6do

CharlesLeaf
источник
1
@bergin уточните, что не работает? Я получаю точное значение из href в вашем тестовом HTML. Что вы ожидаете, что этого не произойдет? Я вижу, что вы используете другой сайт для тестирования, там я также успешно получил значение «href» из вашего примера. myregextester.com/?r=d966dd6b
CharlesLeaf,
0

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

Он протестирован и извлекает все теги из любого html-кода.

Рави Пракаш
источник
0

Далее работает для меня , и возвращается как hrefи 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]
        );
    }
}

Вызываемый многомерный массив $urlsтеперь содержит ассоциативные подмассивы, которые легко использовать.

Meloman
источник