À partir d'un file_get_contents
, j'obtiens le code HTML d'une URL.
preg_match_all('/class=\"four-column mosaicElement\"><a href=\"(.+?)\" title=\"(.+?)"/m', $html, $urls, PREG_SET_ORDER, 0); foreach ($urls as $key => $url) { echo $url[1]; }
Maintenant, je voudrais capturer le lien href
.
Le code HTML est:
<li class="four-column mosaicElement"> <a href="https://example.com" title="Lorem ipsum"> ... </a> </li> <li class="four-column mosaicElement"> <a href="https://example.org" title="Lorem ipsum"> ... </a> </li>
J'utilise donc ceci:
$html = file_get_contents($url);
Comment puis-je résoudre ce problème?
3 Réponses :
J'ai pu faire fonctionner votre code en modifiant simplement le modèle de regex comme suit:
https://example.com https://example.org
Notez attentivement que j'autorise toute quantité d'espace entre la classe code> de la balise externe (
) et de l'ancre interne.
Voici votre script mis à jour:
$html = "<li class=\"four-column mosaicElement\">\n<a href=\"https://example.com\" title=\"Lorem ipsum\">\n</a>\n</li>\n<li class=\"four-column mosaicElement\">\n<a href=\"https://example.org\" title=\"Lorem ipsum\">\n</a>\n</li>"; preg_match_all('/class="four-column mosaicElement">\s*<a href="(.+?)" title="(.+?)"/m', $html, $urls, PREG_SET_ORDER, 0); foreach ($urls as $key => $url) { echo $url[1] . "\n"; }
Ceci imprime:
class="four-column mosaicElement">\s*<a href="(.+?)" title="(.+?)" ^^^^^
Une autre option consiste à utiliser DOMXPath avec une expression xpath qui trouve tous les éléments de la liste avec les deux noms de classe, puis obtient les ancres:
https://example.com https://example.org
Par exemple:
$string = <<<DATA <li class="four-column mosaicElement"> <a href="https://example.com" title="Lorem ipsum"> </a> </li> <li class="four-column mosaicElement"> <a href="https://example.org" title="Lorem ipsum"> </a> </li> DATA; $dom = new DOMDocument(); $dom->loadHTML($string); $xpath = new DOMXpath($dom); foreach($xpath->query("//li[contains(@class, 'four-column') and contains(@class, 'mosaicElement')]/a") as $v) { echo $v->getAttribute("href") . PHP_EOL; }
Résultat
//li[contains(@class, 'four-column') and contains(@class, 'mosaicElement')]/a
Voir une démo php
Ici, nous pouvons également utiliser une expression avec une anticipation positive et des espaces optionnels, juste au cas où
https://example.com https://example.org https://example.org https://example.org
et les URL souhaitées sont dans ce groupe:
$re = '/(?=class="four-column mosaicElement")[\s\S]*?href="\s*(https?[^\s]+)\s*"/m'; $str = '<li class="four-column mosaicElement"> <a href="https://example.com" title="Lorem ipsum"> ... </a> </li> <li class="four-column mosaicElement"> <a href="https://example.org" title="Lorem ipsum"> <li class="four-column mosaicElement"> <a href=" https://example.org " title="Lorem ipsum"> <li class="four-column mosaicElement"> <a href=" https://example.org " title="Lorem ipsum"> ... </a> </li> '; preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0); foreach ($matches as $key => $url) { echo $url[1] . "\n"; }
(https?[^\s]+)
(?=class="four-column mosaicElement")[\s\S]*?href="\s*(https?[^\s]+)\s*"
jex.im visualise les expressions régulières:
Je pense que vous devriez ajouter une nouvelle ligne
\ n
ou\ R
aprèsclass = \ "quatre colonnes mosaicElement \"> \ R
. regex101.com/r/GtBZfG/1 Pourquoi ne pas utiliser DOMDocument à la place?