在處理文章內容提取首圖作為封面時,常會遇到一個棘手問題:內文可能夾雜表情圖片(如百度貼吧表情),若直接抓取第一個 src 屬性,封面極易誤抓為表情圖。此時需透過正則表達式精準過濾,排除特定域名(如 img.baidu.com)的圖片連結。
關鍵在於使用 負向前瞻 (?!pattern),匹配 <img src="... 時,斷言其後不以 https://img.baidu 開頭。以下為完整可執行範例:
<?php
$contents = '<p>疲憊是一種享受,讓我們無暇空虛;坎坷是一種經歷,讓我們真切的理解人生;<br>
忙碌是一種幸福,讓我們沒有時間體會痛苦;奔波是一種快樂,
<br> <img src="https://img.baidu.com/hi/ldw/w_0009.gif" />
<br> <img src="https://img.baidu.com/hi/jx2/j_0020.gif" />
<br> <img src="https://img.baidu.com/hi/jx2/j_0042.gif" />
<br> <img src="https://img.baidu.com/hi/jx2/j_0015.gif" />
<br> <img src="https://www.jb51.net/uploads/image/20140420/13979336569926.jpg" />
<br> <img src="https://www.jb51.net/13979336569926.jpg" />';
// 關鍵正則:排除 https://img.baidu 開頭的 src
preg_match('#<img src="(?!http:\/\/img\.baidu)([^"]+)"#', $contents, $matches);
var_dump($matches);
/* 執行結果:
array (size=2)
0 => string '<img src="https://www.jb51.net/uploads/image/20140420/13979336569926.jpg"' (length=77)
1 => string 'https://www.jb51.net/uploads/image/20140420/13979336569926.jpg' (length=66)
*/
?>
# ... #:使用 # 作為定界符,避免 URL 中的 / 需轉義。(?!http:\/\/img\.baidu):零寬斷言,確保緊隨 src=" 之後的字串不以 https://img.baidu 開頭。注意 . 需轉義為 \.。([^"]+):捕獲組,匹配非雙引號字元一次或多次,即實際圖片 URL。若需同時屏蔽多個表情圖床,可用 | 分隔:
preg_match('#<img src="(?!http:\/\/(img\.baidu|static\.example)\.com)([^"]+)"#', $contents, $matches);
正則處理 HTML 易受標籤屬性順序、換行、單雙引號混用影響。生產環境建議改用 DOMDocument + DOMXPath:
<?php
$dom = new DOMDocument();
@$dom->loadHTML($contents, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
$imgs = $xpath->query('//img[not(starts-with(@src, "https://img.baidu"))]/@src');
foreach ($imgs as $img) {
echo $img->nodeValue . PHP_EOL; // 直接得到乾淨 URL
}
?>
此法更健壯,且可輕鬆擴展條件(如同時檢查 data-src、class 等屬性)。