海洋 CMS 远程图片本地化怎么批量处理
海洋 CMS 的远程图片本地化只有两条路:还没入库的内容,在采集节点的保存设置里把「图片本地化 / 下载远程图片」打开,采集的同时就落地到本地;已经入库的旧文章,后台没有一键批量按钮,只能自己写脚本按批次刷一遍数据库里的正文 HTML。**结论:能改采集规则就别事后补救,必须补的时候用 PHP 脚本 + 分批 SQL 处理,一次跑 100 条最稳。**
为什么采集时就开图片本地化,比事后补救省事?
结论:采集阶段开本地化,图片只下载一次;事后补救要把整站正文重新解析、重新下载,工作量和失败率都翻倍。
采集入库时,海洋 CMS 拿到的是目标站的 HTML,图片链接还是对方的域名。这时候打开本地化,程序会边入库边把图下载到 uploads/(或你配置的图片目录)并替换成站内路径,整个过程一次完成。等到文章已经躺在库里几个月,对方站换了域名、删了图、加了防盗链,你再去下载,能救回来的比例就低很多——尤其是图片站、影视站这类采集量大、原站不稳定的场景。
另外一个现实问题是:事后补的时候,你得先确认哪些文章还挂着远程图。用一条 SQL 就能数出来:
SELECT COUNT(*) FROM sea_data WHERE d_content LIKE '%src="http%';
这个数字就是你要处理的总量,跑之前先记下来,跑完再查一次对比。
海洋 CMS 采集节点里怎么开启图片本地化?
结论:入口在采集节点(采集规则)的保存/图片相关设置项里,勾上「下载远程图片」并确认图片保存目录可写。
具体操作顺序是:后台进采集管理,打开你正在用的采集节点,找到保存设置里的图片选项,把远程图片下载开关打开;同时确认服务器上图片目录权限是 755(部分环境用 777),PHP 的 curl 扩展或 allow_url_fopen 至少有一个是开的。配置好后先跑一次采集测试,抓 5 到 10 条,去前台看图片地址是不是已经变成自己域名下的路径。
需要注意两点:一是采集节点如果有多个,每个都要单独设置,改一个不会同步到其它节点;二是新采集的内容才会走本地化,历史数据不受影响,这也是为什么老站必须单独补一遍。
已经入库的文章,怎么用脚本批量本地化?
结论:写一个 PHP CLI 脚本,每轮取 100 条含远程图的记录,正则抓出 <img src>,用 curl 下载到本地目录后替换链接并回写数据库。
核心代码大致如下(表名和字段以你自己库里的实际结构为准,先在 phpMyAdmin 里 DESCRIBE sea_data 确认):
<?php
set_time_limit(0);
ignore_user_abort(true);
$pdo = new PDO('mysql:host=127.0.0.1;dbname=yourdb;charset=utf8mb4','user','pass');
$saveDir = __DIR__.'/uploads/localimg/';
if (!is_dir($saveDir)) mkdir($saveDir, 0755, true);
while (true) {
$rows = $pdo->query("SELECT d_id,d_content FROM sea_data
WHERE d_content LIKE '%<img%http%' LIMIT 100")->fetchAll(PDO::FETCH_ASSOC);
if (!$rows) break;
foreach ($rows as $row) {
$content = $row['d_content'];
preg_match_all('/<img[^>]+src=["\'](https?:\/\/[^"\']+)["\']/i', $content, $m);
foreach ($m[1] as $url) {
$ext = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'jpg';
$name = md5($url).'.'.$ext;
$file = $saveDir.$name;
if (!file_exists($file)) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_REFERER => 'https://你的域名/',
CURLOPT_USERAGENT => 'Mozilla/5.0',
CURLOPT_SSL_VERIFYPEER => false,
]);
$data = curl_exec($ch);
if ($data) file_put_contents($file, $data);
curl_close($ch);
}
$content = str_replace($url, '/uploads/localimg/'.$name, $content);
}
$pdo->prepare("UPDATE sea_data SET d_content=? WHERE d_id=?")->execute([$content, $row['d_id']]);
}
}
这里有个设计上的小技巧:WHERE ... LIKE '%<img%http%' 加上固定的 LIMIT 100(不带 OFFSET),处理完的这条记录链接已经被替换成 /uploads/...,不再匹配条件,下一轮自然取到的是新的 100 条。这样脚本天然幂等,中断了重跑也不会重复处理。
用 php localize.php 在命令行跑,别在浏览器里打开——浏览器有 30 秒执行时间限制,命令行不受影响。
批量本地化最容易踩的坑有哪些?
结论:防盗链、超时、图片下载失败导致死循环,是三个最高频的问题,前两个加参数就能解决,第三个要加保护。
- 防盗链:目标站校验 Referer,不传就返回 403 或一张占位图。上面代码里的
CURLOPT_REFERER就是干这个的,填你站点的域名即可。 - HTTPS 证书:老服务器 CA 证书过期会直接失败,加
CURLOPT_SSL_VERIFYPEER => false绕过。 - 死循环保护:如果某条记录的图片全部下载失败,链接没被替换,它会一直匹配条件。建议加一个计数器,比如连续 3 轮查出来的
d_id完全一样就break,或者给失败记录打标记跳过。 - 先备份:跑之前
mysqldump -u user -p yourdb > backup.sql,先只处理 10 条验证替换后的前台显示正常,再放开跑全量。 - CDN 与路径:如果站内用了 CDN 或图片走独立域名,替换后的路径要跟着改成对应的绝对地址,否则前台会 404。
跑完全量后,再执行一次开头那条 SELECT COUNT(*),数字降到接近 0 就说明处理干净了。剩下的个位数记录,基本是原图已被删除的,直接手动换成站内占位图即可。
原文链接:https://www.gj0.com/thread-894.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。