從網頁原始碼提取 Email 地址是常見爬蟲需求。PHP preg_match_all() 搭配適當正則可快速完成。本文提供兩種實用寫法、正則細節解析與反爬蟲應對建議。
<?php
$url = 'https://www.example.com';
$html = @file_get_contents($url);
if ($html === false) {
die("無法取得網頁內容");
}
function extractEmails($content) {
// RFC 5322 簡化版:支援常見格式,含子網域、多層 TLD
$pattern = '/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/i';
preg_match_all($pattern, $content, $matches);
// 去重並排序
return array_unique($matches[0]);
}
$emails = extractEmails($html);
print_r($emails);
?>
若目標頁面 Email 集中在特定區塊(如聯絡我們頁),可先以 DOM 解析鎖定區塊再套用正則,減少誤判。
<?php
$url = 'https://www.example.com/contact';
$html = @file_get_contents($url);
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
// 假設 Email 在 class="contact-info" 區塊
$nodes = $xpath->query('//div[contains(@class,"contact-info")]//text()');
$allText = '';
foreach ($nodes as $node) {
$allText .= $node->nodeValue . ' ';
}
$pattern = '/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/i';
preg_match_all($pattern, $allText, $matches);
$emails = array_unique($matches[0]);
print_r($emails);
?>
/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/i
| 片段 | 說明 |
|---|---|
[a-z0-9._%+-]+ | 本地部:英數字、點、底線、百分號、加號、減號,至少一字元 |
@ | 必須包含單一 @ 符號 |
[a-z0-9.-]+ | 網域部:英數字、點、減號 |
\. | 網域與 TLD 分隔點(跳脫) |
[a-z]{2,} | 頂級域:至少兩字母(com、tw、org、io...) |
i | 大小寫不敏感 |
注意: 此正則為實用簡化版,完整 RFC 5322 規範極其複雜(超過 6000 字元),實務上此版本覆蓋 99%+ 真實 Email。
部分網頁為防爬蟲將 Email 編碼:
user@example.com'user' + '@' + 'example.com'解碼策略:
<?php
function decodeHtmlEntities($text) {
return html_entity_decode($text, ENT_QUOTES, 'UTF-8');
}
// 針對 JS 簡單拼接可嘗試正則還原(僅示例,完整需 JS 引擎)
$text = decodeHtmlEntities($html);
// 移除 script/style 標籤內容避免干擾
$text = preg_replace('/<script.*?>.*?<\/script>/is', '', $text);
$text = preg_replace('/<style.*?>.*?<\/style>/is', '', $text);
?>
/robots.txt 規則。PHP 抓取網頁 Email 核心在於 file_get_contents/cURL 取得內容 → 正則/解析器提取 → 去重。基本正則足應付多數情境,複雜頁面建議搭配 DOMXPath 定位區塊。務必遵守法律道德,善用技術造福而非騷擾。