You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决克隆网站内容时CSS/JS资源路径加载失败的问题

嘿,这个问题我太熟了!之前帮朋友做类似的网站镜像工具时就踩过这个坑——根相对路径的资源会默认指向你的域名www.example.com,而不是目标网站www.google.com,所以肯定加载失败。下面给你几个实用的解决思路,从简单到可靠都有:

方案1:直接替换根路径为目标网站的绝对路径

这是最省心的办法,拿到目标网站的HTML后,把所有以/开头的资源路径(CSS、JS、图片、甚至链接)前面拼接上目标网站的完整域名。

给你改好的代码参考:

$targetDomain = 'https://www.google.com';
$url = $_GET['url'];

if(isset($url) && $url !== '') {
    // 模拟浏览器请求,避免被目标网站反爬拦截
    $opts = [
        'http' => [
            'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\r\n"
        ]
    ];
    $context = stream_context_create($opts);
    $html = file_get_contents($url, false, $context);

    // 替换href和src属性里的根路径
    $pattern = '/(href|src)="\/(.*?)"/i';
    $replacement = '$1="' . $targetDomain . '/$2"';
    $html = preg_replace($pattern, $replacement, $html);
    
    // 处理CSS样式里的url('/xxx.png')这种情况(单引号、双引号、无引号三种情况)
    $html = preg_replace('/url\(\'\/(.*?)\'\)/i', 'url(\'' . $targetDomain . '/$1\')', $html);
    $html = preg_replace('/url\("\/(.*?)"\)/i', 'url("' . $targetDomain . '/$1")', $html);
    $html = preg_replace('/url\(\/(.*?)\)/i', 'url(' . $targetDomain . '/$1)', $html);

    echo $html;
}

这个方案的好处是不用在自己服务器存任何资源,所有资源直接从目标网站加载。不过要注意正则可能会有遗漏,比如某些特殊写法的路径,但大部分场景下足够用了。

方案2:做资源代理,让所有请求走你的域名

如果不想让用户直接请求目标网站(比如怕被反爬封IP,或者想加缓存),可以在你的服务器上写一个代理脚本,把根路径的请求转发到目标网站。

步骤1:先写代理脚本proxy.php:

$targetDomain = 'https://www.google.com';
$resourcePath = $_GET['path'];

// 安全校验,防止恶意请求(比如遍历服务器文件)
if(strpos($resourcePath, '..') !== false || empty($resourcePath)) {
    exit('Invalid resource request');
}

$fullUrl = $targetDomain . '/' . $resourcePath;
// 获取目标资源的响应头,比如Content-Type,保证浏览器能正确解析
$headers = get_headers($fullUrl, 1);
if(isset($headers['Content-Type'])) {
    header('Content-Type: ' . $headers['Content-Type']);
}

// 模拟浏览器请求资源
$opts = [
    'http' => [
        'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\r\n"
    ]
];
$context = stream_context_create($opts);
echo file_get_contents($fullUrl, false, $context);

步骤2:修改主脚本的路径替换逻辑:

$url = $_GET['url'];

if(isset($url) && $url !== '') {
    $opts = [
        'http' => [
            'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\r\n"
        ]
    ];
    $context = stream_context_create($opts);
    $html = file_get_contents($url, false, $context);

    // 把根路径替换成代理脚本的路径
    $pattern = '/(href|src)="\/(.*?)"/i';
    $replacement = '$1="/proxy.php?path=$2"';
    $html = preg_replace($pattern, $replacement, $html);
    
    // 同样处理CSS里的url()
    $html = preg_replace('/url\(\'\/(.*?)\'\)/i', 'url(\'/proxy.php?path=$1\')', $html);
    $html = preg_replace('/url\("\/(.*?)"\)/i', 'url("/proxy.php?path=$1")', $html);
    $html = preg_replace('/url\(\/(.*?)\)/i', 'url(/proxy.php?path=$1)', $html);

    echo $html;
}

这个方案的优势是所有资源请求都走你的域名,避免跨域问题,还能在代理脚本里加缓存逻辑,重复请求的资源不用每次都去目标网站拉取。

方案3:用DOM解析替换路径(最可靠)

如果目标网站的HTML结构比较复杂,正则容易漏替换,那用PHP的DOMDocument来解析HTML会更准确,能精准找到所有带路径的元素和属性。

代码参考:

$targetDomain = 'https://www.google.com';
$url = $_GET['url'];

if(isset($url) && $url !== '') {
    $opts = [
        'http' => [
            'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\r\n"
        ]
    ];
    $context = stream_context_create($opts);
    $html = file_get_contents($url, false, $context);

    // 初始化DOM解析器,忽略HTML语法错误(很多网站的HTML不规范)
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML($html);
    libxml_clear_errors();

    // 处理所有带src和href的元素(img、script、link、a等)
    foreach($dom->getElementsByTagName('*') as $elem) {
        // 替换src属性
        if($elem->hasAttribute('src')) {
            $src = $elem->getAttribute('src');
            // 判断是不是根相对路径(以/开头,但不是//开头的绝对路径)
            if(strpos($src, '/') === 0 && strpos($src, '//') !== 0) {
                $elem->setAttribute('src', $targetDomain . $src);
            }
        }
        // 替换href属性
        if($elem->hasAttribute('href')) {
            $href = $elem->getAttribute('href');
            if(strpos($href, '/') === 0 && strpos($href, '//') !== 0) {
                $elem->setAttribute('href', $targetDomain . $href);
            }
        }
    }

    // 处理style标签里的url()
    foreach($dom->getElementsByTagName('style') as $styleTag) {
        $content = $styleTag->nodeValue;
        $content = preg_replace('/url\(\'\/(.*?)\'\)/i', 'url(\'' . $targetDomain . '/$1\')', $content);
        $content = preg_replace('/url\("\/(.*?)"\)/i', 'url("' . $targetDomain . '/$1")', $content);
        $content = preg_replace('/url\(\/(.*?)\)/i', 'url(' . $targetDomain . '/$1)', $content);
        $styleTag->nodeValue = $content;
    }

    // 处理内联style属性里的url()
    foreach($dom->getElementsByTagName('*') as $elem) {
        if($elem->hasAttribute('style')) {
            $style = $elem->getAttribute('style');
            $style = preg_replace('/url\(\'\/(.*?)\'\)/i', 'url(\'' . $targetDomain . '/$1\')', $style);
            $style = preg_replace('/url\("\/(.*?)"\)/i', 'url("' . $targetDomain . '/$1")', $style);
            $style = preg_replace('/url\(\/(.*?)\)/i', 'url(' . $targetDomain . '/$1)', $style);
            $elem->setAttribute('style', $style);
        }
    }

    echo $dom->saveHTML();
}

这种方式虽然代码多一点,但几乎不会漏替换任何路径,适合复杂的网站。

最后提醒
  • 目标网站可能有反爬机制,一定要加User-Agent模拟浏览器请求,不然很容易被封IP;
  • 如果要克隆大型网站,建议加缓存机制,避免频繁请求目标网站;
  • 注意版权问题,克隆别人的网站可能涉及侵权,一定要确保合法合规。

内容的提问来源于stack exchange,提问作者Sigit Purnomo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:30:00