把正文里的外链图片全部搬到自己服务器

米阳 2023-2-24 4 2/24

翻旧文章时发现好几张图挂了——图床倒闭、对方开了防盗链、原站点改了路径。图片是文章的一部分,图没了文章就废了一半。于是决定把所有外链图片搬到自己服务器。

先摸底

统计一下有多少外链图:

SELECT COUNT(*) FROM wp_posts
WHERE post_content LIKE '%<img%src="http%' AND post_status='publish';

结果 60 多篇里有外链图,涉及 100 多个地址。

下载策略

几个坑要注意:

  1. 防盗链:有些站点检查 Referer,请求时要带一个正常的 Referer,或者干脆不带
  2. 超时:不能一个卡住就停,每个请求设 10 秒超时
  3. 重名:不同站点可能有同名文件,用 URL 的 hash 做文件名
  4. 格式:webp 兼容性现在没问题,但老主题可能不认,统一转 jpg/png 更稳

脚本核心逻辑:

import hashlib, os, requests

def localize(url, outdir="wp-content/uploads/imported"):
    h = hashlib.md5(url.encode()).hexdigest()[:12]
    ext = os.path.splitext(url.split("?")[0])[1] or ".jpg"
    name = f"{h}{ext}"
    path = os.path.join(outdir, name)
    if os.path.exists(path):
        return "/" + path
    r = requests.get(url, timeout=10, headers={"User-Agent": "Mozilla/5.0"})
    r.raise_for_status()
    with open(path, "wb") as f:
        f.write(r.content)
    return "/" + path

替换正文

import re
for post in posts:
    new = re.sub(r'(<img[^>]+src=")(https?://[^"]+)',
                 lambda m: m.group(1) + localize(m.group(2)), post["content"])
    if new != post["content"]:
        update_post(post["id"], new)

改之前一定要备份数据库。我第一次跑的时候正则写得太宽,把 <a href> 的链接也替换了,结果文内链接全指向本地。

关于 SEO

搬图片的时候顺手补 alt 属性。搜索引擎识别图片靠 alt,纯装饰性图片用 alt=""。这个改动对收录有实际帮助,比堆关键词有用。

现在的状态

100 多张图全部落到 wp-content/uploads/imported/,每天随站点一起备份。加载速度也快了——原来要等第三方图床响应,现在跟页面同域,还能走浏览器缓存。

代价是流量和存储。图片总量 300 多 M,对一台小服务器来说还好,但以后如果文章量上来,得考虑对象存储。

- THE END -

米阳

2月24日20:55

最后修改:2023年2月24日
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论