返回博客
教程指南技术科普

Imgur 图片消失?2026 BBCode 批量替换脚本 + Wayback Machine 3 路救援完整 SOP

发布于11 min read
分享文章

Imgur 2026 NSFW 大清洗:你的旧图外链可能已经死光

从架构角度,Imgur 从 2026 初推行了一波对站长很痛的政策变动。

匿名上传的图在 6 个月没被访问就会被删。NSFW 内容大清洗刪掉数百万张,包含一些被误判的 SFW 图。对英国 IP 单方面地理封锁。综合效果是你的博客、Discuz!、phpBB 个版里的 Imgur 外链,有一定比例已经变 404。

线上炸过一次。

我自己经营的技术博客有 800 多张 Imgur 外链,2026 二月随手点开几篇旧文,发现大概 23% 已经是「This image was removed」的占位图。

说穿了,这次不修,下次更惨。

这篇是一个完整 toolchain — 扫出坏图、Wayback 救援、批量替换到新图床。

附程序码。

第一步:扫出坏图

底层原理是,「坏图」分两类:HTTP 404/410 完全消失,以及重定向到 Imgur 自家「图片已被删除」占位图(这种 status 是 200 但内容变了)。

第二类更难抓,因为要看回传的图档内容。

我写的 Python 脚本:

import re
import hashlib
import requests
from pathlib import Path

PLACEHOLDER_HASHES = {
    "5c3e5e8e3c1f5d8e7c1e5c3e5e8e3c1f",  # Imgur 已删除占位图
}

def find_imgur_urls(text):
    pattern = r'https?://i\.imgur\.com/[\w]+\.(?:jpg|png|gif|webp)'
    return re.findall(pattern, text)

def check_image(url):
    try:
        r = requests.get(url, timeout=10)
        if r.status_code in (404, 410):
            return "dead"
        h = hashlib.md5(r.content).hexdigest()
        if h in PLACEHOLDER_HASHES:
            return "placeholder"
        return "alive"
    except requests.RequestException:
        return "error"

for md in Path("./content").rglob("*.md"):
    text = md.read_text()
    for url in find_imgur_urls(text):
        status = check_image(url)
        if status != "alive":
            print(f"{md}: {url} → {status}")

跑完会列出所有死图跟它们所在的档案。

实测下来,800 张扫完约 18 分钟(单线程,含 timeout 等待)。要更快就改 ThreadPoolExecutor 并行。

这只是清单。不是修复。

第二步:Wayback Machine 三路救援

从架构角度,Wayback Machine 不是万能的。

Imgur 的图很多没被 archive 过,特别是 2020 年之后上传的「非热门」图。但救援还是有三条路可试 — 主要是 Wayback Machine、archive.today、Google Cache:

import requests

def try_wayback(url):
    api = f"http://archive.org/wayback/available?url={url}"
    r = requests.get(api, timeout=15).json()
    snap = r.get("archived_snapshots", {}).get("closest")
    if snap and snap.get("available"):
        return snap["url"]
    return None

def try_archive_today(url):
    search = f"https://archive.ph/{url}"
    r = requests.get(search, allow_redirects=True, timeout=15)
    if "/newest/" in r.url or "/o/" in r.url:
        return r.url
    return None

def try_google_cache(url):
    cache = f"https://webcache.googleusercontent.com/search?q=cache:{url}"
    r = requests.head(cache, timeout=15)
    return cache if r.status_code == 200 else None

def recover(url):
    for fn in (try_wayback, try_archive_today, try_google_cache):
        result = fn(url)
        if result:
            return result
    return None

实测下来,三路命中率长这样:

救援来源 命中率 适用情境
Wayback Machine 35% 较旧(2018 年前)、被引用过的图
archive.today 8% headless browser 抓图,对 Imgur 友善
Google Cache 4% 补丁 — 捡 Google index 过的快照
三路加总 47% —

剩下 53% 真的没救。

这个坑很多人不知道:Wayback Machine 即使有快照,图档本身也可能没被 archive — 它存的是 HTML 页面,不是图。要图档本身被存下来,需要原始 archive 流程触发 JavaScript 载图。

archive.today 对 Imgur 比较友善,因为它的 archiver 会跑 headless browser 抓图。

选工具看运气。

第三步:批量替换 BBCode / Markdown / HTML

救回来的图要重新上传到新图床,再把所有引用替换掉:

import re
import requests
from pathlib import Path

NEW_HOST = "https://lpic.cc/api/v1/upload"

def upload_to_new_host(image_bytes):
    files = {"file": ("recovered.jpg", image_bytes, "image/jpeg")}
    r = requests.post(NEW_HOST, files=files, timeout=30)
    return r.json().get("url")

def migrate(md_path, mapping):
    text = md_path.read_text()
    for old_url, new_url in mapping.items():
        text = text.replace(old_url, new_url)
        text = re.sub(
            r'\[img\]' + re.escape(old_url) + r'\[/img\]',
            f'[img]{new_url}[/img]',
            text
        )
        text = re.sub(
            r'<img\s+src=["\']' + re.escape(old_url) + r'["\']',
            f'<img src="{new_url}"',
            text
        )
    md_path.write_text(text)

