本文整理一個基於 **CodeIgniter 3** 框架的網頁爬蟲控制器,目標站點為某二手車新聞列表頁。功能涵蓋:分頁列表遍歷、詳情頁解析、圖片下載與本地化替換、資料入庫。程式碼經過重構註解,適合作為 CI 爬蟲開發參考範本。
benchmark->mark('code_start');
// 1. 遍歷 4 個新聞分類
for ($i = 1; $i <= 4; $i++) {
$url = 'https://news.2sche.cn/list.asp?stype=' . $i;
$result = $this->curl_snatch($url);
// 2. 解析總頁數
preg_match_all('/\d\/(.*?)<\/strong>/', $result, $page_news);
$total_pages = isset($page_news[1][0]) ? (int)$page_news[1][0] : 1;
// 3. 遍歷每一分頁
for ($j = 1; $j <= $total_pages; $j++) {
$url_news = ($j == 1)
? 'https://news.2sche.cn/list.asp?stype=' . $i
: 'https://news.2sche.cn/list.asp?page=' . $j . '&stype=' . $i;
$result_news = $this->curl_snatch($url_news);
// 4. 提取列表頁每篇新聞連結
preg_match_all(
'/.*?<\/a><\/td>/sim',
$result_news,
$url_newslist
);
foreach ($url_newslist[1] as $url_newslists) {
$url_newsinfo = 'https://news.2sche.cn/' . $url_newslists;
$result_newsinfo = $this->curl_snatch($url_newsinfo);
// 5. 解析詳情頁欄位
preg_match_all('/(.*?)<\/strong><\/h3>/sim', $result_newsinfo, $title);
preg_match_all('/【來源:(.*?) 】<\/span><\/td>/sim', $result_newsinfo, $source);
preg_match_all('/ (.*?)<\/td>/sim', $result_newsinfo, $content);
// 6. 提取內容區塊圖片
preg_match_all('//sim', $content[1][0], $img);
$picture = '';
foreach ($img[1] as $imgs) {
// 僅處理完整 HTTP 連結
if (strpos($imgs, 'https://') === false) continue;
$img_source = file_get_contents($imgs);
$img_name = trim(strrchr($imgs, '/'), '/');
// 7. 圖片本地化儲存
$save_path = "./static/uploads/news/" . $img_name;
file_put_contents($save_path, $img_source);
// 8. 內容中圖片連結替換為本地路徑
$local_path = '/static/uploads/news/' . $img_name;
$content[1][0] = str_replace($imgs, $local_path, $content[1][0]);
$picture .= $img_name . ':'; // 以冒號分隔多圖
}
// 9. 組裝資料入庫
$data = [
'title' => $title[1][0] ?? '',
'source' => $source[1][0] ?? '',
'contents' => trim($content[1][0] ?? ''),
'picture' => $picture,
'style' => $i,
'create_time' => time(),
];
if (!$this->News_model->add($data)) {
continue; // 入庫失敗跳過
}
}
echo '
';
}
}
$this->benchmark->mark('code_end');
echo $this->benchmark->elapsed_time('code_start', 'code_end');
}
// 通用 cURL 封裝:支援 GBK 轉 UTF-8、自動追蹤重導向
private function curl_snatch($url = 'https://www.2sche.cn/buy.asp') {
$url = trim($url);
$content = '';
if (extension_loaded('curl')) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
$content = iconv("GBK", "UTF-8", $output);
if ($output === FALSE) {
log_message('error', "cURL Error: " . curl_error($ch));
}
curl_close($ch);
} else {
$content = file_get_contents($url);
}
return trim($content);
}
}
關鍵技術點解析
1. 正則表達式精準提取
- 使用
sim 修飾符:s (單行模式讓 . 匹配換行)、i (忽略大小寫)、m (多行模式)。
- 列表頁連結、標題、來源、內容區塊均針對目標站點 HTML 結構定製,需配合瀏覽器開發者工具調試。
2. 圖片本地化流程
- 從內容 HTML 提取所有
<IMG src="..."> 連結。
- 過濾相對路徑/非 HTTP 連結。
file_get_contents 下載二進制內容。
- 取 URL 最後路徑段作為檔名(
strrchr($url, '/'))。
file_put_contents 寫入 ./static/uploads/news/ 目錄(需可寫權限)。
str_replace 將內容中原始圖片 URL 替換為本地相對路徑。
3. 編碼轉換處理
目標站點為 GBK 編碼,CI 內部通常用 UTF-8,iconv("GBK", "UTF-8", $output) 確保中文不亂碼。若 iconv 失敗可嘗試 mb_convert_encoding。
4. 錯誤容忍與效能
set_time_limit(0) 防止長時間爬取被截斷。
- 單篇入庫失敗
continue 不中斷整體流程。
- 建議加入
sleep(1) 或 Token Bucket 限流,避免對目標站點造成過大壓力。
資料庫模型建議
// application/models/News_model.php
class News_model extends CI_Model {
public function add($data) {
return $this->db->insert('news', $data);
}
}
資料表結構:
CREATE TABLE `news` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`source` varchar(100) DEFAULT '',
`contents` longtext,
`picture` varchar(500) DEFAULT '',
`style` tinyint(3) DEFAULT '0',
`create_time` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
進階優化方向
- 併發爬取: 引入
GuzzleHttp\Pool 或 Swoole 協程並發請求詳情頁。
- 斷點續爬: 記錄已爬取 URL 的 MD5 或 ID,支援中斷恢復。
- 反爬應對: 隨機 User-Agent、代理 IP 池、Cookies 池、驗證碼識別。
- 通用化抽取: 結合
DOMDocument / QueryList / Symfony DomCrawler 替代脆弱正則。
- 單元測試: 對
curl_snatch、解析邏輯編寫 PHPUnit 測試。
總結
這個 CI 爬蟲範例展示了從列表分頁、詳情解析、圖片本地化到入庫的完整閉環。實際專案中,請務必遵守 robots.txt、控制爬取頻率、處理異常編碼,並優先考慮使用成熟爬蟲框架(如 Scrapy、Guzzle+DOMCrawler)提升穩定性與可維護性。
- 上一篇文章: C語言文件操作全集:fopen/fread/fwrite/fseek/ftell/rewind 完整 API 詳解與實戰模式
- 下一篇文章: Windows HTTP 協議編程實戰:WinInet API 實現圖片下載完整示例
Copyright © 程式碼之家 All Rights Reserved