[英]PHP - Parse html to retrieve href from an “a” tag that is inside an other “a” tag
我一直在搜索數小時(不應有任何重復),並嘗試使用正則表達式(正則表達式)和DOMdocument的許多不同方式,但均未成功。
非標准html代碼的外觀如下:
<a class="SOMECLASS" href="javascript:__FUNCTION(SOME_HREF_INSIDE)" onclick="SOME_JS_FUNCTION();" id="SOME_ID" style="SOME_STYLE">
<a href="SOME_URL_3">SOME TEXT</a>
</a>
現在的問題是我正在嘗試獲取URL“ SOME_URL_3”,並且在使用正則表達式或DOMdocument進行解析時,一旦遇到第一個href,粘貼就會停止。 當然,由於第二個“ a”標記是第一個標記的一部分,因此解析器只會將其視為一個標記。
我觀察到,瀏覽器似乎在解析時會自動將標簽分開,如下所示:
之前:
<a href="SOME_URL">
<a href="SOME_URL_2">
</a>
</a>
后:
<a href="SOME_URL">
</a>
<a href="SOME_URL_2">
</a>
我無法使用php復制此瀏覽器的行為。
我嘗試過的東西更接近工作:
$dom = new DOMDocument();
@$dom->loadHTML($result);
foreach($dom->getElementsByTagName('a') as $link) {
$href_count = 0;
$attrs = array();
for ($i = 0; $i < $link->attributes->length; ++$i) {
$node = $link->attributes->item($i);
if ($node->nodeName == "href") {
$attrs[$node->nodeName][$href_count] = $node->nodeValue;
$href_count++;
if ($href_count >= 2) {
echo "A second href has been found";
}
}
}
echo "<pre>";
var_dump($attrs);
echo "</pre>";
}
如您所料,不幸的是它不起作用,在那種情況下,我不會在這里尋求幫助...
請不要猶豫,分享您的知識,任何幫助或建議將不勝感激!
我忘記在最初的問題中指定答案仍應允許捕獲標准href。 我的目標是“擴展”或“改進”我的實際html解析器,以確保我也從任何href中檢索了這些url。 我的初始代碼僅使用RegEx,但無法從嵌套的“ a”標簽捕獲第二個href。 一個完美的答案將允許捕獲嵌套的和標准的href。 布蘭登·懷特(Brandon White)的解決方案僅適用於嵌套href,但是使用兩個不同的RegEx(嵌套/標准)將整個html內容解析兩次會很費資源。 理想的解決方案是RegEx,如果可能的話,它可以同時捕獲兩者。
實際上,您可以使用一些精美的RegEx來完成您要問的事情。 使用負前瞻和某些邏輯,您實際上可以完全提取嵌套的href位置。
$result = <<<HTML
<a href="SOME_URL">
<a href="SOME_URL_2">
</a>
</a>
<a href="SOME_URL3">
<a href="SOME_URL_4">
</a>
</a>
<a href="SOME_URL5">
</a>
<a href="SOME_URL_6">
</a>
HTML;
preg_match_all('/<a.*>(?!<\/a>)\s*<a.*href\s*=\s*"(.+)"/', $result, $matches);
var_dump($matches);
在這些棘手的情況下,RegEx非常方便。 值得慶幸的是,您不需要上面所嘗試的所有邏輯。 您需要的只是RegEx的一些邏輯和知識。 我一直推薦的網站是RegExr 。 分析和構建正常運行的RegEx非常有用。 實際上,這里是RegEx“提琴”的示例。
<a.*>
這與任何第一個錨標記匹配 (?!<\\/a>)
這是一個否定的超前行為 -它檢查以確保后面沒有結束的錨標記。 這確保它是嵌套的錨匹配。 \\s*
匹配兩個錨點之間任何可能的空格。 <a.*href\\s*=\\s*"(.+)"
與第二個錨標記匹配,在href屬性和=
和值之間使用任何可能的空格寫入。 同樣, (.+)
將URL放入捕獲組 。 使用preg_match_all()
函數,它將是$match
數組中的第二行。 請參閱下面的示例輸出。 我已經可以使用以下解決方案實現目標:
$result = <<<HTML
<a href="SOME_URL">
<a href="SOME_URL_2">
</a>
</a>
<a href="SOME_URL3">
<a href="SOME_URL_4">
</a>
</a>
<a href="SOME_URL_5">
</a>
<a href="SOME_URL_6">
</a>
HTML;
$dom = new DOMDocument();
@$dom->loadHTML($result);
foreach($dom->getElementsByTagName('a') as $link) {
$tag_html = $dom->saveHTML($link); //Get tag inner html
if (substr_count($tag_html, "href") > 1) { //If tag contains more than one href attribute
preg_match_all('/href="([^"]*)"/is', $tag_html, $link_output, PREG_SET_ORDER);
$output[] = $link_output[1][1]; //Output second href
} else { //Not nested tag
$output[] = $link->getAttribute('href'); //Output first href
}
}
echo "<pre>".print_r($output)."</pre>";
輸出:
array
(
[0] => SOME_URL_2
[1] => SOME_URL_4
[2] => SOME_URL_5
[3] => SOME_URL_6
)
該解決方案適用於具有混合和/或嵌套內容的整個html頁面。 它允許捕獲所需數量的嵌套href,同時仍捕獲標准href“ a”標簽。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.