public function snatch() {
set_time_limit(0);
$this->benchmark->mark('code_start');
// 遍歷 4 個新聞分類
for ($i = 1; $i <= 4; $i++) {
$url = 'https://news.2sche.cn/list.asp?stype=' . $i;
$result = $this->curl_snatch($url);
// 獲取總頁數
preg_match_all('/\d\/(.*?)<\/strong>/', $result, $page_news);
$total_pages = $page_news[1][0];
// 遍歷分頁
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);
// 提取列表頁文章鏈接
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);
// 提取標題
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
);
// 提取並下載圖片
preg_match_all('//sim', $content[1][0], $img);
$picture = '';
foreach ($img[1] as $imgs) {
if (strpos($imgs, 'https://') === false) continue; // 過濾相對路徑
$img_source = file_get_contents($imgs);
$img_names = trim(strrchr($imgs, '/'), '/');
$picture .= $img_names . ':';
file_put_contents("./static/uploads/news/" . $img_names, $img_source);
// 替換正文中的圖片路徑
$img_path = '/static/uploads/news/' . $img_names;
$content[1][0] = str_replace($imgs, $img_path, $content[1][0]);
}
// 入庫
$data = array(
'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 封裝
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) {
echo "cURL Error: " . curl_error($ch);
}
curl_close($ch);
} else {
$content = file_get_contents($url); // 降級方案
}
return trim($content);
}
關鍵技術點總結
環節 處理方案
編碼轉換 GBK → UTF-8 (iconv)
分頁處理 正則提取總頁數 + URL 拼接
圖片下載 file_get_contents + file_put_contents 本地化
路徑替換 str_replace 將遠程圖片 URL 替換為本地相對路徑
異常容錯 入庫失敗 continue、非 HTTP 圖片跳過
改進建議
- 使用
DOMDocument 或 QueryList 替代正則,健壯性更強
- 添加請求間隔
usleep() 避免被封 IP
- 圖片下載改用 cURL 支持大文件、超時控制
- 引入隊列系統(如 Redis + Worker)實現異步爬取
- 添加 User-Agent 池、代理 IP 池應對反爬
- 上一篇文章: Windows WinInet 實現 HTTP 文件下載:從請求發起到文件保存完整示例
- 下一篇文章: C語言文件操作函數大全:fopen/fread/fwrite/fseek 等核心 API 深度解析
Copyright © 程式碼之家 All Rights Reserved