簡體   English   中英

PHP-解析html以從另一個“ a”標簽內的“ a”標簽檢索href

[英]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數組中的第二行。 請參閱下面的示例輸出。
  • 還要注意,它不會像上面的代碼示例中那樣提取非嵌套的URL。

代碼輸出

上面代碼示例的輸出

我已經可以使用以下解決方案實現目標:

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM