首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 采集遠程圖片並本地化存儲完整方案

     編輯:PHP 相關知識

業務場景

采集第三方網站內容時,圖片常有防盜鏈限制,直接引用外鏈會顯示失效。需將圖片下載到自有服務器,再替換頁面中的圖片路徑。

核心流程

  1. 解析目標頁面 HTML,提取所有 `` 標籤的 src 屬性
  2. 逐個下載圖片二進制內容
  3. 生成本地存儲路徑(按日期/域名/隨機名分目錄)
  4. 寫入文件,返回本地相對路徑
  5. 替換原 HTML 中的圖片 URL 為本地路徑

基礎工具函數

<?php
/** 確保目錄存在並可寫 */
function ensureDir(string $dir): void {
    if (!is_dir($dir)) {
        mkdir($dir, 0755, true);
        chmod($dir, 0755);
    }
}

/** 讀取遠程/本地文件內容 */
function readFileContent(string $path): string|false {
    $path = trim($path);
    $fp = @fopen($path, 'rb');
    if (!$fp) return false;

    $content = '';
    if (str_contains($path, '://')) { // 遠程流式讀取
        while (!feof($fp)) {
            $content .= fread($fp, 8192);
        }
    } else { // 本地一次性讀取
        $content = fread($fp, filesize($path));
    }
    fclose($fp);
    return $content;
}

/** 寫入文件 */
function writeFile(string $path, string $content): bool {
    $fp = @fopen($path, 'wb');
    if (!$fp) return false;
    fwrite($fp, $content);
    fclose($fp);
    return true;
}

/** 從 URL 解析文件名(含擴展名) */
function parseFilename(string $url): string {
    $parsed = parse_url($url);
    $path = $parsed['path'] ?? '';
    $name = basename($path);
    // 去除查詢參數
    if (($pos = strpos($name, '?')) !== false) {
        $name = substr($name, 0, $pos);
    }
    // 無擴展名時默認 .jpg
    if (!preg_match('/\.(jpg|jpeg|png|gif|webp)$/i', $name)) {
        $name .= '.jpg';
    }
    return $name;
}

主下載函數

/**
 * 下載遠程圖片到本地
 * @param string $url 圖片完整 URL
 * @param string $saveDir 本地存儲根目錄(絕對路徑)
 * @return string|false 成功返回相對路徑,失敗返回 false
 */
function saveRemoteImage(string $url, string $saveDir = 'images/'): string|false {
    $url = trim($url);
    $url = str_replace(' ', '%20', $url); // 處理空格

    $content = readFileContent($url);
    if ($content === false || $content === '') {
        error_log("Failed to fetch: $url");
        return false;
    }

    $filename = parseFilename($url);
    // 防衝突:時間戳 + 隨機數 + 原文件名
    $uniqueName = time() . '_' . mt_rand(1000, 9999) . '_' . $filename;

    // 按日期分目錄
    $dateDir = date('Y/m/d');
    $fullDir = rtrim($saveDir, '/') . '/' . $dateDir;
    ensureDir($fullDir);

    $fullPath = $fullDir . '/' . $uniqueName;
    if (!writeFile($fullPath, $content)) {
        error_log("Failed to write: $fullPath");
        return false;
    }

    // 返回相對 Web 根目錄的路徑
    return ltrim(str_replace($_SERVER['DOCUMENT_ROOT'], '', $fullPath), '/');
}

批量采集頁面圖片

/**
 * 采集頁面所有圖片並本地化
 * @param string $html 頁面 HTML
 * @param string $baseUrl 頁面基礎 URL(用於補全相對路徑)
 * @param string $saveDir 存儲目錄
 * @return string 處理後的 HTML(圖片 src 已替換為本地路徑)
 */
function localizeImages(string $html, string $baseUrl, string $saveDir = 'images/'): string {
    $dom = new DOMDocument();
    @$dom->loadHTML('' . $html); // 抑制警告

    $xpath = new DOMXPath($dom);
    $images = $xpath->query('//img[@src]');

    foreach ($images as $img) {
        $src = $img->getAttribute('src');
        if (empty($src)) continue;

        // 補全相對路徑
        $absoluteUrl = parse_url($src, PHP_URL_SCHEME) ? $src : rtrim($baseUrl, '/') . '/' . ltrim($src, '/');

        $localPath = saveRemoteImage($absoluteUrl, $saveDir);
        if ($localPath) {
            $img->setAttribute('src', $localPath);
            // 可選:保留原始 src 作為 data-original
            $img->setAttribute('data-original', $absoluteUrl);
        }
    }

    // 輸出處理後的 body 內容
    $body = $dom->getElementsByTagName('body')->item(0);
    return $dom->saveHTML($body);
}

實戰示例:采集某新聞站文章圖片

$targetUrl = 'https://example.com/news/123.html';
$html = file_get_contents($targetUrl);

// 1. 提取正文區域(需根據目標站點結構調整選擇器)
$dom = new DOMDocument();
@$dom->loadHTML('' . $html);
$xpath = new DOMXPath($dom);
$contentNode = $xpath->query('//div[@class="article-content"]')->item(0);
if (!$contentNode) exit('Content area not found');

$articleHtml = $dom->saveHTML($contentNode);

// 2. 本地化圖片
$processedHtml = localizeImages($articleHtml, $targetUrl, 'uploads/collected/');

// 3. 入庫或輸出
echo $processedHtml;

進階應對策略

反采集手段應對方案
Referer 檢查curl 設置 CURLOPT_REFERER 為目標頁面 URL
User-Agent 封禁使用真實瀏覽器 UA 池隨機切換
圖片 302 多次跳轉curl 開啟 CURLOPT_FOLLOWLOCATION 並限制最大跳轉次數
Cookie/Session 驗證先登錄獲取 Cookie,攜帶訪問
圖片動態簽名(帶時間戳參數)下載時忽略查詢參數,或模擬簽名算法
IP 限流代理 IP 池輪換,控制請求頻率

法律與道德提醒

  • 遵守目標站點 robots.txt 及服務條款。
  • 僅采集公開、允許轉載的內容,尊重版權。
  • 高頻采集請聯繫站點方申請 API 或授權。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved