方案一:正則非貪婪匹配(簡單、輕量)
$html = '<p class="question-desp">內容一</p><p class="question-desp">內容二</p>';
// 非貪婪 .+? 配合 s 修飾符(讓 . 匹配換行)
preg_match_all('/<p class="question-desp">(.+?)<\/p>/is', $html, $matches);
// $matches[1] = ['內容一', '內容二']
關鍵點
(.+?) 非貪婪:盡可能少匹配,遇到第一個 </p> 即停止。
s (PCRE_DOTALL) 修飾符:讓 . 匹配換行符。
i 修飾符:忽略標籤大小寫。
方案二:DOMDocument 解析器(健壯、標準)
$dom = new DOMDocument();
libxml_use_internal_errors(true); // 抑制 HTML5 非標準警告
$dom->loadHTML('' . $html); // 強制 UTF-8
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//p[@class="question-desp"]');
$contents = [];
foreach ($nodes as $node) {
$contents[] = $node->nodeValue; // 純文本
// $contents[] = $dom->saveHTML($node); // 含標籤 HTML
}
print_r($contents);
比較與選擇指南
| 維度 | 正則 | DOMDocument |
| HTML 結構變動 | 極易失效(屬性順序、換行、巢狀) | 穩健,按樹結構查找 |
| 巢狀標籤 | 難以正確處理 | 原生支援 |
| 編碼/實體 | 手動處理 | 自動解碼實體 |
| 效能 | 極快(短字串) | 較慢(建立樹) |
| 依賴 | 無 | 需 libxml、dom 擴展(通常內建) |
最佳實踐
- 結構固定、一次性腳本、極簡需求 → 正則非貪婪匹配。
- 生產環境、HTML 來源不可控、需提取屬性/巢狀結構 → DOMDocument + XPath。
- 大規模爬蟲 → 考慮
Masterminds/HTML5-PHP (HTML5 解析器) 或 symfony/dom-crawler。