實作原理
fopen() 開啟遠端 URL 串流(需 allow_url_fopen=On)
fread() 循環讀取全部 HTML 內容
- 正則表達式匹配所有
href 屬性值
- 判斷相對/絕對路徑,補全為完整 URL
核心代碼
<?php
$url = isset($_GET['url']) ? $_GET['url'] : "https://www.csdn.net/expert/";
// 解析基礎 URL
$site = substr($url, 0, strpos($url, "/", 8)); // https://domain.com
$base = substr($url, 0, strrpos($url, "/") + 1); // https://domain.com/path/
// 讀取遠端內容
$fp = fopen($url, "r");
$contents = '';
while (!feof($fp)) {
$contents .= fread($fp, 1024);
}
fclose($fp);
// 正則匹配所有 href
$pattern = '|href=["\']?([^"\'>\s]+)["\']?|U';
preg_match_all($pattern, $contents, $matches, PREG_SET_ORDER);
// 處理並輸出
foreach ($matches as $i => $m) {
$link = $m[1];
if (!preg_match('|://|', $link)) { // 相對路徑
if (substr($link, 0, 1) === '/') { // 站內絕對路徑 /path
$link = $site . $link;
} else { // 相對路徑 path/file
$link = $base . $link;
}
}
echo "Link " . ($i+1) . ": $link<br>";
}
?>
正則表達式解析
|href=["\']?([^"\'>\s]+)["\']?|U
| 定界符
href= 字面匹配
["\']? 可選單雙引號
( 捕獲組開始
[^"\'>\s]+ 非引號、非>、非空白字元(連結內容)
) 捕獲組結束
["\']? 可選結尾引號
|U 非貪婪模式
功能擴充建議
| 功能 | 實作方向 |
| 遞迴爬取 | 隊列 + 已訪問集合,限制深度/網域 |
| 過濾資源類型 | 副檔名判斷、Content-Type 檢查 |
| 處理 JS 動態渲染 | Headless Chrome (Puppeteer/PHP-WebDriver) |
| 反爬蟲應對 | User-Agent 偽裝、Cookie 池、IP 代理、延遲請求 |
| robots.txt 遵守 | 解析 robots.txt、檢查 User-agent: * 規則 |
| 編碼自動偵測 | mb_detect_encoding() + iconv() 統一轉 UTF-8 |
| 儲存資料庫 | URL、標題、內容摘要、抓取時間、狀態碼 |
現代化重寫:Guzzle + Symfony DomCrawler
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
$client = new Client(['timeout' => 10, 'headers' => ['User-Agent' => 'Mozilla/5.0']]);
$url = 'https://example.com';
try {
$response = $client->get($url);
$html = $response->getBody()->getContents();
$crawler = new Crawler($html);
$links = $crawler->filter('a[href]')->each(function (Crawler $node) use ($url) {
$href = $node->attr('href');
// 解析相對路徑
$absolute = (parse_url($href, PHP_URL_SCHEME)) ? $href : rtrim($url, '/') . '/' . ltrim($href, '/');
return ['text' => trim($node->text()), 'url' => $absolute];
});
print_r($links);
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
?>
法律與道德提醒
- 遵守目標網站
robots.txt 與服務條款
- 控制抓取頻率(建議 > 1 秒/請求),避免造成服務負擔
- 僅抓取公開資料,勿繞過登入/驗證機制
- 尊重著作權,抓取資料僅供個人研究/分析,不可商業轉售
總結
基於 fopen + 正則的連結提取器構思簡單、零依賴,適合學習 HTTP、正則、URL 解析基礎。生產級爬蟲請採用 Guzzle + DomCrawler 或 Scrapy (Python) 等成熟框架,具備併發、重試、中介軟體、選擇器、管道等企業級能力。
- 上一篇文章: PHP 透過 COM 元件呼叫 ADO 操作 Access 資料庫與 Word 自動化
- 下一篇文章: PHP4 Session O_RDWR 錯誤解決:session.save_path 配置與目錄權限
Copyright ©
程式碼之家 All Rights Reserved