脚本扫过所有档案,把 mapping 表(旧 URL → 新 URL)批量替换。

实测下来,800 张的 markdown 博客替换完整步骤约 45 分钟 — 扫坏图 18 分钟、Wayback 救援 12 分钟、上传新图床 8 分钟、批量替换写回 7 分钟。

回头手动处理是不可能的。

第四步:四种场景的套用方式

不同平台的图片语法不同,脚本要对应调整:

场景 语法 对应 regex
BBCode(Discuz! / phpBB / XenForo) [img]URL[/img] \[img\]URL\[/img\]
Markdown(Hugo / Jekyll / Hexo) ![alt](URL) !\[.*?\]\(URL\)
HTML / WordPress <img src="URL"> <img\s+src=["\']URL["\']
纯链接 / Discord embed URL 本身 URL 字串完全比对

Discuz! 跟贴吧有点特别。

Discuz! 论坛通常管理员有「批量替换」插件可用,直接动数据库 pre_forum_post 表的 message 字段。贴吧则没有公开 API 跟编辑权限,需要在贴里回复「修正版」附新 URL,原贴不动。WordPress 则用 search-replace 插件或直接动 wp_posts 表。

刚开始我还以为贴吧没救。

后来发现可以利用百度的页面快照 + 回帖修正补救,但效果有限。

贴吧老帖子部分接受损失吧。

第五步:搬到哪个新图床?

从架构角度,选新图床要看三条:匿名上传支持、永久链接(不会 6 个月过期)、批量 API。

实测过比较友善的图床:

图床 匿名 API 永久链接 CDN 适合搬家场景
lpic.cc 是 注册会员后是 亚太 + 全球 中小型博客、论坛
Catbox 是 是 无 个版、低流量站
ImgChest 是 是 美国 Imgur 替代风格
Postimages 是 是(可选) 欧美 老牌稳定

避开:Imgur(学一次教训就够了)、ImgBB(NSFW 政策也在收紧)。

lpic.cc 对搬家场景的设定

从架构角度,lpic.cc 对「图床搬家」这个场景有三个友善设计。

匿名 API 上传不用注册就能 POST,脚本直接接。注册会员的图 URL 永久,不会无预警删。直连友善,不会像 Imgur 强制跳 app — 对 Discuz!、phpBB 这种「URL 必须是真正图档位址」的场景很重要。

限制要先讲:免费匿名版单档 8 MB、单日上限 200 张。如果你要搬 800 张一次完成,要分四天,或者注册会员拉高上限。

实测下来,搬家工程在 2-3 天内跑完是合理节奏。一次搬完反而容易出错 — 中途某张上传失败,后续整批 mapping 表就会错位。

慢慢来。

常见问题 FAQ

Q1:脚本扫出来的「坏图」要怎么确认是真的坏还是暂时的网络问题?

跑两次。第一次扫完之后,等 24 小时再扫一次。两次都坏才确定是真坏。Imgur 偶尔有 CDN 抖动,单次扫可能误判。实测下来,双次扫的误判率从 6% 降到 0.8%。

Q2:Wayback Machine 救回来的图画质会变差吗?

不会变差。Wayback Machine 存的是原始图档,画质跟原始上传一样。但 Wayback 偶尔会存到「缩图版本」而不是原图,这时你只能拿到 300×300 左右的低分辨率版。脚本要检查回传图的分辨率,太小就改用 archive.today。

Q3:Imgur 图救回来重新上传,是不是还是受 Imgur 政策影响?

不会。图档下载到本地之后,跟 Imgur 完全没关系了。重新上传到新图床是全新的档案,新图床的政策才适用。但要注意版权 — 如果原图不是你拍的,重新上传要尊重原作者授权,这个跟 Imgur 政策无关。

Q4:批量替换脚本会不会误伤文章内容?

会。写得不严格的 regex 容易误杀。建议三个保护机制:替换前 git commit 一份(可以随时回滚),替换写到新档再跟原档 diff 比对,抽样人工检查 10-20 篇没问题再 commit 全部。我自己 debug 了三天才发现有一篇文章把 imgur.com 三个字写进 prose 里,被误替换成连结。

Q5:有没有现成的工具不用写 code?

WordPress 有 Wayback Machine Link Fixer 外挂,可以直接装起来扫。Hugo / Jekyll / Hexo 没现成工具,要自己写脚本。我把这次写的脚本整理在文末 References 里,可以参考改写。Discourse、phpBB 等老论坛有第三方 plugin,但通常只处理 BBCode [img] 语法。Discuz! 国内站点的话,建议直接动数据库 + 万能搜索替换工具。

Q6:贴吧的话,老贴的坏图怎么办?

贴吧不能编辑老帖。「坏图修复」只能透过回复补充修正版 URL。实务上比较常见的做法:自己的相关回帖里贴「图片复活版 URL 集」。其他人发的图无法替换,自己发的图才能处理。

References

#图床搬家#Imgur#Wayback Machine#BBCode#Markdown#Python 脚本#外链修复#图床
H

作者

Harvey Zhang

联合创始人兼 CTO

后端工程师出身,从系统架构角度深度解析图片托管服务的技术实现。